mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-06 08:30:29 +00:00
fix: deep link hidden handling on MacOS (#1262)
This commit is contained in:
4 files changed
+82
-60
No files matched your search
@@ -62,6 +62,11 @@ final allTrackerSubscribeUrlCdns = {
|
||||
class AppController extends GetxController with WindowListener, TrayListener {
|
||||
static StartConfig? _defaultStartConfig;
|
||||
|
||||
/// Command line --hidden flag passed from main.dart
|
||||
final bool hiddenFromArgs;
|
||||
|
||||
AppController({this.hiddenFromArgs = false});
|
||||
|
||||
final autoStartup = false.obs;
|
||||
final startConfig = StartConfig().obs;
|
||||
final runningPort = 0.obs;
|
||||
@@ -156,24 +161,44 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
|
||||
Future<void> _initDeepLinks() async {
|
||||
if (Util.isWeb()) {
|
||||
// For web, just show window
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle deep link
|
||||
() async {
|
||||
_appLinks = AppLinks();
|
||||
_appLinks = AppLinks();
|
||||
|
||||
// Handle link when app is in warm state (front or background)
|
||||
_linkSubscription = _appLinks.uriLinkStream.listen((uri) async {
|
||||
await _handleDeepLink(uri);
|
||||
});
|
||||
// Handle link when app is in warm state (front or background)
|
||||
_linkSubscription = _appLinks.uriLinkStream.listen((uri) async {
|
||||
await _handleDeepLink(uri);
|
||||
});
|
||||
|
||||
// Check initial link if app was in cold state (terminated)
|
||||
final uri = await _appLinks.getInitialLink();
|
||||
if (uri != null) {
|
||||
await _handleDeepLink(uri);
|
||||
}
|
||||
}();
|
||||
// Get initial link for cold start - this works after runApp()
|
||||
Uri? initialLink;
|
||||
try {
|
||||
initialLink = await _appLinks.getInitialLink();
|
||||
} catch (e) {
|
||||
// ignore errors
|
||||
}
|
||||
|
||||
// Determine if window should be hidden
|
||||
// Priority 1: gopeed: URL scheme hidden parameter
|
||||
// Priority 2: Command line --hidden flag
|
||||
bool shouldHide = hiddenFromArgs;
|
||||
if (initialLink?.scheme == "gopeed") {
|
||||
shouldHide = initialLink!.queryParameters["hidden"] == "true";
|
||||
}
|
||||
|
||||
// Show window if not hidden (desktop only)
|
||||
if (Util.isDesktop() && !shouldHide) {
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
}
|
||||
|
||||
// Handle initial link for deep link navigation
|
||||
if (initialLink != null) {
|
||||
_handleDeepLink(initialLink);
|
||||
}
|
||||
|
||||
// Handle shared media, e.g. shared link from browser
|
||||
if (Util.isMobile()) {
|
||||
@@ -638,7 +663,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
launchAtStartup.setup(
|
||||
appName: packageInfo.appName,
|
||||
appPath: Platform.resolvedExecutable,
|
||||
args: ['--${Args.flagHidden}']);
|
||||
args: ['--${StartupArgs.flagHidden}']);
|
||||
autoStartup.value = await launchAtStartup.isEnabled();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,11 @@ class AppView extends GetView<AppController> {
|
||||
// Set the title bar to use the actual brightness of the UI
|
||||
windowManager.setBrightness(brightness);
|
||||
}
|
||||
return child!;
|
||||
// Fix for GetX Overlay issue with Flutter 3.38.1+
|
||||
// Reference: https://github.com/jonataslaw/getx/issues/3425
|
||||
return Overlay(
|
||||
initialEntries: [OverlayEntry(builder: (_) => child!)],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
_installBtnController.start();
|
||||
try {
|
||||
await installExtension(InstallExtension(url: _installUrlController.text));
|
||||
Get.snackbar('tip'.tr, 'extensionInstallSuccess'.tr);
|
||||
showMessage('tip'.tr, 'extensionInstallSuccess'.tr);
|
||||
await controller.load();
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
@@ -109,7 +109,7 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
try {
|
||||
await installExtension(
|
||||
InstallExtension(devMode: true, url: dir));
|
||||
Get.snackbar(
|
||||
showMessage(
|
||||
'tip'.tr, 'extensionInstallSuccess'.tr);
|
||||
await controller.load();
|
||||
} catch (e) {
|
||||
@@ -290,7 +290,7 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
return showDialog<void>(
|
||||
context: Get.context!,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => AlertDialog(
|
||||
builder: (dialogContext) => AlertDialog(
|
||||
content: Builder(builder: (context) {
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
@@ -351,7 +351,7 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
backgroundColor: MaterialStateProperty.all(
|
||||
Get.theme.colorScheme.background)),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
child: Text('cancel'.tr),
|
||||
),
|
||||
@@ -372,7 +372,9 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
UpdateExtensionSettings(
|
||||
settings: formKey.currentState!.value));
|
||||
await controller.load();
|
||||
Get.back();
|
||||
if (dialogContext.mounted) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
@@ -453,12 +455,12 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => AlertDialog(
|
||||
builder: (dialogContext) => AlertDialog(
|
||||
title: Text('extensionDelete'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('cancel'.tr),
|
||||
onPressed: () => Get.back(),
|
||||
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
@@ -469,7 +471,9 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
try {
|
||||
await deleteExtension(extension.identity);
|
||||
await controller.load();
|
||||
Get.back();
|
||||
if (dialogContext.mounted) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
}
|
||||
@@ -484,14 +488,14 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
builder: (context) => AlertDialog(
|
||||
builder: (dialogContext) => AlertDialog(
|
||||
content: Text('newVersionTitle'.trParams({
|
||||
'version': 'v${controller.updateFlags[extension.identity]!}'
|
||||
})),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
child: Text('newVersionLater'.tr),
|
||||
),
|
||||
@@ -503,7 +507,9 @@ class ExtensionView extends GetView<ExtensionController> {
|
||||
await updateExtension(extension.identity);
|
||||
await controller.load();
|
||||
controller.updateFlags.remove(extension.identity);
|
||||
Get.back();
|
||||
if (dialogContext.mounted) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
}
|
||||
showMessage('tip'.tr, 'extensionUpdateSuccess'.tr);
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
|
||||
+22
-35
@@ -22,37 +22,32 @@ import 'util/scheme_register/scheme_register.dart';
|
||||
import 'util/updater.dart';
|
||||
import 'util/util.dart';
|
||||
|
||||
class Args {
|
||||
class StartupArgs {
|
||||
static const flagHidden = "hidden";
|
||||
|
||||
bool hidden = false;
|
||||
/// Command line --hidden flag (for auto-start)
|
||||
bool hiddenFromArgs = false;
|
||||
|
||||
Args();
|
||||
StartupArgs._();
|
||||
|
||||
Args.parse(List<String> args) {
|
||||
final parser = ArgParser();
|
||||
parser.addFlag(flagHidden);
|
||||
final results = parser.parse(args);
|
||||
hidden = results.flag(flagHidden);
|
||||
/// Parse from command line arguments only
|
||||
static StartupArgs parse(List<String> arguments) {
|
||||
final args = StartupArgs._();
|
||||
try {
|
||||
final parser = ArgParser()..addFlag(flagHidden);
|
||||
final results = parser.parse(arguments);
|
||||
args.hiddenFromArgs = results.flag(flagHidden);
|
||||
} catch (e) {
|
||||
// ignore parse errors
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
void main(List<String> arguments) async {
|
||||
Args args;
|
||||
// Parse url scheme arguments, e.g. gopeed:?hidden=true
|
||||
// TODO: macos open url handle
|
||||
// TODO: macos updater test
|
||||
if (arguments.firstOrNull?.startsWith("gopeed:") == true) {
|
||||
try {
|
||||
final uri = Uri.parse(arguments.first);
|
||||
args = Args()..hidden = uri.queryParameters["hidden"] == "true";
|
||||
} catch (e) {
|
||||
// ignore
|
||||
args = Args.parse([]);
|
||||
}
|
||||
} else {
|
||||
args = Args.parse(arguments);
|
||||
}
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
final args = StartupArgs.parse(arguments);
|
||||
|
||||
await init(args);
|
||||
onStart();
|
||||
@@ -60,8 +55,8 @@ void main(List<String> arguments) async {
|
||||
runApp(const AppView());
|
||||
}
|
||||
|
||||
Future<void> init(Args args) async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
Future<void> init(StartupArgs args) async {
|
||||
// Note: WidgetsFlutterBinding.ensureInitialized() is already called in main()
|
||||
if (Util.isMobile()) {
|
||||
FlutterForegroundTask.initCommunicationPort();
|
||||
}
|
||||
@@ -81,16 +76,7 @@ Future<void> init(Args args) async {
|
||||
skipTaskbar: runAsMenubarApp,
|
||||
);
|
||||
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||
if (!args.hidden) {
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
}
|
||||
await windowManager.setPreventClose(true);
|
||||
// windows_manager has a bug where when window to be maximized, it will be unmaximized immediately, so can't implement this feature currently.
|
||||
// https://github.com/leanflutter/window_manager/issues/412
|
||||
// if (windowState.isMaximized) {
|
||||
// await windowManager.maximize();
|
||||
// }
|
||||
});
|
||||
|
||||
// Register Cmd+W hotkey on macOS to close window
|
||||
@@ -118,7 +104,8 @@ Future<void> init(Args args) async {
|
||||
logger.e("init package info fail", e);
|
||||
}
|
||||
|
||||
final controller = Get.put(AppController());
|
||||
final controller =
|
||||
Get.put(AppController(hiddenFromArgs: args.hiddenFromArgs));
|
||||
try {
|
||||
await controller.loadStartConfig();
|
||||
final startCfg = controller.startConfig.value;
|
||||
|
||||
Reference in new issue
Block a user