From 415460df752ca94a2c0476ab130323019db8d429 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Fri, 15 Dec 2023 23:37:04 -0500 Subject: [PATCH 01/11] Custom link support (#918) --- android/app/src/main/AndroidManifest.xml | 10 +- lib/pages/add_app.dart | 101 ++++++++++--------- lib/pages/home.dart | 117 ++++++++++++++++------- pubspec.lock | 16 ++++ pubspec.yaml | 1 + 5 files changed, 165 insertions(+), 80 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d48e3f5..b265cfe 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ + + + + + + + diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index 0ff0cda..f514a32 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -21,10 +23,10 @@ class AddAppPage extends StatefulWidget { const AddAppPage({super.key}); @override - State createState() => _AddAppPageState(); + State createState() => AddAppPageState(); } -class _AddAppPageState extends State { +class AddAppPageState extends State { bool gettingAppInfo = false; bool searching = false; @@ -36,9 +38,57 @@ class _AddAppPageState extends State { bool additionalSettingsValid = true; bool inferAppIdIfOptional = true; List pickedCategories = []; - int searchnum = 0; SourceProvider sourceProvider = SourceProvider(); + linkFn(String input) { + try { + if (input.isEmpty) { + throw UnsupportedURLError(); + } + sourceProvider.getSource(input); + changeUserInput(input, true, false); + } catch (e) { + showError(e, context); + } + } + + changeUserInput(String input, bool valid, bool isBuilding) { + userInput = input; + if (!isBuilding) { + setState(() { + var prevHost = pickedSource?.host; + try { + var naturalSource = + valid ? sourceProvider.getSource(userInput) : null; + if (naturalSource != null && + naturalSource.runtimeType.toString() != + HTML().runtimeType.toString()) { + // If input has changed to match a regular source, reset the override + pickedSourceOverride = null; + } + } catch (e) { + // ignore + } + var source = valid + ? sourceProvider.getSource(userInput, + overrideSource: pickedSourceOverride) + : null; + if (pickedSource.runtimeType != source.runtimeType || + (prevHost != null && prevHost != source?.host)) { + pickedSource = source; + additionalSettings = source != null + ? getDefaultValuesFromFormItems( + source.combinedAppSpecificSettingFormItems) + : {}; + additionalSettingsValid = source != null + ? !sourceProvider.ifRequiredAppSpecificSettingsExist(source) + : true; + inferAppIdIfOptional = true; + } + }); + } + } + @override Widget build(BuildContext context) { AppsProvider appsProvider = context.read(); @@ -48,47 +98,6 @@ class _AddAppPageState extends State { bool doingSomething = gettingAppInfo || searching; - changeUserInput(String input, bool valid, bool isBuilding, - {bool isSearch = false}) { - userInput = input; - if (!isBuilding) { - setState(() { - if (isSearch) { - searchnum++; - } - var prevHost = pickedSource?.host; - try { - var naturalSource = - valid ? sourceProvider.getSource(userInput) : null; - if (naturalSource != null && - naturalSource.runtimeType.toString() != - HTML().runtimeType.toString()) { - // If input has changed to match a regular source, reset the override - pickedSourceOverride = null; - } - } catch (e) { - // ignore - } - var source = valid - ? sourceProvider.getSource(userInput, - overrideSource: pickedSourceOverride) - : null; - if (pickedSource.runtimeType != source.runtimeType || - (prevHost != null && prevHost != source?.host)) { - pickedSource = source; - additionalSettings = source != null - ? getDefaultValuesFromFormItems( - source.combinedAppSpecificSettingFormItems) - : {}; - additionalSettingsValid = source != null - ? !sourceProvider.ifRequiredAppSpecificSettingsExist(source) - : true; - inferAppIdIfOptional = true; - } - }); - } - } - Future getTrackOnlyConfirmationIfNeeded(bool userPickedTrackOnly, {bool ignoreHideSetting = false}) async { var useTrackOnly = userPickedTrackOnly || pickedSource!.enforceTrackOnly; @@ -205,7 +214,7 @@ class _AddAppPageState extends State { children: [ Expanded( child: GeneratedForm( - key: Key(searchnum.toString()), + key: Key(Random().nextInt(10000).toString()), items: [ [ GeneratedFormTextField('appSourceURL', @@ -325,7 +334,7 @@ class _AddAppPageState extends State { ); }); if (selectedUrls != null && selectedUrls.isNotEmpty) { - changeUserInput(selectedUrls[0], true, false, isSearch: true); + changeUserInput(selectedUrls[0], true, false); } } } catch (e) { diff --git a/lib/pages/home.dart b/lib/pages/home.dart index c14e83f..c2dd91d 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -1,4 +1,7 @@ +import 'dart:async'; + import 'package:animations/animations.dart'; +import 'package:app_links/app_links.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -30,53 +33,95 @@ class _HomePageState extends State { bool isReversing = false; int prevAppCount = -1; bool prevIsLoading = true; + late AppLinks _appLinks; + StreamSubscription? _linkSubscription; List pages = [ NavigationPageItem(tr('appsString'), Icons.apps, AppsPage(key: GlobalKey())), - NavigationPageItem(tr('addApp'), Icons.add, const AddAppPage()), + NavigationPageItem( + tr('addApp'), Icons.add, AddAppPage(key: GlobalKey())), NavigationPageItem( tr('importExport'), Icons.import_export, const ImportExportPage()), NavigationPageItem(tr('settings'), Icons.settings, const SettingsPage()) ]; + @override + void initState() { + super.initState(); + initDeepLinks(); + } + + Future initDeepLinks() async { + _appLinks = AppLinks(); + + goToAddApp(Uri uri) async { + switchToPage(1); + while ( + (pages[1].widget.key as GlobalKey?)?.currentState == + null) { + await Future.delayed(const Duration(microseconds: 1)); + } + (pages[1].widget.key as GlobalKey?) + ?.currentState + ?.linkFn(uri.path.length > 1 ? uri.path.substring(1) : ""); + } + + // Check initial link if app was in cold state (terminated) + final appLink = await _appLinks.getInitialAppLink(); + if (appLink != null) { + await goToAddApp(appLink); + } + + // Handle link when app is in warm state (front or background) + _linkSubscription = _appLinks.uriLinkStream.listen((uri) async { + await goToAddApp(uri); + }); + } + + setIsReversing(int targetIndex) { + bool reversing = selectedIndexHistory.isNotEmpty && + selectedIndexHistory.last > targetIndex; + setState(() { + isReversing = reversing; + }); + } + + switchToPage(int index) async { + setIsReversing(index); + if (index == 0) { + while ((pages[0].widget.key as GlobalKey).currentState != + null) { + // Avoid duplicate GlobalKey error + await Future.delayed(const Duration(microseconds: 1)); + } + setState(() { + selectedIndexHistory.clear(); + }); + } else if (selectedIndexHistory.isEmpty || + (selectedIndexHistory.isNotEmpty && + selectedIndexHistory.last != index)) { + // while (index == 1 && + // (pages[0].widget.key as GlobalKey).currentState != + // null) { + // // Avoid duplicate GlobalKey error + // await Future.delayed(const Duration(microseconds: 1)); + // } + setState(() { + int existingInd = selectedIndexHistory.indexOf(index); + if (existingInd >= 0) { + selectedIndexHistory.removeAt(existingInd); + } + selectedIndexHistory.add(index); + }); + } + } + @override Widget build(BuildContext context) { AppsProvider appsProvider = context.watch(); SettingsProvider settingsProvider = context.watch(); - setIsReversing(int targetIndex) { - bool reversing = selectedIndexHistory.isNotEmpty && - selectedIndexHistory.last > targetIndex; - setState(() { - isReversing = reversing; - }); - } - - switchToPage(int index) async { - setIsReversing(index); - if (index == 0) { - while ((pages[0].widget.key as GlobalKey).currentState != - null) { - // Avoid duplicate GlobalKey error - await Future.delayed(const Duration(microseconds: 1)); - } - setState(() { - selectedIndexHistory.clear(); - }); - } else if (selectedIndexHistory.isEmpty || - (selectedIndexHistory.isNotEmpty && - selectedIndexHistory.last != index)) { - setState(() { - int existingInd = selectedIndexHistory.indexOf(index); - if (existingInd >= 0) { - selectedIndexHistory.removeAt(existingInd); - } - selectedIndexHistory.add(index); - }); - } - } - if (!prevIsLoading && prevAppCount >= 0 && appsProvider.apps.length > prevAppCount && @@ -143,4 +188,10 @@ class _HomePageState extends State { ?.clearSelected(); }); } + + @override + void dispose() { + super.dispose(); + _linkSubscription?.cancel(); + } } diff --git a/pubspec.lock b/pubspec.lock index 88905ae..cf74778 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,6 +42,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.10" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: "4e392b5eba997df356ca6021f28431ce1cfeb16758699553a94b13add874a3bb" + url: "https://pub.dev" + source: hosted + version: "3.5.0" archive: dependency: transitive description: @@ -350,6 +358,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.4" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" hsluv: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 0b9b272..8a9ffeb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -67,6 +67,7 @@ dependencies: connectivity_plus: ^5.0.0 shared_storage: ^0.8.0 crypto: ^3.0.3 + app_links: ^3.5.0 dev_dependencies: flutter_test: From 7413f693d79a08d9e89abe4cc9ea7ab36e6af90f Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 00:31:32 -0500 Subject: [PATCH 02/11] JSON import link support (#368) --- android/app/src/main/AndroidManifest.xml | 33 ++++++++++++------------ lib/pages/home.dart | 31 +++++++++++++++++++--- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b265cfe..5e60b1c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -28,16 +28,15 @@ + android:exported="false" /> - + - + @@ -47,10 +46,10 @@ + android:exported="false" /> + android:exported="false" /> - + android:name="androidx.core.content.FileProvider" + android:authorities="dev.imranr.obtainium" + android:grantUriPermissions="true"> + - - - - + + + + + android:maxSdkVersion="29" /> \ No newline at end of file diff --git a/lib/pages/home.dart b/lib/pages/home.dart index c2dd91d..c2b66bf 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -5,6 +5,7 @@ import 'package:app_links/app_links.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/pages/add_app.dart'; import 'package:obtainium/pages/apps.dart'; import 'package:obtainium/pages/import_export.dart'; @@ -55,7 +56,7 @@ class _HomePageState extends State { Future initDeepLinks() async { _appLinks = AppLinks(); - goToAddApp(Uri uri) async { + goToAddApp(String data) async { switchToPage(1); while ( (pages[1].widget.key as GlobalKey?)?.currentState == @@ -64,18 +65,40 @@ class _HomePageState extends State { } (pages[1].widget.key as GlobalKey?) ?.currentState - ?.linkFn(uri.path.length > 1 ? uri.path.substring(1) : ""); + ?.linkFn(data); + } + + interpretLink(Uri uri) async { + var action = uri.host; + var data = uri.path.length > 1 ? uri.path.substring(1) : ""; + try { + if (action == 'add') { + await goToAddApp(data); + } else if (action == 'app') { + await context + .read() + .importApps('[${Uri.decodeComponent(data)}]'); + } else if (action == 'apps') { + await context + .read() + .importApps(Uri.decodeComponent(data)); + } else { + throw ObtainiumError(tr('unknown')); + } + } catch (e) { + showError(e, context); + } } // Check initial link if app was in cold state (terminated) final appLink = await _appLinks.getInitialAppLink(); if (appLink != null) { - await goToAddApp(appLink); + await interpretLink(appLink); } // Handle link when app is in warm state (front or background) _linkSubscription = _appLinks.uriLinkStream.listen((uri) async { - await goToAddApp(uri); + await interpretLink(uri); }); } From 2dec52e221aba0e7cc93df5d93772445c97c7f39 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 01:24:43 -0500 Subject: [PATCH 03/11] Bugfix --- lib/pages/add_app.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index f514a32..fe141f8 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -38,6 +36,7 @@ class AddAppPageState extends State { bool additionalSettingsValid = true; bool inferAppIdIfOptional = true; List pickedCategories = []; + int urlInputKey = 0; SourceProvider sourceProvider = SourceProvider(); linkFn(String input) { @@ -46,16 +45,20 @@ class AddAppPageState extends State { throw UnsupportedURLError(); } sourceProvider.getSource(input); - changeUserInput(input, true, false); + changeUserInput(input, true, false, updateUrlInput: true); } catch (e) { showError(e, context); } } - changeUserInput(String input, bool valid, bool isBuilding) { + changeUserInput(String input, bool valid, bool isBuilding, + {bool updateUrlInput = false}) { userInput = input; if (!isBuilding) { setState(() { + if (updateUrlInput) { + urlInputKey++; + } var prevHost = pickedSource?.host; try { var naturalSource = @@ -214,7 +217,7 @@ class AddAppPageState extends State { children: [ Expanded( child: GeneratedForm( - key: Key(Random().nextInt(10000).toString()), + key: Key(urlInputKey.toString()), items: [ [ GeneratedFormTextField('appSourceURL', @@ -334,7 +337,7 @@ class AddAppPageState extends State { ); }); if (selectedUrls != null && selectedUrls.isNotEmpty) { - changeUserInput(selectedUrls[0], true, false); + changeUserInput(selectedUrls[0], true, false, updateUrlInput: true); } } } catch (e) { From f9bab18076bf3c6a0772577251a91b024faec876 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 01:44:02 -0500 Subject: [PATCH 04/11] Fix unauthorized error (#1153) --- lib/providers/settings_provider.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index d72fd8d..cf3c7c6 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -213,7 +213,8 @@ class SettingsProvider with ChangeNotifier { } String? getSettingString(String settingId) { - return prefs?.getString(settingId); + String? str = prefs?.getString(settingId); + return str?.isNotEmpty == true ? str : null; } void setSettingString(String settingId, String value) { From dc92ccda0a46f78315fe2936728a7062266aa59c Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 02:01:43 -0500 Subject: [PATCH 05/11] Use public GitLab search API (#1147) --- lib/app_sources/gitlab.dart | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index 265b299..ae191f1 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -48,12 +48,6 @@ class GitLab extends AppSource { label: tr('fallbackToOlderReleases'), defaultValue: true) ] ]; - searchQuerySettingFormItems = [ - GeneratedFormTextField('PAT', - label: tr('gitlabPATLabel').split('(')[0], - password: true, - required: false) - ]; } @override @@ -86,18 +80,8 @@ class GitLab extends AppSource { @override Future>> search(String query, {Map querySettings = const {}}) async { - String? PAT; - if (!hostChanged) { - PAT = await getPATIfAny({}); - if (PAT == null) { - throw CredsNeededError(name); - } - } - if ((querySettings['PAT'] as String?)?.isNotEmpty == true) { - PAT = querySettings['PAT']; - } var url = - 'https://$host/api/v4/search?${PAT?.isNotEmpty == true ? 'private_token=$PAT&' : ''}scope=projects&search=${Uri.encodeQueryComponent(query)}'; + 'https://$host/api/v4/projects?search=${Uri.encodeQueryComponent(query)}'; var res = await sourceRequest(url); if (res.statusCode != 200) { throw getObtainiumHttpError(res); From 80e4986b23cc76eb58b147e10cd1361dabb50323 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 02:55:05 -0500 Subject: [PATCH 06/11] Export settings (#1157) --- assets/translations/bs.json | 1 + assets/translations/cs.json | 1 + assets/translations/de.json | 1 + assets/translations/en.json | 1 + assets/translations/es.json | 1 + assets/translations/fa.json | 1 + assets/translations/fr.json | 1 + assets/translations/hu.json | 1 + assets/translations/it.json | 1 + assets/translations/ja.json | 1 + assets/translations/nl.json | 1 + assets/translations/pl.json | 1 + assets/translations/pt.json | 1 + assets/translations/ru.json | 1 + assets/translations/sv.json | 1 + assets/translations/tr.json | 1 + assets/translations/vi.json | 1 + assets/translations/zh.json | 1 + lib/pages/import_export.dart | 14 ++++++++++ lib/providers/apps_provider.dart | 39 +++++++++++++++++++++++----- lib/providers/settings_provider.dart | 9 +++++++ 21 files changed, 74 insertions(+), 6 deletions(-) diff --git a/assets/translations/bs.json b/assets/translations/bs.json index eadd9b6..0cafa91 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Highlight less obvious touch targets", "pickExportDir": "Pick Export Directory", "autoExportOnChanges": "Auto-export on changes", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filter Versions by Regular Expression", "trySelectingSuggestedVersionCode": "Try selecting suggested versionCode APK", "dontSortReleasesList": "Retain release order from API", diff --git a/assets/translations/cs.json b/assets/translations/cs.json index 0af18b7..d029e18 100644 --- a/assets/translations/cs.json +++ b/assets/translations/cs.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Zvýraznit méně zjevné cíle dotyku", "pickExportDir": "Vybrat adresář pro export", "autoExportOnChanges": "Automatický export při změnách", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filtrovat verze podle regulárního výrazu", "trySelectingSuggestedVersionCode": "Zkusit vybrat navrhovaný kód verze APK", "dontSortReleasesList": "Retain release order from API", diff --git a/assets/translations/de.json b/assets/translations/de.json index 85376bc..289e192 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Weniger offensichtliche Touch-Ziele hervorheben", "pickExportDir": "Export-Verzeichnis wählen", "autoExportOnChanges": "Automatischer Export bei Änderung(en)", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Versionen nach regulären Ausdrücken filtern", "trySelectingSuggestedVersionCode": "Versuchen, den vorgeschlagenen APK-Versionscode auszuwählen", "dontSortReleasesList": "Freigaberelease von der API ordern", diff --git a/assets/translations/en.json b/assets/translations/en.json index d81785a..cb061cf 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Highlight less obvious touch targets", "pickExportDir": "Pick Export Directory", "autoExportOnChanges": "Auto-export on changes", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filter Versions by Regular Expression", "trySelectingSuggestedVersionCode": "Try selecting suggested versionCode APK", "dontSortReleasesList": "Retain release order from API", diff --git a/assets/translations/es.json b/assets/translations/es.json index fff2e8b..6acef19 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Highlight less obvious touch targets", "pickExportDir": "Pick Export Directory", "autoExportOnChanges": "Auto-export on changes", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filter Versions by Regular Expression", "trySelectingSuggestedVersionCode": "Try selecting suggested versionCode APK", "dontSortReleasesList": "Retain release order from API", diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 2631131..f9a31fe 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "اهداف لمسی کمتر واضح را برجسته کنید", "pickExportDir": "فهرست صادرات را انتخاب کنید", "autoExportOnChanges": "صادرات خودکار تغییرات", + "includeSettings": "Include settings", "filterVersionsByRegEx": "فیلتر کردن نسخه ها با RegEx", "trySelectingSuggestedVersionCode": "نسخه پیشنهادی APK نسخه کد را انتخاب کنید", "dontSortReleasesList": "حفظ سفارش انتشار از API", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 1940b2d..a7000c1 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Highlight less obvious touch targets", "pickExportDir": "Pick Export Directory", "autoExportOnChanges": "Auto-export on changes", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filter Versions by Regular Expression", "trySelectingSuggestedVersionCode": "Try selecting suggested versionCode APK", "dontSortReleasesList": "Retain release order from API", diff --git a/assets/translations/hu.json b/assets/translations/hu.json index de1402e..17cd3ff 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -255,6 +255,7 @@ "highlightTouchTargets": "Emelje ki a kevésbé nyilvánvaló érintési célokat", "pickExportDir": "Válassza az Exportálási könyvtárat", "autoExportOnChanges": "Auto-exportálás a változások után", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Verziók szűrése reguláris kifejezéssel", "trySelectingSuggestedVersionCode": "Próbálja ki a javasolt verziókódú APK-t", "dontSortReleasesList": "Az API-ból származó kiadási sorrend megőrzése", diff --git a/assets/translations/it.json b/assets/translations/it.json index 25d1788..3afdec3 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Evidenzia elementi toccabili meno ovvi", "pickExportDir": "Scegli cartella esp.", "autoExportOnChanges": "Auto-esporta dopo modifiche", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filtra versioni con espressione regolare", "trySelectingSuggestedVersionCode": "Prova a selezionare APK con versionCode suggerito", "dontSortReleasesList": "Conserva l'ordine di release da API", diff --git a/assets/translations/ja.json b/assets/translations/ja.json index b81d093..88cbcea 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "目立たないタップ可能な対象をハイライトする", "pickExportDir": "エクスポートディレクトリを選択", "autoExportOnChanges": "変更があった際に自動でエクスポートする", + "includeSettings": "Include settings", "filterVersionsByRegEx": "正規表現でバージョンをフィルタリングする", "trySelectingSuggestedVersionCode": "提案されたバージョンコードのAPKを選択する", "dontSortReleasesList": "APIからのリリース順を保持する", diff --git a/assets/translations/nl.json b/assets/translations/nl.json index aa33f61..a365bfa 100644 --- a/assets/translations/nl.json +++ b/assets/translations/nl.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Markeer minder voor de hand liggende aanraakdoelen.", "pickExportDir": "Kies de exportmap", "autoExportOnChanges": "Automatisch exporteren bij wijzigingen", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filter versies met een reguliere expressie", "trySelectingSuggestedVersionCode": "Probeer de voorgestelde versiecode APK te selecteren", "dontSortReleasesList": "Volgorde van releases behouden vanuit de API", diff --git a/assets/translations/pl.json b/assets/translations/pl.json index c70c494..7c43fee 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Wyróżnij mniej oczywiste elementy dotykowe", "pickExportDir": "Wybierz katalog eksportu", "autoExportOnChanges": "Automatyczny eksport po wprowadzeniu zmian", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filtruj wersje według wyrażenia regularnego", "trySelectingSuggestedVersionCode": "Spróbuj wybierać sugerowany kod wersji APK", "dontSortReleasesList": "Utrzymaj kolejność wydań z interfejsu API", diff --git a/assets/translations/pt.json b/assets/translations/pt.json index 878d9f5..fa89746 100644 --- a/assets/translations/pt.json +++ b/assets/translations/pt.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Destaque areas de toque menos óbvias", "pickExportDir": "Escolher Diretorio de Exportação", "autoExportOnChanges": "Auto-exportar em mudanças", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filtrar Versões por Expressão Regular", "trySelectingSuggestedVersionCode": "Tente selecionar a versão sugerida", "dontSortReleasesList": "Reter a ordem de lançamento da API", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index b5682ea..b0dfae8 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Выделить менее очевидные элементы управления касанием", "pickExportDir": "Выбрать каталог для экспорта", "autoExportOnChanges": "Автоэкспорт при изменениях", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Фильтровать версии по регулярному выражению", "trySelectingSuggestedVersionCode": "Попробуйте выбрать предложенный код версии APK", "dontSortReleasesList": "Сохранить порядок релизов от API", diff --git a/assets/translations/sv.json b/assets/translations/sv.json index 6df5314..c4b0304 100644 --- a/assets/translations/sv.json +++ b/assets/translations/sv.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Highlight less obvious touch targets", "pickExportDir": "Välj Exportsökväg", "autoExportOnChanges": "Automatisk export vid ändringar", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Filter Versions by Regular Expression", "trySelectingSuggestedVersionCode": "Try selecting suggested versionCode APK", "dontSortReleasesList": "Retain release order from API", diff --git a/assets/translations/tr.json b/assets/translations/tr.json index a463ae6..d2c15f3 100644 --- a/assets/translations/tr.json +++ b/assets/translations/tr.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Daha az belirgin dokunma hedeflerini vurgula", "pickExportDir": "Dışa Aktarılacak Klasörü Seç", "autoExportOnChanges": "Değişikliklerde otomatik olarak dışa aktar", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Sürümleri Düzenli İfade ile Filtrele", "trySelectingSuggestedVersionCode": "Önerilen sürüm kodunu seçmeyi dene", "dontSortReleasesList": "API'den sıralama düzenini koru", diff --git a/assets/translations/vi.json b/assets/translations/vi.json index 5f649f5..e5cd308 100644 --- a/assets/translations/vi.json +++ b/assets/translations/vi.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "Đánh dấu các mục tiêu cảm ứng ít rõ ràng hơn", "pickExportDir": "Chọn thư mục xuất", "autoExportOnChanges": "Tự động xuất khi thay đổi", + "includeSettings": "Include settings", "filterVersionsByRegEx": "Lọc phiên bản theo biểu thức chính quy", "trySelectingSuggestedVersionCode": "Thử chọn APK Mã phiên bản được đề xuất", "dontSortReleasesList": "Giữ lại thứ tự phát hành từ API", diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 0de58fc..46682d3 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -256,6 +256,7 @@ "highlightTouchTargets": "突出展示不明显的触摸区域", "pickExportDir": "选择导出文件夹", "autoExportOnChanges": "数据变更时自动导出", + "includeSettings": "Include settings", "filterVersionsByRegEx": "筛选版本号(正则表达式)", "trySelectingSuggestedVersionCode": "尝试选择推荐版本的 APK 文件", "dontSortReleasesList": "保持来自 API 的发行顺序", diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index e523792..0083512 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -388,6 +388,14 @@ class _ImportExportPageState extends State { defaultValue: settingsProvider .autoExportOnChanges, ) + ], + [ + GeneratedFormSwitch( + 'exportSettings', + label: tr('includeSettings'), + defaultValue: settingsProvider + .exportSettings, + ) ] ], onValueChanges: @@ -400,6 +408,12 @@ class _ImportExportPageState extends State { 'autoExportOnChanges'] == true; } + if (value['exportSettings'] != + null) { + settingsProvider.exportSettings = + value['exportSettings'] == + true; + } } }), ], diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index dae50c4..9130684 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -1174,7 +1174,10 @@ class AppsProvider with ChangeNotifier { } Future exportApps( - {bool pickOnly = false, isAuto = false, SettingsProvider? sp}) async { + {bool pickOnly = false, + isAuto = false, + SettingsProvider? sp, + bool includeSettings = false}) async { SettingsProvider settingsProvider = sp ?? this.settingsProvider; var exportDir = await settingsProvider.getExportDir(); if (isAuto) { @@ -1203,12 +1206,22 @@ class AppsProvider with ChangeNotifier { } String? returnPath; if (!pickOnly) { + Map finalExport = {}; + finalExport['apps'] = apps.values.map((e) => e.app.toJson()).toList(); + if (settingsProvider.exportSettings) { + finalExport['settings'] = Map.fromEntries( + (settingsProvider.prefs + ?.getKeys() + .map((key) => + MapEntry(key, settingsProvider.prefs?.get(key))) + .toList()) ?? + []); + } var result = await saf.createFile(exportDir, displayName: '${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().toIso8601String().replaceAll(':', '-')}${isAuto ? '-auto' : ''}.json', mimeType: 'application/json', - bytes: Uint8List.fromList(utf8.encode( - jsonEncode(apps.values.map((e) => e.app.toJson()).toList())))); + bytes: Uint8List.fromList(utf8.encode(jsonEncode(finalExport)))); if (result == null) { throw ObtainiumError(tr('unexpectedError')); } @@ -1219,9 +1232,11 @@ class AppsProvider with ChangeNotifier { } Future importApps(String appsJSON) async { - List importedApps = (jsonDecode(appsJSON) as List) - .map((e) => App.fromJson(e)) - .toList(); + var decodedJSON = jsonDecode(appsJSON); + List importedApps = + ((decodedJSON['apps'] ?? decodedJSON) as List) + .map((e) => App.fromJson(e)) + .toList(); while (loadingApps) { await Future.delayed(const Duration(microseconds: 1)); } @@ -1232,6 +1247,18 @@ class AppsProvider with ChangeNotifier { } await saveApps(importedApps, onlyIfExists: false); notifyListeners(); + if (decodedJSON['settings'] != null) { + var settingsMap = decodedJSON['settings'] as Map; + settingsMap.forEach((key, value) { + if (value is int) { + settingsProvider.prefs?.setInt(key, value); + } else if (value is bool) { + settingsProvider.prefs?.setBool(key, value); + } else { + settingsProvider.prefs?.setString(key, value as String); + } + }); + } return importedApps.length; } diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index cf3c7c6..25e9a3b 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -416,4 +416,13 @@ class SettingsProvider with ChangeNotifier { prefs?.setBool('onlyCheckInstalledOrTrackOnlyApps', val); notifyListeners(); } + + bool get exportSettings { + return prefs?.getBool('exportSettings') ?? false; + } + + set exportSettings(bool val) { + prefs?.setBool('exportSettings', val); + notifyListeners(); + } } From ffefa4b30e813c2415e92a85d7bc07e413caa84e Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 02:57:08 -0500 Subject: [PATCH 07/11] Update packages, increment version --- lib/main.dart | 2 +- pubspec.lock | 28 ++++++++++++++-------------- pubspec.yaml | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index fa1a657..824818e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,7 +19,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; // ignore: implementation_imports import 'package:easy_localization/src/localization.dart'; -const String currentVersion = '0.14.36'; +const String currentVersion = '0.14.37'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES diff --git a/pubspec.lock b/pubspec.lock index cf74778..72e6244 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -102,10 +102,10 @@ packages: dependency: transitive description: name: cli_util - sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.1" clock: dependency: transitive description: @@ -823,10 +823,10 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba + sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.2" url_launcher_android: dependency: transitive description: @@ -847,10 +847,10 @@ packages: dependency: transitive description: name: url_launcher_linux - sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd" + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" url_launcher_macos: dependency: transitive description: @@ -871,26 +871,26 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "138bd45b3a456dcfafc46d1a146787424f8d2edfbf2809c9324361e58f851cf7" + sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc" + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" uuid: dependency: transitive description: name: uuid - sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921 + sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "4.2.2" vector_math: dependency: transitive description: @@ -919,10 +919,10 @@ packages: dependency: transitive description: name: webview_flutter_android - sha256: "8326ee235f87605a2bfc444a4abc897f4abc78d83f054ba7d3d1074ce82b4fbf" + sha256: e313dcdf45d4c95bcb8960351ef2389b7f0687b90bc92483f7f7983ae5758456 url: "https://pub.dev" source: hosted - version: "3.12.1" + version: "3.13.0" webview_flutter_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8a9ffeb..79739f3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.14.36+230 # When changing this, update the tag in main() accordingly +version: 0.14.37+231 # When changing this, update the tag in main() accordingly environment: sdk: '>=3.0.0 <4.0.0' From 5720c55301c5798f838d456e80befd3b679ddc00 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 03:43:55 -0500 Subject: [PATCH 08/11] bugs --- android/app/src/main/AndroidManifest.xml | 2 +- lib/pages/home.dart | 20 +++++++++----------- lib/pages/import_export.dart | 9 ++++++--- lib/providers/apps_provider.dart | 21 ++++++++++----------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5e60b1c..fb0c563 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ { } else if (action == 'app') { await context .read() - .importApps('[${Uri.decodeComponent(data)}]'); + .import('[${Uri.decodeComponent(data)}]'); } else if (action == 'apps') { - await context - .read() - .importApps(Uri.decodeComponent(data)); + await context.read().import(Uri.decodeComponent(data)); } else { throw ObtainiumError(tr('unknown')); } @@ -145,13 +143,13 @@ class _HomePageState extends State { AppsProvider appsProvider = context.watch(); SettingsProvider settingsProvider = context.watch(); - if (!prevIsLoading && - prevAppCount >= 0 && - appsProvider.apps.length > prevAppCount && - selectedIndexHistory.isNotEmpty && - selectedIndexHistory.last == 1) { - switchToPage(0); - } + // if (!prevIsLoading && + // prevAppCount >= 0 && + // appsProvider.apps.length > prevAppCount && + // selectedIndexHistory.isNotEmpty && + // selectedIndexHistory.last == 1) { + // switchToPage(0); + // } prevAppCount = appsProvider.apps.length; prevIsLoading = appsProvider.loadingApps; diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index 0083512..0a624e9 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -106,7 +106,7 @@ class _ImportExportPageState extends State { runObtainiumExport({bool pickOnly = false}) async { HapticFeedback.selectionClick(); appsProvider - .exportApps( + .export( pickOnly: pickOnly || (await settingsProvider.getExportDir()) == null, sp: settingsProvider) @@ -132,7 +132,7 @@ class _ImportExportPageState extends State { } catch (e) { throw ObtainiumError(tr('invalidInput')); } - appsProvider.importApps(data).then((value) { + appsProvider.import(data).then((value) { var cats = settingsProvider.categories; appsProvider.apps.forEach((key, value) { for (var c in value.app.categories) { @@ -143,7 +143,10 @@ class _ImportExportPageState extends State { }); appsProvider.addMissingCategories(settingsProvider); showMessage( - tr('importedX', args: [plural('apps', value)]), context); + '${tr('importedX', args: [ + plural('apps', value.key) + ])}${value.value ? ' + ${tr('settings')}' : ''}', + context); }); } else { // User canceled the picker diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 9130684..e76c1fd 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -974,7 +974,7 @@ class AppsProvider with ChangeNotifier { } } notifyListeners(); - exportApps(isAuto: true); + export(isAuto: true); } Future removeApps(List appIds) async { @@ -996,7 +996,7 @@ class AppsProvider with ChangeNotifier { } if (appIds.isNotEmpty) { notifyListeners(); - exportApps(isAuto: true); + export(isAuto: true); } } @@ -1173,11 +1173,8 @@ class AppsProvider with ChangeNotifier { return updateAppIds; } - Future exportApps( - {bool pickOnly = false, - isAuto = false, - SettingsProvider? sp, - bool includeSettings = false}) async { + Future export( + {bool pickOnly = false, isAuto = false, SettingsProvider? sp}) async { SettingsProvider settingsProvider = sp ?? this.settingsProvider; var exportDir = await settingsProvider.getExportDir(); if (isAuto) { @@ -1231,10 +1228,11 @@ class AppsProvider with ChangeNotifier { return returnPath; } - Future importApps(String appsJSON) async { + Future> import(String appsJSON) async { var decodedJSON = jsonDecode(appsJSON); + var newFormat = !(decodedJSON is List); List importedApps = - ((decodedJSON['apps'] ?? decodedJSON) as List) + ((newFormat ? decodedJSON['apps'] : decodedJSON) as List) .map((e) => App.fromJson(e)) .toList(); while (loadingApps) { @@ -1247,7 +1245,7 @@ class AppsProvider with ChangeNotifier { } await saveApps(importedApps, onlyIfExists: false); notifyListeners(); - if (decodedJSON['settings'] != null) { + if (newFormat && decodedJSON['settings'] != null) { var settingsMap = decodedJSON['settings'] as Map; settingsMap.forEach((key, value) { if (value is int) { @@ -1259,7 +1257,8 @@ class AppsProvider with ChangeNotifier { } }); } - return importedApps.length; + return MapEntry( + importedApps.length, newFormat && decodedJSON['settings'] != null); } @override From 5da56acac87fe42beb19bf8467d065477169562c Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 03:45:15 -0500 Subject: [PATCH 09/11] bug --- lib/pages/home.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pages/home.dart b/lib/pages/home.dart index dc94317..84f4c81 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -77,9 +77,11 @@ class _HomePageState extends State { } else if (action == 'app') { await context .read() - .import('[${Uri.decodeComponent(data)}]'); + .import('{ apps: [${Uri.decodeComponent(data)}] }'); } else if (action == 'apps') { - await context.read().import(Uri.decodeComponent(data)); + await context + .read() + .import('{ apps: ${Uri.decodeComponent(data)} }'); } else { throw ObtainiumError(tr('unknown')); } From ede65eda6c41c9473f843360b4b3faf95fb8a0de Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 03:47:29 -0500 Subject: [PATCH 10/11] bug --- lib/pages/home.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 84f4c81..7ec92e8 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -77,11 +77,11 @@ class _HomePageState extends State { } else if (action == 'app') { await context .read() - .import('{ apps: [${Uri.decodeComponent(data)}] }'); + .import('{ "apps": [${Uri.decodeComponent(data)}] }'); } else if (action == 'apps') { await context .read() - .import('{ apps: ${Uri.decodeComponent(data)} }'); + .import('{ "apps": ${Uri.decodeComponent(data)} }'); } else { throw ObtainiumError(tr('unknown')); } From 65988f4e088ecfffe13d88e0d001a1c637ee41a4 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 16 Dec 2023 04:02:10 -0500 Subject: [PATCH 11/11] Link UI bugfix --- lib/pages/home.dart | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 7ec92e8..0bba900 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -36,6 +36,7 @@ class _HomePageState extends State { bool prevIsLoading = true; late AppLinks _appLinks; StreamSubscription? _linkSubscription; + bool isLinkActivity = false; List pages = [ NavigationPageItem(tr('appsString'), Icons.apps, @@ -69,6 +70,7 @@ class _HomePageState extends State { } interpretLink(Uri uri) async { + isLinkActivity = true; var action = uri.host; var data = uri.path.length > 1 ? uri.path.substring(1) : ""; try { @@ -124,12 +126,6 @@ class _HomePageState extends State { } else if (selectedIndexHistory.isEmpty || (selectedIndexHistory.isNotEmpty && selectedIndexHistory.last != index)) { - // while (index == 1 && - // (pages[0].widget.key as GlobalKey).currentState != - // null) { - // // Avoid duplicate GlobalKey error - // await Future.delayed(const Duration(microseconds: 1)); - // } setState(() { int existingInd = selectedIndexHistory.indexOf(index); if (existingInd >= 0) { @@ -145,13 +141,14 @@ class _HomePageState extends State { AppsProvider appsProvider = context.watch(); SettingsProvider settingsProvider = context.watch(); - // if (!prevIsLoading && - // prevAppCount >= 0 && - // appsProvider.apps.length > prevAppCount && - // selectedIndexHistory.isNotEmpty && - // selectedIndexHistory.last == 1) { - // switchToPage(0); - // } + if (!prevIsLoading && + prevAppCount >= 0 && + appsProvider.apps.length > prevAppCount && + selectedIndexHistory.isNotEmpty && + selectedIndexHistory.last == 1 && + !isLinkActivity) { + switchToPage(0); + } prevAppCount = appsProvider.apps.length; prevIsLoading = appsProvider.loadingApps; @@ -197,6 +194,11 @@ class _HomePageState extends State { ), ), onWillPop: () async { + if (isLinkActivity && + selectedIndexHistory.length == 1 && + selectedIndexHistory.last == 1) { + return true; + } setIsReversing(selectedIndexHistory.length >= 2 ? selectedIndexHistory.reversed.toList()[1] : 0);