mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-04 07:13:28 +01:00 
			
		
		
		
	Merge pull request #504 from ImranR98/dev
Less restrictive install permission requests (#495) Add toggles to disable warnings (#495 Fix a breaking bug on Add App page from the previous PR
This commit is contained in:
		@@ -224,6 +224,10 @@
 | 
			
		||||
    "standardVersionDetection": "Standardversionserkennung",
 | 
			
		||||
    "groupByCategory": "Nach Kategorie gruppieren",
 | 
			
		||||
    "autoApkFilterByArch": "Nach Möglichkeit versuchen, APKs nach CPU-Architektur zu filtern",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "App entfernen?",
 | 
			
		||||
        "other": "Apps entfernen?"
 | 
			
		||||
 
 | 
			
		||||
@@ -225,6 +225,9 @@
 | 
			
		||||
    "groupByCategory": "Group by Category",
 | 
			
		||||
    "autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show 'Track-Only' Warnings",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Remove App?",
 | 
			
		||||
        "other": "Remove Apps?"
 | 
			
		||||
 
 | 
			
		||||
@@ -224,6 +224,10 @@
 | 
			
		||||
    "standardVersionDetection": "تشخیص نسخه استاندارد",
 | 
			
		||||
    "groupByCategory": "گروه بر اساس دسته",
 | 
			
		||||
    "autoApkFilterByArch": "در صورت امکان سعی کنید APKها را بر اساس معماری CPU فیلتر کنید",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "برنامه حذف شود؟",
 | 
			
		||||
        "other": "برنامه ها حذف شوند؟"
 | 
			
		||||
 
 | 
			
		||||
@@ -224,6 +224,10 @@
 | 
			
		||||
    "standardVersionDetection": "Détection de version standard",
 | 
			
		||||
    "groupByCategory": "Group by Category",
 | 
			
		||||
    "autoApkFilterByArch": "Attempt to filter APKs by CPU architecture if possible",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Supprimer l'application ?",
 | 
			
		||||
        "other": "Supprimer les applications ?"
 | 
			
		||||
 
 | 
			
		||||
@@ -223,6 +223,10 @@
 | 
			
		||||
    "standardVersionDetection": "Alapért. verzió érzékelés",
 | 
			
		||||
    "groupByCategory": "Csoportosítás Kategória alapján",
 | 
			
		||||
    "autoApkFilterByArch": "Ha lehetséges, próbálja CPU architektúra szerint szűrni az APK-kat",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Eltávolítja az alkalmazást?",
 | 
			
		||||
        "other": "Eltávolítja az alkalmazást?"
 | 
			
		||||
 
 | 
			
		||||
@@ -224,6 +224,10 @@
 | 
			
		||||
    "standardVersionDetection": "Rilevamento di versione standard",
 | 
			
		||||
    "groupByCategory": "Raggruppa per categoria",
 | 
			
		||||
    "autoApkFilterByArch": "Tenta di filtrare gli APK in base all'architettura della CPU, se possibile",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "Rimuovere l'App?",
 | 
			
		||||
        "other": "Rimuovere le App?"
 | 
			
		||||
 
 | 
			
		||||
@@ -224,6 +224,10 @@
 | 
			
		||||
    "standardVersionDetection": "標準のバージョン検出",
 | 
			
		||||
    "groupByCategory": "カテゴリ別にグループ化する",
 | 
			
		||||
    "autoApkFilterByArch": "可能であれば,CPUアーキテクチャによるAPKのフィルタリングを試みる",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "アプリを削除しますか?",
 | 
			
		||||
        "other": "アプリを削除しますか?"
 | 
			
		||||
 
 | 
			
		||||
@@ -224,6 +224,10 @@
 | 
			
		||||
    "standardVersionDetection": "常规版本检测",
 | 
			
		||||
    "groupByCategory": "按类别分组显示",
 | 
			
		||||
    "autoApkFilterByArch": "如果可能,尝试按 CPU 架构筛选 APK 文件",
 | 
			
		||||
    "overrideSource": "Override Source",
 | 
			
		||||
    "dontShowAgain": "Don't show this again",
 | 
			
		||||
    "dontShowTrackOnlyWarnings": "Don't Show the 'Track-Only' Warning",
 | 
			
		||||
    "dontShowAPKOriginWarnings": "Don't Show APK Origin Warnings",
 | 
			
		||||
    "removeAppQuestion": {
 | 
			
		||||
        "one": "是否删除应用?",
 | 
			
		||||
        "other": "是否删除应用?"
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,18 @@ class _AddAppPageState extends State<AddAppPage> {
 | 
			
		||||
            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)
 | 
			
		||||
@@ -71,24 +83,35 @@ class _AddAppPageState extends State<AddAppPage> {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getTrackOnlyConfirmationIfNeeded(bool userPickedTrackOnly) async {
 | 
			
		||||
      return (!((userPickedTrackOnly || pickedSource!.enforceTrackOnly) &&
 | 
			
		||||
    Future<bool> getTrackOnlyConfirmationIfNeeded(
 | 
			
		||||
        bool userPickedTrackOnly, SettingsProvider settingsProvider,
 | 
			
		||||
        {bool ignoreHideSetting = false}) async {
 | 
			
		||||
      var useTrackOnly = userPickedTrackOnly || pickedSource!.enforceTrackOnly;
 | 
			
		||||
      if (useTrackOnly &&
 | 
			
		||||
          (!settingsProvider.hideTrackOnlyWarning || ignoreHideSetting)) {
 | 
			
		||||
        // ignore: use_build_context_synchronously
 | 
			
		||||
          await showDialog(
 | 
			
		||||
        var values = await showDialog(
 | 
			
		||||
            context: context,
 | 
			
		||||
            builder: (BuildContext ctx) {
 | 
			
		||||
              return GeneratedFormModal(
 | 
			
		||||
                initValid: true,
 | 
			
		||||
                title: tr('xIsTrackOnly', args: [
 | 
			
		||||
                        pickedSource!.enforceTrackOnly
 | 
			
		||||
                            ? tr('source')
 | 
			
		||||
                            : tr('app')
 | 
			
		||||
                  pickedSource!.enforceTrackOnly ? tr('source') : tr('app')
 | 
			
		||||
                ]),
 | 
			
		||||
                      items: const [],
 | 
			
		||||
                items: [
 | 
			
		||||
                  [GeneratedFormSwitch('hide', label: tr('dontShowAgain'))]
 | 
			
		||||
                ],
 | 
			
		||||
                message:
 | 
			
		||||
                    '${pickedSource!.enforceTrackOnly ? tr('appsFromSourceAreTrackOnly') : tr('youPickedTrackOnly')}\n\n${tr('trackOnlyAppDescription')}',
 | 
			
		||||
              );
 | 
			
		||||
                  }) ==
 | 
			
		||||
              null));
 | 
			
		||||
            });
 | 
			
		||||
        if (values != null) {
 | 
			
		||||
          settingsProvider.hideTrackOnlyWarning = values['hide'] == true;
 | 
			
		||||
        }
 | 
			
		||||
        return useTrackOnly && values != null;
 | 
			
		||||
      } else {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getReleaseDateAsVersionConfirmationIfNeeded(
 | 
			
		||||
@@ -116,7 +139,8 @@ class _AddAppPageState extends State<AddAppPage> {
 | 
			
		||||
        var settingsProvider = context.read<SettingsProvider>();
 | 
			
		||||
        var userPickedTrackOnly = additionalSettings['trackOnly'] == true;
 | 
			
		||||
        App? app;
 | 
			
		||||
        if ((await getTrackOnlyConfirmationIfNeeded(userPickedTrackOnly)) &&
 | 
			
		||||
        if ((await getTrackOnlyConfirmationIfNeeded(
 | 
			
		||||
                userPickedTrackOnly, settingsProvider)) &&
 | 
			
		||||
            (await getReleaseDateAsVersionConfirmationIfNeeded(
 | 
			
		||||
                userPickedTrackOnly))) {
 | 
			
		||||
          var trackOnly = pickedSource!.enforceTrackOnly || userPickedTrackOnly;
 | 
			
		||||
@@ -124,9 +148,6 @@ class _AddAppPageState extends State<AddAppPage> {
 | 
			
		||||
              pickedSource!, userInput, additionalSettings,
 | 
			
		||||
              trackOnlyOverride: trackOnly,
 | 
			
		||||
              overrideSource: pickedSourceOverride);
 | 
			
		||||
          if (!trackOnly) {
 | 
			
		||||
            await settingsProvider.getInstallPermission();
 | 
			
		||||
          }
 | 
			
		||||
          // Only download the APK here if you need to for the package ID
 | 
			
		||||
          if (sourceProvider.isTempId(app) &&
 | 
			
		||||
              app.additionalSettings['trackOnly'] != true) {
 | 
			
		||||
 
 | 
			
		||||
@@ -327,9 +327,6 @@ class _AppPageState extends State<AppPage> {
 | 
			
		||||
            ? () async {
 | 
			
		||||
                try {
 | 
			
		||||
                  HapticFeedback.heavyImpact();
 | 
			
		||||
                  if (app?.app.additionalSettings['trackOnly'] != true) {
 | 
			
		||||
                    await settingsProvider.getInstallPermission();
 | 
			
		||||
                  }
 | 
			
		||||
                  var res = await appsProvider.downloadAndInstallLatestApps(
 | 
			
		||||
                      [app!.app.id], globalNavigatorKey.currentContext);
 | 
			
		||||
                  if (res.isNotEmpty && mounted) {
 | 
			
		||||
 
 | 
			
		||||
@@ -615,7 +615,7 @@ class AppsPageState extends State<AppsPage> {
 | 
			
		||||
                      items: formItems.map((e) => [e]).toList(),
 | 
			
		||||
                      initValid: true,
 | 
			
		||||
                    );
 | 
			
		||||
                  }).then((values) {
 | 
			
		||||
                  }).then((values) async {
 | 
			
		||||
                if (values != null) {
 | 
			
		||||
                  if (values.isEmpty) {
 | 
			
		||||
                    values = getDefaultValuesFromFormItems([formItems]);
 | 
			
		||||
@@ -623,12 +623,6 @@ class AppsPageState extends State<AppsPage> {
 | 
			
		||||
                  bool shouldInstallUpdates = values['updates'] == true;
 | 
			
		||||
                  bool shouldInstallNew = values['installs'] == true;
 | 
			
		||||
                  bool shouldMarkTrackOnlies = values['trackonlies'] == true;
 | 
			
		||||
                  (() async {
 | 
			
		||||
                    if (shouldInstallNew || shouldInstallUpdates) {
 | 
			
		||||
                      await settingsProvider.getInstallPermission();
 | 
			
		||||
                    }
 | 
			
		||||
                  })()
 | 
			
		||||
                      .then((_) {
 | 
			
		||||
                  List<String> toInstall = [];
 | 
			
		||||
                  if (shouldInstallUpdates) {
 | 
			
		||||
                    toInstall.addAll(existingUpdateIdsAllOrSelected);
 | 
			
		||||
@@ -641,11 +635,11 @@ class AppsPageState extends State<AppsPage> {
 | 
			
		||||
                  }
 | 
			
		||||
                  appsProvider
 | 
			
		||||
                      .downloadAndInstallLatestApps(
 | 
			
		||||
                            toInstall, globalNavigatorKey.currentContext)
 | 
			
		||||
                          toInstall, globalNavigatorKey.currentContext,
 | 
			
		||||
                          settingsProvider: settingsProvider)
 | 
			
		||||
                      .catchError((e) {
 | 
			
		||||
                    showError(e, context);
 | 
			
		||||
                  });
 | 
			
		||||
                  });
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -286,6 +286,34 @@ class _SettingsPageState extends State<SettingsPage> {
 | 
			
		||||
                                    })
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                            height16,
 | 
			
		||||
                            Row(
 | 
			
		||||
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                              children: [
 | 
			
		||||
                                Text(tr('dontShowTrackOnlyWarnings')),
 | 
			
		||||
                                Switch(
 | 
			
		||||
                                    value:
 | 
			
		||||
                                        settingsProvider.hideTrackOnlyWarning,
 | 
			
		||||
                                    onChanged: (value) {
 | 
			
		||||
                                      settingsProvider.hideTrackOnlyWarning =
 | 
			
		||||
                                          value;
 | 
			
		||||
                                    })
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                            height16,
 | 
			
		||||
                            Row(
 | 
			
		||||
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                              children: [
 | 
			
		||||
                                Text(tr('dontShowAPKOriginWarnings')),
 | 
			
		||||
                                Switch(
 | 
			
		||||
                                    value:
 | 
			
		||||
                                        settingsProvider.hideAPKOriginWarning,
 | 
			
		||||
                                    onChanged: (value) {
 | 
			
		||||
                                      settingsProvider.hideAPKOriginWarning =
 | 
			
		||||
                                          value;
 | 
			
		||||
                                    })
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                            const Divider(
 | 
			
		||||
                              height: 16,
 | 
			
		||||
                            ),
 | 
			
		||||
 
 | 
			
		||||
@@ -332,7 +332,10 @@ class AppsProvider with ChangeNotifier {
 | 
			
		||||
        getHost(apkUrl.value) != getHost(app.url) &&
 | 
			
		||||
        context != null) {
 | 
			
		||||
      // ignore: use_build_context_synchronously
 | 
			
		||||
      if (await showDialog(
 | 
			
		||||
      var settingsProvider = context.read<SettingsProvider>();
 | 
			
		||||
      if (!(settingsProvider.hideAPKOriginWarning) &&
 | 
			
		||||
          // ignore: use_build_context_synchronously
 | 
			
		||||
          await showDialog(
 | 
			
		||||
                  context: context,
 | 
			
		||||
                  builder: (BuildContext ctx) {
 | 
			
		||||
                    return APKOriginWarningDialog(
 | 
			
		||||
@@ -351,7 +354,8 @@ class AppsProvider with ChangeNotifier {
 | 
			
		||||
  // If user input is needed and the App is in the background, a notification is sent to get the user's attention
 | 
			
		||||
  // Returns an array of Ids for Apps that were successfully downloaded, regardless of installation result
 | 
			
		||||
  Future<List<String>> downloadAndInstallLatestApps(
 | 
			
		||||
      List<String> appIds, BuildContext? context) async {
 | 
			
		||||
      List<String> appIds, BuildContext? context,
 | 
			
		||||
      {SettingsProvider? settingsProvider}) async {
 | 
			
		||||
    List<String> appsToInstall = [];
 | 
			
		||||
    List<String> trackOnlyAppsToUpdate = [];
 | 
			
		||||
    // For all specified Apps, filter out those for which:
 | 
			
		||||
@@ -440,6 +444,11 @@ class AppsProvider with ChangeNotifier {
 | 
			
		||||
    silentUpdates = moveObtainiumToStart(silentUpdates);
 | 
			
		||||
    regularInstalls = moveObtainiumToStart(regularInstalls);
 | 
			
		||||
 | 
			
		||||
    if (!(await settingsProvider?.getInstallPermission(enforce: false) ??
 | 
			
		||||
        true)) {
 | 
			
		||||
      throw ObtainiumError(tr('cancelled'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // // Install silent updates (uncomment when it works - TODO)
 | 
			
		||||
    // for (var u in silentUpdates) {
 | 
			
		||||
    //   await installApk(u, silent: true); // Would need to add silent option
 | 
			
		||||
 
 | 
			
		||||
@@ -120,16 +120,20 @@ class SettingsProvider with ChangeNotifier {
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> getInstallPermission() async {
 | 
			
		||||
  Future<bool> getInstallPermission({bool enforce = false}) async {
 | 
			
		||||
    while (!(await Permission.requestInstallPackages.isGranted)) {
 | 
			
		||||
      // Explicit request as InstallPlugin request sometimes bugged
 | 
			
		||||
      Fluttertoast.showToast(
 | 
			
		||||
          msg: tr('pleaseAllowInstallPerm'), toastLength: Toast.LENGTH_LONG);
 | 
			
		||||
      if ((await Permission.requestInstallPackages.request()) ==
 | 
			
		||||
          PermissionStatus.granted) {
 | 
			
		||||
        break;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      if (!enforce) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool get showAppWebpage {
 | 
			
		||||
@@ -159,6 +163,24 @@ class SettingsProvider with ChangeNotifier {
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool get hideTrackOnlyWarning {
 | 
			
		||||
    return prefs?.getBool('hideTrackOnlyWarning') ?? false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set hideTrackOnlyWarning(bool show) {
 | 
			
		||||
    prefs?.setBool('hideTrackOnlyWarning', show);
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool get hideAPKOriginWarning {
 | 
			
		||||
    return prefs?.getBool('hideAPKOriginWarning') ?? false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set hideAPKOriginWarning(bool show) {
 | 
			
		||||
    prefs?.setBool('hideAPKOriginWarning', show);
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String? getSettingString(String settingId) {
 | 
			
		||||
    return prefs?.getString(settingId);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -470,7 +470,7 @@ class SourceProvider {
 | 
			
		||||
    }
 | 
			
		||||
    AppSource? source;
 | 
			
		||||
    for (var s in sources.where((element) => element.host != null)) {
 | 
			
		||||
      if (RegExp('://${s.host}').hasMatch(url)) {
 | 
			
		||||
      if (RegExp('://${s.host}(/|\\z)?').hasMatch(url)) {
 | 
			
		||||
        source = s;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -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.12.0+159 # When changing this, update the tag in main() accordingly
 | 
			
		||||
version: 0.12.0+160 # When changing this, update the tag in main() accordingly
 | 
			
		||||
 | 
			
		||||
environment:
 | 
			
		||||
  sdk: '>=2.18.2 <3.0.0'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user