lemmur-app-android/lib/url_launcher.dart

127 lines
3.5 KiB
Dart

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<void> linkLauncher({
required BuildContext context,
required String url,
required String instanceHost,
}) async {
void push(Widget Function() builder) {
goTo(context, (c) => builder());
}
final instances = context.read<AccountsStore>().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<void>(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<bool> 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;
}
}