import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart' as ul; import 'l10n/l10n.dart'; import 'pages/community/community.dart'; import 'pages/instance/instance.dart'; import 'pages/media_view.dart'; import 'pages/user.dart'; import 'stores/accounts_store.dart'; import 'util/goto.dart'; /// Decides where does a link link to. Either somewhere in-app: /// opens the correct page, or outside of the app: opens in a browser Future linkLauncher({ required BuildContext context, required String url, required String instanceHost, }) async { void push(Widget Function() builder) { goTo(context, (c) => builder()); } final instances = context.read().instances; final chonks = url.split('/'); if (chonks.length == 1) { await launchLink(link: url, context: context); return; } // CHECK IF LINK TO USER if (url.startsWith('/u/')) { return push(() => UserPage.fromName(instanceHost: instanceHost, username: chonks[2])); } // CHECK IF LINK TO COMMUNITY if (url.startsWith('/c/')) { await Navigator.of(context) .push(CommunityPage.fromNameRoute(instanceHost, chonks[2])); return; } // CHECK IF REDIRECTS TO A PAGE ON ONE OF ADDED INSTANCES final instanceRegex = RegExp(r'^(?:https?:\/\/)?([\w\.-]+)(.*)$'); final match = instanceRegex.firstMatch(url); final matchedInstance = match?.group(1); final rest = match?.group(2); if (matchedInstance != null && instances.any((e) => e == match?.group(1))) { if (rest == null || rest.isEmpty || rest == '/') { return Navigator.of(context).push(InstancePage.route(instanceHost)); } final split = rest.split('/'); switch (split[1]) { case 'c': return goToCommunity.byName(context, matchedInstance, split[2]); case 'u': return goToUser.byName(context, matchedInstance, split[2]); case 'post': if (split.length == 3) { return goToPost(context, matchedInstance, int.parse(split[2])); } else if (split.length == 5) { // TODO: post with focus on comment thread return goToPost(context, matchedInstance, int.parse(split[2])); } break; case 'pictrs': return push(() => MediaViewPage(url)); case 'communities': // TODO: put here push to communities page return; case 'modlog': // TODO: put here push to modlog return; case 'inbox': // TODO: put here push to inbox return; case 'search': // TODO: *maybe* put here push to search. we'll see // how much web version differs form the app return; case 'create_post': case 'create_community': case 'sponsors': case 'instances': case 'docs': break; default: break; } } // FALLBACK TO REGULAR LINK STUFF await launchLink(link: url, context: context); } final _logger = Logger('launchLink'); /// Returns whether launching was successful. Future launchLink({ required String link, required BuildContext context, }) async { final uri = Uri.tryParse(link); if (uri != null && await ul.canLaunchUrl(uri)) { await ul.launchUrl(uri); return true; } else { _logger.warning('Failed to launch a link: $link'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(L10n.of(context).cannot_open_in_browser)), ); return false; } }