mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-31 05:23:28 +01:00 
			
		
		
		
	Compare commits
	
		
			58 Commits
		
	
	
		
			v0.13.22-b
			...
			v0.13.26-b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | ce89d456e1 | ||
|  | a0c48fcca6 | ||
|  | d0cba6d6bc | ||
|  | 6baf6ccf4b | ||
|  | a2571e61a8 | ||
|  | f61824ff0d | ||
|  | 734a1aeb01 | ||
|  | 5269aad90d | ||
|  | eaeee188eb | ||
|  | 8c850e06ca | ||
|  | 0f754a8da8 | ||
|  | 81c4d4f393 | ||
|  | 5317aee18d | ||
|  | b66eeba3b5 | ||
|  | 522ff1ddf7 | ||
|  | 7ef9c43ee3 | ||
|  | 05ac76e3e9 | ||
|  | 4838402797 | ||
|  | 0de12c7c07 | ||
|  | 0dadd8bffe | ||
|  | 75a0cb1189 | ||
|  | a52d936b4d | ||
|  | cfd04dc602 | ||
|  | 7622e63975 | ||
|  | 3e7172b9d1 | ||
|  | 7aa0294447 | ||
|  | 5b89c4d293 | ||
|  | 3bb991f57f | ||
|  | 1dd3aa0e8a | ||
|  | 189cecbc37 | ||
|  | 9680ba08e9 | ||
|  | dcf5bd37ca | ||
|  | d6a4b0a96d | ||
|  | 5f8638d349 | ||
|  | 1de274df39 | ||
|  | 3df801c54e | ||
|  | d473cb49c5 | ||
|  | 2a5118a2cf | ||
|  | 347c56da55 | ||
|  | 8073723e1f | ||
|  | c8e90a755d | ||
|  | aeb0a5d8ea | ||
|  | 09fe7f3ecd | ||
|  | a549411589 | ||
|  | f426b5e118 | ||
|  | 12a8ef5e31 | ||
|  | 8210279a4c | ||
|  | 999d13b80d | ||
|  | 0573c0b270 | ||
|  | 5a36a7980c | ||
|  | 6bf9b5297f | ||
|  | fdc6b0ff00 | ||
|  | 73c20a53d2 | ||
|  | 16ae8d8e4d | ||
|  | 3f8cfae64e | ||
|  | 6861a71efb | ||
|  | 2a603f410f | ||
|  | 6d22788f92 | 
| @@ -18,6 +18,7 @@ Currently supported App sources: | ||||
| - [SourceHut](https://git.sr.ht/) | ||||
| - [APKMirror](https://apkmirror.com/) (Track-Only) | ||||
| - [APKPure](https://apkpure.com/) | ||||
| - [Huawei AppGallery](https://appgallery.huawei.com/) | ||||
| - Third Party F-Droid Repos | ||||
| - Jenkins Jobs | ||||
| - [Steam](https://store.steampowered.com/mobile) | ||||
|   | ||||
| @@ -49,7 +49,6 @@ android { | ||||
|     } | ||||
|  | ||||
|     defaultConfig { | ||||
|         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). | ||||
|         applicationId "dev.imranr.obtainium" | ||||
|         // You can update the following values to match your application needs. | ||||
|         // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. | ||||
|   | ||||
| @@ -62,6 +62,7 @@ | ||||
|     </application> | ||||
|     <uses-permission android:name="android.permission.INTERNET" /> | ||||
|     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> | ||||
|     <uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" /> | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> | ||||
|     <uses-permission android:name="android.permission.WAKE_LOCK"/> | ||||
|   | ||||
| @@ -244,6 +244,9 @@ | ||||
|    "addInfoInSettings": "Add this info in the Settings.", | ||||
|    "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|    "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|    "sortByFileNamesNotLinks": "Sort by file names instead of full links", | ||||
|    "filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression", | ||||
|    "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|    "removeAppQuestion": { | ||||
|       "one": "Želite li ukloniti aplikaciju?", | ||||
|       "other": "Želite li ukloniti aplikacije?" | ||||
|   | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "Warnung für 'Nur Nachverfolgen' nicht anzeigen", | ||||
|     "dontShowAPKOriginWarnings": "Warnung für APK-Herkunft nicht anzeigen", | ||||
|     "moveNonInstalledAppsToBottom": "Nicht installierte Apps ans Ende der Apps Ansicht verschieben", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche and Better APK Discovery)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Aktiviert Suche und bessere APK Entdeckung)", | ||||
|     "about": "Über", | ||||
|     "requiresCredentialsInSettings": "Benötigt zusätzliche Anmeldedaten (in den Einstellungen)", | ||||
|     "checkOnStart": "Überprüfe einmalig beim Start", | ||||
| @@ -240,10 +240,13 @@ | ||||
|     "disablePageTransitions": "Animationen für Seitenübergänge deaktivieren", | ||||
|     "reversePageTransitions": "Umgekehrte Animationen für Seitenübergänge", | ||||
|     "minStarCount": "Minimale Anzahl von Sternen", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "addInfoBelow": "Fügen Sie diese Informationen unten hinzu.", | ||||
|     "addInfoInSettings": "Fügen Sie diese Info in den Einstellungen hinzu.", | ||||
|     "githubSourceNote": "Die GitHub-Ratenbegrenzung kann mit einem API-Schlüssel umgangen werden.", | ||||
|     "gitlabSourceNote": "GitLab APK-Extraktion funktioniert möglicherweise nicht ohne API-Schlüssel", | ||||
|     "sortByFileNamesNotLinks": "Sortiere nach Dateinamen, anstelle von ganzen Links", | ||||
|     "filterReleaseNotesByRegEx": "Versionshinweise nach regulärem Ausdruck filtern", | ||||
|     "customLinkFilterRegex": "Benutzerdefinierter Link Filter nach Regulärem Ausdruck (Standard '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "App entfernen?", | ||||
|         "other": "Apps entfernen?" | ||||
|   | ||||
| @@ -244,6 +244,9 @@ | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "sortByFileNamesNotLinks": "Sort by file names instead of full links", | ||||
|     "filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression", | ||||
|     "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Remove App?", | ||||
|         "other": "Remove Apps?" | ||||
|   | ||||
| @@ -244,6 +244,9 @@ | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "sortByFileNamesNotLinks": "Sort by file names instead of full links", | ||||
|     "filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression", | ||||
|     "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "¿Eliminar Aplicación?", | ||||
|         "other": "¿Eliminar Aplicaciones?" | ||||
|   | ||||
| @@ -229,21 +229,24 @@ | ||||
|     "dontShowTrackOnlyWarnings": "هشدار 'فقط ردیابی' را نشان ندهید", | ||||
|     "dontShowAPKOriginWarnings": "هشدارهای منبع APK را نشان ندهید", | ||||
|     "moveNonInstalledAppsToBottom": "برنامه های نصب نشده را به نمای پایین برنامه ها منتقل کنید", | ||||
|     "gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو را فعال می کند and Better APK Discovery)", | ||||
|     "gitlabPATLabel": "رمز دسترسی شخصی GitLab\n(جستجو و کشف بهتر APK را فعال میکند)", | ||||
|     "about": "درباره", | ||||
|     "requiresCredentialsInSettings": "این به اعتبارنامه های اضافی نیاز دارد (در تنظیمات)", | ||||
|     "checkOnStart": "بررسی در شروع", | ||||
|     "tryInferAppIdFromCode": "شناسه برنامه را از کد منبع استنباط کنید", | ||||
|     "removeOnExternalUninstall": "Automatically remove externally uninstalled Apps", | ||||
|     "pickHighestVersionCode": "Auto-select highest version code APK", | ||||
|     "checkUpdateOnDetailPage": "Check for updates on opening an App detail page", | ||||
|     "disablePageTransitions": "Disable page transition animations", | ||||
|     "reversePageTransitions": "Reverse page transition animations", | ||||
|     "minStarCount": "Minimum Star Count", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "removeOnExternalUninstall": "حذف خودکار برنامه های حذف نصب شده خارجی", | ||||
|     "pickHighestVersionCode": "انتخاب خودکار بالاترین کد نسخه APK", | ||||
|     "checkUpdateOnDetailPage": "برای باز کردن صفحه جزئیات برنامه، بهروزرسانیها را بررسی کنید", | ||||
|     "disablePageTransitions": "غیرفعال کردن انیمیشن های انتقال صفحه", | ||||
|     "reversePageTransitions": "انیمیشن های انتقال معکوس صفحه", | ||||
|     "minStarCount": "حداقل تعداد ستاره", | ||||
|     "addInfoBelow": "این اطلاعات را در زیر اضافه کنید", | ||||
|     "addInfoInSettings": "این اطلاعات را در تنظیمات اضافه کنید.", | ||||
|     "githubSourceNote": "با استفاده از کلید API می توان از محدودیت نرخ GitHub جلوگیری کرد.", | ||||
|     "gitlabSourceNote": "استخراج APK GitLab ممکن است بدون کلید API کار نکند.", | ||||
|     "sortByFileNamesNotLinks": "مرتب سازی بر اساس نام فایل به جای پیوندهای کامل", | ||||
|     "filterReleaseNotesByRegEx": "یادداشت های انتشار را با بیان منظم فیلتر کنید", | ||||
|     "customLinkFilterRegex": "فیلتر پیوند سفارشی بر اساس عبارت منظم (پیشفرض '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "برنامه حذف شود؟", | ||||
|         "other": "برنامه ها حذف شوند؟" | ||||
|   | ||||
| @@ -45,7 +45,7 @@ | ||||
|     "addApp": "Ajouter une application", | ||||
|     "appSourceURL": "URL de la source de l'application", | ||||
|     "error": "Erreur", | ||||
|     "add": "Ajoutée", | ||||
|     "add": "Ajouter", | ||||
|     "searchSomeSourcesLabel": "Rechercher (certaines sources uniquement)", | ||||
|     "search": "Rechercher", | ||||
|     "additionalOptsFor": "Options supplémentaires pour {}", | ||||
| @@ -244,6 +244,9 @@ | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "sortByFileNamesNotLinks": "Sort by file names instead of full links", | ||||
|     "filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression", | ||||
|     "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Supprimer l'application ?", | ||||
|         "other": "Supprimer les applications ?" | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
|     "bgUpdateTaskFinished": "A háttérfrissítés ellenőrzési feladat befejeződött", | ||||
|     "firstRun": "Ez az Obtainium első futása", | ||||
|     "settingUpdateCheckIntervalTo": "A frissítési intervallum beállítása erre: {}", | ||||
|     "githubPATLabel": "GitHub személyes hozzáférési token (megnöveli a díjkorlátot)", | ||||
|     "githubPATLabel": "GitHub Personal Access Token (megnöveli a díjkorlátot)", | ||||
|     "githubPATHint": "A PAT-nak a következő formátumban kell lennie: felhasználónév:token", | ||||
|     "githubPATFormat": "felhasználónév:token", | ||||
|     "includePrereleases": "Tartalmazza az előzetes kiadásokat", | ||||
| @@ -93,13 +93,13 @@ | ||||
|     "author": "Szerző", | ||||
|     "upToDateApps": "Naprakész appok", | ||||
|     "nonInstalledApps": "Nem telepített appok", | ||||
|     "importExport": "Import/Export", | ||||
|     "importExport": "Importálás/Exportálás", | ||||
|     "settings": "Beállítások", | ||||
|     "exportedTo": "Exportálva ide {}", | ||||
|     "obtainiumExport": "Obtainium Export", | ||||
|     "obtainiumExport": "Obtainium Adat Exportálás", | ||||
|     "invalidInput": "Hibás bemenet", | ||||
|     "importedX": "Importálva innen {}", | ||||
|     "obtainiumImport": "Obtainium Import", | ||||
|     "obtainiumImport": "Obtainium Adat Importálás", | ||||
|     "importFromURLList": "Importálás URL listából", | ||||
|     "searchQuery": "Keresési lekérdezés", | ||||
|     "appURLList": "App URL lista", | ||||
| @@ -139,11 +139,11 @@ | ||||
|     "appSource": "App forrás", | ||||
|     "noLogs": "Nincsenek naplók", | ||||
|     "appLogs": "App naplók", | ||||
|     "close": "Bezár", | ||||
|     "share": "Megoszt", | ||||
|     "close": "Bezárás", | ||||
|     "share": "Megosztás", | ||||
|     "appNotFound": "App nem található", | ||||
|     "obtainiumExportHyphenatedLowercase": "obtainium-export", | ||||
|     "pickAnAPK": "Válasszon egy APK-t", | ||||
|     "pickAnAPK": "Válasszon egy APK-ot", | ||||
|     "appHasMoreThanOnePackage": "A(z) {} egynél több csomaggal rendelkezik:", | ||||
|     "deviceSupportsXArch": "Eszköze támogatja a {} CPU architektúrát.", | ||||
|     "deviceSupportsFollowingArchs": "Az eszköze a következő CPU architektúrákat támogatja:", | ||||
| @@ -210,7 +210,7 @@ | ||||
|     "copiedToClipboard": "Másolva a vágólapra", | ||||
|     "storagePermissionDenied": "Tárhely engedély megtagadva", | ||||
|     "selectedCategorizeWarning": "Ez felváltja a kiválasztott alkalmazások meglévő kategória-beállításait.", | ||||
|     "filterAPKsByRegEx": "Az APK-k szűrése reguláris kifejezéssel", | ||||
|     "filterAPKsByRegEx": "Az APK-ok szűrése reguláris kifejezéssel", | ||||
|     "removeFromObtainium": "Eltávolítás az Obtainiumból", | ||||
|     "uninstallFromDevice": "Eltávolítás a készülékről", | ||||
|     "onlyWorksWithNonVersionDetectApps": "Csak azoknál az alkalmazásoknál működik, amelyeknél a verzióérzékelés le van tiltva.", | ||||
| @@ -222,27 +222,30 @@ | ||||
|     "versionDetection": "Verzió érzékelés", | ||||
|     "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", | ||||
|     "autoApkFilterByArch": "Ha lehetséges, próbálja CPU architektúra szerint szűrni az APK-okat", | ||||
|     "overrideSource": "Forrás felülbírálása", | ||||
|     "dontShowAgain": "Ne mutassa ezt újra", | ||||
|     "dontShowTrackOnlyWarnings": "Ne jelenítsen meg 'Csak nyomon követés' figyelmeztetést", | ||||
|     "dontShowAPKOriginWarnings": "Ne jelenítsen meg az APK eredetére vonatkozó figyelmeztetéseket", | ||||
|     "moveNonInstalledAppsToBottom": "Helyezze át a nem telepített appokat az App nézet aljára", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést and Better APK Discovery)", | ||||
|     "gitlabPATLabel": "GitLab Personal Access Token\n(Engedélyezi a Keresést és jobb APK felfedezés)", | ||||
|     "about": "Rólunk", | ||||
|     "requiresCredentialsInSettings": "Ehhez további hitelesítő adatokra van szükség (a Beállításokban)", | ||||
|     "checkOnStart": "Egyszer az indításkor", | ||||
|     "checkOnStart": "Egyszer az alkalmazás indításakor is", | ||||
|     "tryInferAppIdFromCode": "Próbálja kikövetkeztetni az app azonosítót a forráskódból", | ||||
|     "removeOnExternalUninstall": "A külsőleg eltávolított appok auto. eltávolítása", | ||||
|     "pickHighestVersionCode": "A legmagasabb verziószámú APK auto. kiválasztása", | ||||
|     "checkUpdateOnDetailPage": "Frissítések keresése az app részleteit tartalmazó oldal megnyitásakor", | ||||
|     "disablePageTransitions": "Lap áttűnési animációk tiltása", | ||||
|     "disablePageTransitions": "Lap áttűnési animációk letiltása", | ||||
|     "reversePageTransitions": "Fordított lap áttűnési animációk", | ||||
|     "minStarCount": "Minimális csillag szám", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "addInfoBelow": "Adja hozzá ezt az infót alább.", | ||||
|     "addInfoInSettings": "Adja hozzá ezt az infót a Beállításokban.", | ||||
|     "githubSourceNote": "A GitHub sebességkorlátozás elkerülhető API-kulcs használatával.", | ||||
|     "gitlabSourceNote": "Előfordulhat, hogy a GitLab APK kibontása nem működik API-kulcs nélkül.", | ||||
|     "sortByFileNamesNotLinks": "Fájlnevek szerinti elrendezés teljes linkek helyett", | ||||
|     "filterReleaseNotesByRegEx": "Kiadási megjegyzések szűrése reguláris kifejezéssel", | ||||
|     "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Eltávolítja az alkalmazást?", | ||||
|         "other": "Eltávolítja az alkalmazást?" | ||||
| @@ -285,10 +288,10 @@ | ||||
|     }, | ||||
|     "xAndNMoreUpdatesAvailable": { | ||||
|         "one": "A(z) {} és 1 további alkalmazás frissítéseket kapott.", | ||||
|         "other": "{} és további {} alkalmazás frissítéseket kapott." | ||||
|         "other": "{} és {} további alkalmazás frissítéseket kapott." | ||||
|     }, | ||||
|     "xAndNMoreUpdatesInstalled": { | ||||
|         "one": "A(z) {} és 1 további alkalmazás frissítve.", | ||||
|         "other": "{} és további {} alkalmazás frissítve." | ||||
|         "other": "{} és {} további alkalmazás frissítve." | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -244,6 +244,9 @@ | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "sortByFileNamesNotLinks": "Sort by file names instead of full links", | ||||
|     "filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression", | ||||
|     "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Rimuovere l'app?", | ||||
|         "other": "Rimuovere le app?" | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
|     "githubPATFormat": "ユーザー名:トークン", | ||||
|     "includePrereleases": "プレリリースを含む", | ||||
|     "fallbackToOlderReleases": "旧リリースへのフォールバック", | ||||
|     "filterReleaseTitlesByRegEx": "正規表現でリリースタイトルを絞り込む", | ||||
|     "filterReleaseTitlesByRegEx": "正規表現でリリースタイトルをフィルタリングする", | ||||
|     "invalidRegEx": "無効な正規表現", | ||||
|     "noDescription": "説明はありません", | ||||
|     "cancel": "キャンセル", | ||||
| @@ -88,7 +88,7 @@ | ||||
|     "showOutdatedOnly": "アップデートが存在するアプリのみ表示する", | ||||
|     "filter": "フィルター", | ||||
|     "filterActive": "フィルター *", | ||||
|     "filterApps": "アプリを絞り込む", | ||||
|     "filterApps": "アプリをフィルタリングする", | ||||
|     "appName": "アプリ名", | ||||
|     "author": "作者", | ||||
|     "upToDateApps": "最新のアプリ", | ||||
| @@ -211,7 +211,7 @@ | ||||
|     "copiedToClipboard": "クリップボードにコピーしました", | ||||
|     "storagePermissionDenied": "ストレージ権限が拒否されました", | ||||
|     "selectedCategorizeWarning": "これにより、選択したアプリの既存のカテゴリ設定がすべて置き換えられます。", | ||||
|     "filterAPKsByRegEx": "正規表現でAPKを絞り込む", | ||||
|     "filterAPKsByRegEx": "正規表現でAPKをフィルタリングする", | ||||
|     "removeFromObtainium": "Obtainiumから削除する", | ||||
|     "uninstallFromDevice": "デバイスからアンインストールする", | ||||
|     "onlyWorksWithNonVersionDetectApps": "バージョン検出を無効にしているアプリにのみ動作します。", | ||||
| @@ -239,11 +239,14 @@ | ||||
|     "checkUpdateOnDetailPage": "アプリの詳細ページを開く際にアップデートを確認する", | ||||
|     "disablePageTransitions": "ページ遷移アニメーションを無効化する", | ||||
|     "reversePageTransitions": "ページ遷移アニメーションを反転する", | ||||
|     "minStarCount": "Minimum Star Count", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "minStarCount": "最小スター数", | ||||
|     "addInfoBelow": "下部でこの情報を追加してください。", | ||||
|     "addInfoInSettings": "設定でこの情報を追加してください。", | ||||
|     "githubSourceNote": "GitHubのレート制限はAPIキーを使うことで回避できます。", | ||||
|     "gitlabSourceNote": "GitLabのAPK抽出はAPIキーがないと動作しない場合があります。", | ||||
|     "sortByFileNamesNotLinks": "フルのリンクではなくファイル名でソートする", | ||||
|     "filterReleaseNotesByRegEx": "正規表現でリリースノートをフィルタリングする", | ||||
|     "customLinkFilterRegex": "正規表現によるカスタムリンクフィルター (デフォルト '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "アプリを削除しますか?", | ||||
|         "other": "アプリを削除しますか?" | ||||
|   | ||||
| @@ -244,10 +244,13 @@ | ||||
|     "disablePageTransitions": "Wyłącz animacje przejścia między stronami", | ||||
|     "reversePageTransitions": "Odwróć animacje przejścia pomiędzy stronami", | ||||
|     "minStarCount": "Minimalna ilość gwiazdek", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "addInfoBelow": "Dodaj tę informację poniżej.", | ||||
|     "addInfoInSettings": "Dodaj tę informację w Ustawieniach.", | ||||
|     "githubSourceNote": "Limit żądań GitHub można ominąć za pomocą klucza API.", | ||||
|     "gitlabSourceNote": "Pozyskiwanie pliku APK z GitLab może nie działać bez klucza API.", | ||||
|     "sortByFileNamesNotLinks": "Sortuj wg nazw plików zamiast pełnych linków", | ||||
|     "filterReleaseNotesByRegEx": "Filtruj informacje o wersji według wyrażenia regularnego", | ||||
|     "customLinkFilterRegex": "Niestandardowy filtr linków wg. wyrażenia regularnego (domyślnie \".apk$\")", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Usunąć aplikację?", | ||||
|         "other": "Usunąć aplikacje?" | ||||
|   | ||||
| @@ -240,10 +240,13 @@ | ||||
|     "disablePageTransitions": "Отключить анимацию перехода между страницами", | ||||
|     "reversePageTransitions": "Реверс анимации перехода между страницами", | ||||
|     "minStarCount": "Минимальное количество звёзд", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "addInfoBelow": "Добавьте эту информацию ниже.", | ||||
|     "addInfoInSettings": "Добавьте эту информацию в Настройки.", | ||||
|     "githubSourceNote": "Лимит запросов GitHub можно обойти, используя ключ API.", | ||||
|     "gitlabSourceNote": "Извлечение APK из GitLab может не работать без ключа API.", | ||||
|     "sortByFileNamesNotLinks": "Sort by file names instead of full links", | ||||
|     "filterReleaseNotesByRegEx": "Filter Release Notes by Regular Expression", | ||||
|     "customLinkFilterRegex": "Custom Link Filter by Regular Expression (Default '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Удалить приложение?", | ||||
|         "other": "Удалить приложения?" | ||||
|   | ||||
| @@ -107,7 +107,7 @@ | ||||
|     "searchX": "搜索 {}", | ||||
|     "noResults": "无结果", | ||||
|     "importX": "导入 {}", | ||||
|     "importedAppsIdDisclaimer": "导入的应用可能错误地显示为“未安装”。\n请通过 Obtainium 重新安装这些应用来解决此问题。", | ||||
|     "importedAppsIdDisclaimer": "导入的应用可能会错误地显示为“未安装”状态。\n请通过 Obtainium 重新安装这些应用来解决此问题。", | ||||
|     "importErrors": "导入错误", | ||||
|     "importedXOfYApps": "已导入 {} 中的 {} 个应用。", | ||||
|     "followingURLsHadErrors": "下列 URL 存在错误:", | ||||
| @@ -229,7 +229,7 @@ | ||||
|     "dontShowTrackOnlyWarnings": "不显示“仅追踪”模式警告", | ||||
|     "dontShowAPKOriginWarnings": "不显示 APK 文件来源警告", | ||||
|     "moveNonInstalledAppsToBottom": "将未安装应用置底", | ||||
|     "gitlabPATLabel": "GitLab 个人访问令牌\n(用于搜索应用 and Better APK Discovery)", | ||||
|     "gitlabPATLabel": "GitLab 个人访问令牌\n(启用搜索功能并增强 APK 发现)", | ||||
|     "about": "相关文档", | ||||
|     "requiresCredentialsInSettings": "此功能需要额外的凭据(在“设置”中添加)", | ||||
|     "checkOnStart": "启动时进行一次检查", | ||||
| @@ -240,10 +240,13 @@ | ||||
|     "disablePageTransitions": "禁用页面过渡动画效果", | ||||
|     "reversePageTransitions": "反转页面过渡动画效果", | ||||
|     "minStarCount": "最小星标数", | ||||
|     "addInfoBelow": "Add this info below.", | ||||
|     "addInfoInSettings": "Add this info in the Settings.", | ||||
|     "githubSourceNote": "GitHub rate limiting can be avoided using an API key.", | ||||
|     "gitlabSourceNote": "GitLab APK extraction may not work without an API key.", | ||||
|     "addInfoBelow": "在下方添加此凭据。", | ||||
|     "addInfoInSettings": "在“设置”中添加此凭据。", | ||||
|     "githubSourceNote": "使用访问令牌可避免触发 GitHub 的 API 请求限制。", | ||||
|     "gitlabSourceNote": "未使用访问令牌时可能无法从 GitLab 获取 APK 文件。", | ||||
|     "sortByFileNamesNotLinks": "根据文件名而不是完整链接来排序", | ||||
|     "filterReleaseNotesByRegEx": "用正则表达式筛选发布说明", | ||||
|     "customLinkFilterRegex": "用正则表达式自定义链接筛选(默认 '.apk$')", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "是否删除应用?", | ||||
|         "other": "是否删除应用?" | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -9,26 +7,8 @@ class Codeberg extends AppSource { | ||||
|   Codeberg() { | ||||
|     host = 'codeberg.org'; | ||||
|  | ||||
|     additionalSourceAppSpecificSettingFormItems = [ | ||||
|       [ | ||||
|         GeneratedFormSwitch('includePrereleases', | ||||
|             label: tr('includePrereleases'), defaultValue: false) | ||||
|       ], | ||||
|       [ | ||||
|         GeneratedFormSwitch('fallbackToOlderReleases', | ||||
|             label: tr('fallbackToOlderReleases'), defaultValue: true) | ||||
|       ], | ||||
|       [ | ||||
|         GeneratedFormTextField('filterReleaseTitlesByRegEx', | ||||
|             label: tr('filterReleaseTitlesByRegEx'), | ||||
|             required: false, | ||||
|             additionalValidators: [ | ||||
|               (value) { | ||||
|                 return regExValidator(value); | ||||
|               } | ||||
|             ]) | ||||
|       ] | ||||
|     ]; | ||||
|     additionalSourceAppSpecificSettingFormItems = | ||||
|         gh.additionalSourceAppSpecificSettingFormItems; | ||||
|  | ||||
|     canSearch = true; | ||||
|     searchQuerySettingFormItems = gh.searchQuerySettingFormItems; | ||||
|   | ||||
| @@ -75,6 +75,16 @@ class GitHub extends AppSource { | ||||
|                 return regExValidator(value); | ||||
|               } | ||||
|             ]) | ||||
|       ], | ||||
|       [ | ||||
|         GeneratedFormTextField('filterReleaseNotesByRegEx', | ||||
|             label: tr('filterReleaseNotesByRegEx'), | ||||
|             required: false, | ||||
|             additionalValidators: [ | ||||
|               (value) { | ||||
|                 return regExValidator(value); | ||||
|               } | ||||
|             ]) | ||||
|       ] | ||||
|     ]; | ||||
|  | ||||
| @@ -196,6 +206,12 @@ class GitHub extends AppSource { | ||||
|                 true | ||||
|             ? additionalSettings['filterReleaseTitlesByRegEx'] | ||||
|             : null; | ||||
|     String? regexNotesFilter = | ||||
|         (additionalSettings['filterReleaseNotesByRegEx'] as String?) | ||||
|                     ?.isNotEmpty == | ||||
|                 true | ||||
|             ? additionalSettings['filterReleaseNotesByRegEx'] | ||||
|             : null; | ||||
|     Response res = await sourceRequest(requestUrl); | ||||
|     if (res.statusCode == 200) { | ||||
|       var releases = jsonDecode(res.body) as List<dynamic>; | ||||
| @@ -264,6 +280,11 @@ class GitHub extends AppSource { | ||||
|             !RegExp(regexFilter).hasMatch(nameToFilter.trim())) { | ||||
|           continue; | ||||
|         } | ||||
|         if (regexNotesFilter != null && | ||||
|             !RegExp(regexNotesFilter) | ||||
|                 .hasMatch(((releases[i]['body'] as String?) ?? '').trim())) { | ||||
|           continue; | ||||
|         } | ||||
|         var apkUrls = getReleaseAPKUrls(releases[i]); | ||||
|         if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) { | ||||
|           continue; | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -85,11 +86,31 @@ bool _isNumeric(String s) { | ||||
| } | ||||
|  | ||||
| class HTML extends AppSource { | ||||
|   HTML() { | ||||
|     additionalSourceAppSpecificSettingFormItems = [ | ||||
|       [ | ||||
|         GeneratedFormSwitch('sortByFileNamesNotLinks', | ||||
|             label: tr('sortByFileNamesNotLinks')) | ||||
|       ], | ||||
|       [ | ||||
|         GeneratedFormTextField('customLinkFilterRegex', | ||||
|             label: tr('customLinkFilterRegex'), | ||||
|             hint: 'download/(.*/)?(android|apk|mobile)', | ||||
|             required: false, | ||||
|             additionalValidators: [ | ||||
|               (value) { | ||||
|                 return regExValidator(value); | ||||
|               } | ||||
|             ]) | ||||
|       ], | ||||
|     ]; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   // TODO: implement requestHeaders choice, hardcoded for now | ||||
|   Map<String, String>? get requestHeaders => { | ||||
|         "User-Agent": | ||||
|             "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0" | ||||
|             "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36" | ||||
|       }; | ||||
|  | ||||
|   @override | ||||
| @@ -105,14 +126,29 @@ class HTML extends AppSource { | ||||
|     var uri = Uri.parse(standardUrl); | ||||
|     Response res = await sourceRequest(standardUrl); | ||||
|     if (res.statusCode == 200) { | ||||
|       List<String> links = parse(res.body) | ||||
|       var html = parse(res.body); | ||||
|       List<String> allLinks = html | ||||
|           .querySelectorAll('a') | ||||
|           .map((element) => element.attributes['href'] ?? '') | ||||
|           .where((element) => | ||||
|               Uri.parse(element).path.toLowerCase().endsWith('.apk')) | ||||
|           .toList(); | ||||
|       links.sort((a, b) => compareAlphaNumeric(a, b)); | ||||
|       if (additionalSettings['apkFilterRegEx'] != null) { | ||||
|       List<String> links = []; | ||||
|       if ((additionalSettings['customLinkFilterRegex'] as String?) | ||||
|               ?.isNotEmpty == | ||||
|           true) { | ||||
|         var reg = RegExp(additionalSettings['customLinkFilterRegex']); | ||||
|         links = allLinks.where((element) => reg.hasMatch(element)).toList(); | ||||
|       } else { | ||||
|         links = allLinks | ||||
|             .where((element) => | ||||
|                 Uri.parse(element).path.toLowerCase().endsWith('.apk')) | ||||
|             .toList(); | ||||
|       } | ||||
|       links.sort((a, b) => additionalSettings['sortByFileNamesNotLinks'] == true | ||||
|           ? compareAlphaNumeric(a.split('/').where((e) => e.isNotEmpty).last, | ||||
|               b.split('/').where((e) => e.isNotEmpty).last) | ||||
|           : compareAlphaNumeric(a, b)); | ||||
|       if ((additionalSettings['apkFilterRegEx'] as String?)?.isNotEmpty == | ||||
|           true) { | ||||
|         var reg = RegExp(additionalSettings['apkFilterRegEx']); | ||||
|         links = links.where((element) => reg.hasMatch(element)).toList(); | ||||
|       } | ||||
|   | ||||
							
								
								
									
										90
									
								
								lib/app_sources/huaweiappgallery.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								lib/app_sources/huaweiappgallery.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| class HuaweiAppGallery extends AppSource { | ||||
|   HuaweiAppGallery() { | ||||
|     name = 'Huawei AppGallery'; | ||||
|     host = 'appgallery.huawei.com'; | ||||
|     overrideVersionDetectionFormDefault('releaseDateAsVersion', true); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String sourceSpecificStandardizeURL(String url) { | ||||
|     RegExp standardUrlRegEx = RegExp('^https?://$host/app/[^/]+'); | ||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||
|     if (match == null) { | ||||
|       throw InvalidURLError(name); | ||||
|     } | ||||
|     return url.substring(0, match.end); | ||||
|   } | ||||
|  | ||||
|   getDlUrl(String standardUrl) => | ||||
|       'https://${host!.replaceAll('appgallery.', 'appgallery.cloud.')}/appdl/${standardUrl.split('/').last}'; | ||||
|  | ||||
|   requestAppdlRedirect(String dlUrl) async { | ||||
|     Response res = await sourceRequest(dlUrl, followRedirects: false); | ||||
|     if (res.statusCode == 200 || | ||||
|         res.statusCode == 302 || | ||||
|         res.statusCode == 304) { | ||||
|       return res; | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   appIdFromRedirectDlUrl(String redirectDlUrl) { | ||||
|     var parts = redirectDlUrl | ||||
|         .split('?')[0] | ||||
|         .split('/') | ||||
|         .last | ||||
|         .split('.') | ||||
|         .reversed | ||||
|         .toList(); | ||||
|     parts.removeAt(0); | ||||
|     parts.removeAt(0); | ||||
|     return parts.reversed.join('.'); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<String?> tryInferringAppId(String standardUrl, | ||||
|       {Map<String, dynamic> additionalSettings = const {}}) async { | ||||
|     String dlUrl = getDlUrl(standardUrl); | ||||
|     Response res = await requestAppdlRedirect(dlUrl); | ||||
|     return res.headers['location'] != null | ||||
|         ? appIdFromRedirectDlUrl(res.headers['location']!) | ||||
|         : null; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<APKDetails> getLatestAPKDetails( | ||||
|     String standardUrl, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     String dlUrl = getDlUrl(standardUrl); | ||||
|     Response res = await requestAppdlRedirect(dlUrl); | ||||
|     if (res.headers['location'] == null) { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
|     String appId = appIdFromRedirectDlUrl(res.headers['location']!); | ||||
|     var relDateStr = | ||||
|         res.headers['location']?.split('?')[0].split('.').reversed.toList()[1]; | ||||
|     var relDateStrAdj = relDateStr?.split(''); | ||||
|     var tempLen = relDateStrAdj?.length ?? 0; | ||||
|     var i = 2; | ||||
|     while (i < tempLen) { | ||||
|       relDateStrAdj?.insert((i + i ~/ 2 - 1), '-'); | ||||
|       i += 2; | ||||
|     } | ||||
|     var relDate = relDateStrAdj == null | ||||
|         ? null | ||||
|         : DateFormat('yy-MM-dd-HH-mm').parse(relDateStrAdj.join('')); | ||||
|     if (relDateStr == null) { | ||||
|       throw NoVersionError(); | ||||
|     } | ||||
|     return APKDetails( | ||||
|         relDateStr, [MapEntry('$appId.apk', dlUrl)], AppNames(name, appId), | ||||
|         releaseDate: relDate); | ||||
|   } | ||||
| } | ||||
| @@ -1,5 +1,6 @@ | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/html.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -7,54 +8,73 @@ class VLC extends AppSource { | ||||
|   VLC() { | ||||
|     host = 'videolan.org'; | ||||
|   } | ||||
|   get dwUrlBase => 'https://get.$host/vlc-android/'; | ||||
|  | ||||
|   @override | ||||
|   Map<String, String>? get requestHeaders => HTML().requestHeaders; | ||||
|  | ||||
|   @override | ||||
|   String sourceSpecificStandardizeURL(String url) { | ||||
|     return 'https://$host'; | ||||
|   } | ||||
|  | ||||
|   Future<String?> getLatestVersion(String standardUrl) async { | ||||
|     Response res = await sourceRequest(dwUrlBase); | ||||
|     if (res.statusCode == 200) { | ||||
|       var dwLinks = parse(res.body) | ||||
|           .querySelectorAll('a') | ||||
|           .where((element) => element.attributes['href'] != 'last/') | ||||
|           .map((e) => e.attributes['href']?.split('/')[0]) | ||||
|           .toList(); | ||||
|       String? version = dwLinks.isNotEmpty ? dwLinks.last : null; | ||||
|       if (version == null) { | ||||
|         throw NoVersionError(); | ||||
|       } | ||||
|       return version; | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<APKDetails> getLatestAPKDetails( | ||||
|     String standardUrl, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     Response res = await sourceRequest( | ||||
|         'https://www.videolan.org/vlc/download-android.html'); | ||||
|     String? version = await getLatestVersion(standardUrl); | ||||
|     if (version == null) { | ||||
|       throw NoVersionError(); | ||||
|     } | ||||
|     String? targetUrl = '$dwUrlBase$version/'; | ||||
|     Response res = await sourceRequest(targetUrl); | ||||
|     List<String> apkUrls = []; | ||||
|     if (res.statusCode == 200) { | ||||
|       var dwUrlBase = 'get.videolan.org/vlc-android'; | ||||
|       var dwLinks = parse(res.body) | ||||
|       apkUrls = parse(res.body) | ||||
|           .querySelectorAll('a') | ||||
|           .where((element) => | ||||
|               element.attributes['href']?.contains(dwUrlBase) ?? false) | ||||
|           .map((e) => e.attributes['href']?.split('/').last) | ||||
|           .where((h) => | ||||
|               h != null && h.isNotEmpty && h.toLowerCase().endsWith('.apk')) | ||||
|           .map((e) => targetUrl + e!) | ||||
|           .toList(); | ||||
|       String? version = dwLinks.isNotEmpty | ||||
|           ? dwLinks.first.attributes['href'] | ||||
|               ?.split('/') | ||||
|               .where((s) => s.isNotEmpty) | ||||
|               .last | ||||
|           : null; | ||||
|       if (version == null) { | ||||
|         throw NoVersionError(); | ||||
|       } | ||||
|       String? targetUrl = 'https://$dwUrlBase/$version/'; | ||||
|       Response res2 = await sourceRequest(targetUrl); | ||||
|       String mirrorDwBase = | ||||
|           'https://plug-mirror.rcac.purdue.edu/vlc/vlc-android/$version/'; | ||||
|       List<String> apkUrls = []; | ||||
|       if (res2.statusCode == 200) { | ||||
|         apkUrls = parse(res2.body) | ||||
|             .querySelectorAll('a') | ||||
|             .map((e) => e.attributes['href']) | ||||
|             .where((h) => | ||||
|                 h != null && h.isNotEmpty && h.toLowerCase().endsWith('.apk')) | ||||
|             .map((e) => mirrorDwBase + e!) | ||||
|             .toList(); | ||||
|       } else { | ||||
|         throw getObtainiumHttpError(res2); | ||||
|       } | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|  | ||||
|       return APKDetails( | ||||
|           version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC')); | ||||
|     return APKDetails( | ||||
|         version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC')); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<String> apkUrlPrefetchModifier( | ||||
|       String apkUrl, String standardUrl) async { | ||||
|     Response res = await sourceRequest(apkUrl); | ||||
|     if (res.statusCode == 200) { | ||||
|       String? apkUrl = | ||||
|           parse(res.body).querySelector('#alt_link')?.attributes['href']; | ||||
|       if (apkUrl == null) { | ||||
|         throw NoAPKError(); | ||||
|       } | ||||
|       return apkUrl; | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   | ||||
| @@ -11,7 +11,8 @@ class GeneratedFormModal extends StatefulWidget { | ||||
|       this.initValid = false, | ||||
|       this.message = '', | ||||
|       this.additionalWidgets = const [], | ||||
|       this.singleNullReturnButton}); | ||||
|       this.singleNullReturnButton, | ||||
|       this.primaryActionColour}); | ||||
|  | ||||
|   final String title; | ||||
|   final String message; | ||||
| @@ -19,6 +20,7 @@ class GeneratedFormModal extends StatefulWidget { | ||||
|   final bool initValid; | ||||
|   final List<Widget> additionalWidgets; | ||||
|   final String? singleNullReturnButton; | ||||
|   final Color? primaryActionColour; | ||||
|  | ||||
|   @override | ||||
|   State<GeneratedFormModal> createState() => _GeneratedFormModalState(); | ||||
| @@ -71,6 +73,10 @@ class _GeneratedFormModalState extends State<GeneratedFormModal> { | ||||
|                 : widget.singleNullReturnButton!)), | ||||
|         widget.singleNullReturnButton == null | ||||
|             ? TextButton( | ||||
|                 style: widget.primaryActionColour == null | ||||
|                     ? null | ||||
|                     : TextButton.styleFrom( | ||||
|                         foregroundColor: widget.primaryActionColour), | ||||
|                 onPressed: !valid | ||||
|                     ? null | ||||
|                     : () { | ||||
|   | ||||
| @@ -22,7 +22,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; | ||||
| // ignore: implementation_imports | ||||
| import 'package:easy_localization/src/localization.dart'; | ||||
|  | ||||
| const String currentVersion = '0.13.22'; | ||||
| const String currentVersion = '0.13.26'; | ||||
| const String currentReleaseTag = | ||||
|     'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES | ||||
|  | ||||
| @@ -299,7 +299,9 @@ class _ObtainiumState extends State<Obtainium> { | ||||
|                   ? lightColorScheme | ||||
|                   : darkColorScheme, | ||||
|               fontFamily: 'Metropolis'), | ||||
|           home: const HomePage()); | ||||
|           home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{ | ||||
|             LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), | ||||
|           }, child: const HomePage())); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -643,15 +643,15 @@ class AppsPageState extends State<AppsPage> { | ||||
|                     label: tr('installX', args: [ | ||||
|                       plural('apps', newInstallIdsAllOrSelected.length) | ||||
|                     ]), | ||||
|                     defaultValue: existingUpdateIdsAllOrSelected.isNotEmpty)); | ||||
|                     defaultValue: existingUpdateIdsAllOrSelected.isEmpty)); | ||||
|               } | ||||
|               if (trackOnlyUpdateIdsAllOrSelected.isNotEmpty) { | ||||
|                 formItems.add(GeneratedFormSwitch('trackonlies', | ||||
|                     label: tr('markXTrackOnlyAsUpdated', args: [ | ||||
|                       plural('apps', trackOnlyUpdateIdsAllOrSelected.length) | ||||
|                     ]), | ||||
|                     defaultValue: existingUpdateIdsAllOrSelected.isNotEmpty || | ||||
|                         newInstallIdsAllOrSelected.isNotEmpty)); | ||||
|                     defaultValue: existingUpdateIdsAllOrSelected.isEmpty && | ||||
|                         newInstallIdsAllOrSelected.isEmpty)); | ||||
|               } | ||||
|               showDialog<Map<String, dynamic>?>( | ||||
|                   context: context, | ||||
|   | ||||
| @@ -403,10 +403,13 @@ class _SettingsPageState extends State<SettingsPage> { | ||||
|                                 Switch( | ||||
|                                     value: | ||||
|                                         settingsProvider.reversePageTransitions, | ||||
|                                     onChanged: (value) { | ||||
|                                       settingsProvider.reversePageTransitions = | ||||
|                                           value; | ||||
|                                     }) | ||||
|                                     onChanged: settingsProvider | ||||
|                                             .disablePageTransitions | ||||
|                                         ? null | ||||
|                                         : (value) { | ||||
|                                             settingsProvider | ||||
|                                                 .reversePageTransitions = value; | ||||
|                                           }) | ||||
|                               ], | ||||
|                             ), | ||||
|                             height32, | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import 'dart:io'; | ||||
|  | ||||
| import 'package:android_intent_plus/flag.dart'; | ||||
| import 'package:android_package_installer/android_package_installer.dart'; | ||||
| import 'package:android_package_manager/android_package_manager.dart'; | ||||
| import 'package:device_info_plus/device_info_plus.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| @@ -29,6 +30,8 @@ import 'package:http/http.dart'; | ||||
| import 'package:android_intent_plus/android_intent.dart'; | ||||
| import 'package:flutter_archive/flutter_archive.dart'; | ||||
|  | ||||
| final pm = AndroidPackageManager(); | ||||
|  | ||||
| class AppInMemory { | ||||
|   late App app; | ||||
|   double? downloadProgress; | ||||
| @@ -322,16 +325,39 @@ class AppsProvider with ChangeNotifier { | ||||
|       .isNotEmpty; | ||||
|  | ||||
|   Future<bool> canInstallSilently(App app) async { | ||||
|     return false; | ||||
|     // TODO: Uncomment the below if silent updates are ever figured out | ||||
|     // // NOTE: This is unreliable - try to get from OS in the future | ||||
|     // if (app.apkUrls.length > 1) { | ||||
|     //    return false; | ||||
|     // } | ||||
|     // var osInfo = await DeviceInfoPlugin().androidInfo; | ||||
|     // return app.installedVersion != null && | ||||
|     //     osInfo.version.sdkInt >= 30 && | ||||
|     //     osInfo.version.release.compareTo('12') >= 0; | ||||
|     if (app.apkUrls.length > 1) { | ||||
|       // Manual API selection means silent install is not possible | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     var osInfo = await DeviceInfoPlugin().androidInfo; | ||||
|     String? installerPackageName; | ||||
|     try { | ||||
|       installerPackageName = osInfo.version.sdkInt >= 30 | ||||
|           ? (await pm.getInstallSourceInfo(packageName: app.id)) | ||||
|               ?.installingPackageName | ||||
|           : (await pm.getInstallerPackageName(packageName: app.id)); | ||||
|     } catch (e) { | ||||
|       // Probably not installed - ignore | ||||
|     } | ||||
|     if (installerPackageName != obtainiumId) { | ||||
|       // If we did not install the app (or it isn't installed), silent install is not possible | ||||
|       return false; | ||||
|     } | ||||
|     int? targetSDK; | ||||
|     try { | ||||
|       targetSDK = (await pm.getPackageInfo(packageName: app.id)) | ||||
|           ?.applicationInfo | ||||
|           ?.targetSdkVersion; | ||||
|     } catch (e) { | ||||
|       // Weird if you get here - ignore | ||||
|     } | ||||
|  | ||||
|     // The OS must also be new enough and the APK should target a new enough API | ||||
|     return osInfo.version.sdkInt >= 30 && | ||||
|         targetSDK != null && | ||||
|         targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) | ||||
|             (osInfo.version.sdkInt - 3); | ||||
|   } | ||||
|  | ||||
|   Future<void> waitForUserToReturnToForeground(BuildContext context) async { | ||||
| @@ -359,26 +385,24 @@ class AppsProvider with ChangeNotifier { | ||||
|         zipFile: File(filePath), destinationDir: Directory(destinationPath)); | ||||
|   } | ||||
|  | ||||
|   Future<void> installXApkDir(DownloadedXApkDir dir, | ||||
|       {bool silent = false}) async { | ||||
|   Future<void> installXApkDir(DownloadedXApkDir dir) async { | ||||
|     // We don't know which APKs in an XAPK are supported by the user's device | ||||
|     // So we try installing all of them and assume success if at least one installed | ||||
|     // If 0 APKs installed, throw the first install error encountered | ||||
|     try { | ||||
|       var somethingInstalled = false; | ||||
|       Object? firstError; | ||||
|       MultiAppMultiError errors = MultiAppMultiError(); | ||||
|       for (var file in dir.extracted | ||||
|           .listSync(recursive: true, followLinks: false) | ||||
|           .whereType<File>()) { | ||||
|         if (file.path.toLowerCase().endsWith('.apk')) { | ||||
|           try { | ||||
|             somethingInstalled = somethingInstalled || | ||||
|                 await installApk(DownloadedApk(dir.appId, file), | ||||
|                     silent: silent); | ||||
|                 await installApk(DownloadedApk(dir.appId, file)); | ||||
|           } catch (e) { | ||||
|             logs.add( | ||||
|                 'Could not install APK from XAPK \'${file.path}\': ${e.toString()}'); | ||||
|             firstError ??= e; | ||||
|             errors.add(dir.appId, e.toString()); | ||||
|           } | ||||
|         } else if (file.path.toLowerCase().endsWith('.obb')) { | ||||
|           await moveObbFile(file, dir.appId); | ||||
| @@ -386,16 +410,15 @@ class AppsProvider with ChangeNotifier { | ||||
|       } | ||||
|       if (somethingInstalled) { | ||||
|         dir.file.delete(recursive: true); | ||||
|       } else if (firstError != null) { | ||||
|         throw firstError; | ||||
|       } else if (errors.content.isNotEmpty) { | ||||
|         throw errors; | ||||
|       } | ||||
|     } finally { | ||||
|       dir.extracted.delete(recursive: true); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Future<bool> installApk(DownloadedApk file, {bool silent = false}) async { | ||||
|     // TODO: Use 'silent' when/if ever possible | ||||
|   Future<bool> installApk(DownloadedApk file) async { | ||||
|     var newInfo = await PackageArchiveInfo.fromPath(file.file.path); | ||||
|     AppInfo? appInfo; | ||||
|     try { | ||||
| @@ -571,7 +594,6 @@ class AppsProvider with ChangeNotifier { | ||||
|         } | ||||
|         bool willBeSilent = await canInstallSilently( | ||||
|             apps[downloadedFile?.appId ?? downloadedDir!.appId]!.app); | ||||
|         willBeSilent = false; // TODO: Remove this when silent updates work | ||||
|         if (!(await settingsProvider?.getInstallPermission(enforce: false) ?? | ||||
|             true)) { | ||||
|           throw ObtainiumError(tr('cancelled')); | ||||
| @@ -584,9 +606,9 @@ class AppsProvider with ChangeNotifier { | ||||
|         notifyListeners(); | ||||
|         try { | ||||
|           if (downloadedFile != null) { | ||||
|             await installApk(downloadedFile, silent: willBeSilent); | ||||
|             await installApk(downloadedFile); | ||||
|           } else { | ||||
|             await installXApkDir(downloadedDir!, silent: willBeSilent); | ||||
|             await installXApkDir(downloadedDir!); | ||||
|           } | ||||
|         } finally { | ||||
|           apps[id]?.downloadProgress = null; | ||||
| @@ -892,6 +914,7 @@ class AppsProvider with ChangeNotifier { | ||||
|         context: context, | ||||
|         builder: (BuildContext ctx) { | ||||
|           return GeneratedFormModal( | ||||
|             primaryActionColour: Theme.of(context).colorScheme.error, | ||||
|             title: plural('removeAppQuestion', apps.length), | ||||
|             items: !showUninstallOption | ||||
|                 ? [] | ||||
|   | ||||
| @@ -14,6 +14,7 @@ import 'package:obtainium/app_sources/fdroid.dart'; | ||||
| import 'package:obtainium/app_sources/fdroidrepo.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/app_sources/gitlab.dart'; | ||||
| import 'package:obtainium/app_sources/huaweiappgallery.dart'; | ||||
| import 'package:obtainium/app_sources/izzyondroid.dart'; | ||||
| import 'package:obtainium/app_sources/html.dart'; | ||||
| import 'package:obtainium/app_sources/jenkins.dart'; | ||||
| @@ -355,10 +356,14 @@ abstract class AppSource { | ||||
|  | ||||
|   Map<String, String>? get requestHeaders => null; | ||||
|  | ||||
|   Future<Response> sourceRequest(String url) async { | ||||
|     if (requestHeaders != null) { | ||||
|   Future<Response> sourceRequest(String url, | ||||
|       {bool followRedirects = true}) async { | ||||
|     if (requestHeaders != null || followRedirects == false) { | ||||
|       var req = Request('GET', Uri.parse(url)); | ||||
|       req.headers.addAll(requestHeaders!); | ||||
|       req.followRedirects = followRedirects; | ||||
|       if (requestHeaders != null) { | ||||
|         req.headers.addAll(requestHeaders!); | ||||
|       } | ||||
|       return Response.fromStream(await Client().send(req)); | ||||
|     } else { | ||||
|       return get(Uri.parse(url)); | ||||
| @@ -431,14 +436,14 @@ abstract class AppSource { | ||||
|       Map<String, dynamic> additionalSettings, | ||||
|       SettingsProvider settingsProvider) async { | ||||
|     Map<String, String> results = {}; | ||||
|     sourceConfigSettingFormItems.forEach((e) { | ||||
|     for (var e in sourceConfigSettingFormItems) { | ||||
|       var val = hostChanged | ||||
|           ? additionalSettings[e.key] | ||||
|           : settingsProvider.getSettingString(e.key); | ||||
|       if (val != null) { | ||||
|         results[e.key] = val; | ||||
|       } | ||||
|     }); | ||||
|     } | ||||
|     return results; | ||||
|   } | ||||
|  | ||||
| @@ -508,6 +513,7 @@ class SourceProvider { | ||||
|         SourceHut(), | ||||
|         APKMirror(), | ||||
|         APKPure(), | ||||
|         HuaweiAppGallery(), | ||||
|         // APKCombo(), // Can't get past their scraping blocking yet (get 403 Forbidden) | ||||
|         Mullvad(), | ||||
|         Signal(), | ||||
|   | ||||
							
								
								
									
										91
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -5,27 +5,36 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: android_alarm_manager_plus | ||||
|       sha256: "80f963d47cb7ab0818144c7b0668aea4c038f9cb8626626e89a4ea77375defb7" | ||||
|       sha256: c20d91a9096596f66274bf8172321c278f9cba8091638f80205fe66d31587fa5 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.0.1" | ||||
|     version: "3.0.2" | ||||
|   android_intent_plus: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: android_intent_plus | ||||
|       sha256: "2c87d8330ba5deef5fe20e77f4d178190b3b24531dce08368030ab4be40a9d4e" | ||||
|       sha256: f72ae20bb37108694f442e7ae6acbd28b453ca62ce86842f6787b784355abfe6 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.0.1" | ||||
|     version: "4.0.2" | ||||
|   android_package_installer: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       path: "." | ||||
|       ref: main | ||||
|       resolved-ref: f09c79eee5be3c60b04760143eb954a13fdd07f1 | ||||
|       resolved-ref: ba2aa7a11edc2649d1d80c25ed9291521262f714 | ||||
|       url: "https://github.com/ImranR98/android_package_installer" | ||||
|     source: git | ||||
|     version: "0.0.1" | ||||
|   android_package_manager: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       path: "." | ||||
|       ref: master | ||||
|       resolved-ref: "6e68991ef9c6232695abce2eef345d3cca2f52ac" | ||||
|       url: "https://github.com/ImranR98/android_package_manager" | ||||
|     source: git | ||||
|     version: "0.5.4" | ||||
|   animations: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -158,10 +167,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: device_info_plus | ||||
|       sha256: "2c35b6d1682b028e42d07b3aee4b98fa62996c10bc12cb651ec856a80d6a761b" | ||||
|       sha256: "86add5ef97215562d2e090535b0a16f197902b10c369c558a100e74ea06e8659" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "9.0.2" | ||||
|     version: "9.0.3" | ||||
|   device_info_plus_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -206,10 +215,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: ffi | ||||
|       sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 | ||||
|       sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.2" | ||||
|     version: "2.1.0" | ||||
|   file: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -296,10 +305,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_markdown | ||||
|       sha256: "4b1bfbb802d76320a1a46d9ce984106135093efd9d969765d07c2125af107bdf" | ||||
|       sha256: "2b206d397dd7836ea60035b2d43825c8a303a76a5098e66f42d55a753e18d431" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.6.17" | ||||
|     version: "0.6.17+1" | ||||
|   flutter_plugin_android_lifecycle: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -482,50 +491,50 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: path_provider | ||||
|       sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" | ||||
|       sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.15" | ||||
|     version: "2.1.0" | ||||
|   path_provider_android: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_android | ||||
|       sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" | ||||
|       sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.27" | ||||
|     version: "2.1.0" | ||||
|   path_provider_foundation: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_foundation | ||||
|       sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" | ||||
|       sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.2.4" | ||||
|     version: "2.3.0" | ||||
|   path_provider_linux: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_linux | ||||
|       sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 | ||||
|       sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.1.11" | ||||
|     version: "2.2.0" | ||||
|   path_provider_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_platform_interface | ||||
|       sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" | ||||
|       sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.6" | ||||
|     version: "2.1.0" | ||||
|   path_provider_windows: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_windows | ||||
|       sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" | ||||
|       sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.1.7" | ||||
|     version: "2.2.0" | ||||
|   permission_handler: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -578,10 +587,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: platform | ||||
|       sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" | ||||
|       sha256: "57c07bf82207aee366dfaa3867b3164e4f03a238a461a11b0e8a3a510d51203d" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.1.0" | ||||
|     version: "3.1.1" | ||||
|   plugin_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -610,18 +619,18 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: share_plus | ||||
|       sha256: ed3fcea4f789ed95913328e629c0c53e69e80e08b6c24542f1b3576046c614e8 | ||||
|       sha256: "6cec740fa0943a826951223e76218df002804adb588235a8910dc3d6b0654e11" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "7.0.2" | ||||
|     version: "7.1.0" | ||||
|   share_plus_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: share_plus_platform_interface | ||||
|       sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981" | ||||
|       sha256: "357412af4178d8e11d14f41723f80f12caea54cf0d5cd29af9dcdab85d58aea7" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.2.1" | ||||
|     version: "3.3.0" | ||||
|   shared_preferences: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -642,10 +651,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: shared_preferences_foundation | ||||
|       sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 | ||||
|       sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.2" | ||||
|     version: "2.3.3" | ||||
|   shared_preferences_linux: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -783,10 +792,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_android | ||||
|       sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" | ||||
|       sha256: "3dd2388cc0c42912eee04434531a26a82512b9cb1827e0214430c9bcbddfe025" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.0.37" | ||||
|     version: "6.0.38" | ||||
|   url_launcher_ios: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -863,26 +872,26 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: webview_flutter_android | ||||
|       sha256: d936a09fbfd08cb78f7329e0bbacf6158fbdfe24ffc908b22444c07d295eb193 | ||||
|       sha256: bca797abba472868655b5f1a6029c1132385685ee9db4713cb0e7f33076210c6 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.9.2" | ||||
|     version: "3.9.3" | ||||
|   webview_flutter_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: webview_flutter_platform_interface | ||||
|       sha256: "564ef378cafc1a0e29f1d76ce175ef517a0a6115875dff7b43fccbef2b0aeb30" | ||||
|       sha256: "0ca3cfcc6781a7de701d580917af4a9efc4e3e129f8ead95a80587f0a749480a" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.4.0" | ||||
|     version: "2.5.0" | ||||
|   webview_flutter_wkwebview: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: webview_flutter_wkwebview | ||||
|       sha256: "5fa098f28b606f699e8ca52d9e4e11edbbfef65189f5f77ae92703ba5408fd25" | ||||
|       sha256: ed749f94ac9e814d04a258a9255cf69cfa4cc6006ff59542aea7fb4590144972 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.7.2" | ||||
|     version: "3.7.3" | ||||
|   win32: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -903,10 +912,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: xdg_directories | ||||
|       sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff | ||||
|       sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.1" | ||||
|     version: "1.0.2" | ||||
|   xml: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
							
								
								
									
										12
									
								
								pubspec.yaml
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								pubspec.yaml
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| name: obtainium | ||||
| description: A new Flutter project. | ||||
| description: Get Android App Updates Directly From the Source. | ||||
|  | ||||
| # The following line prevents the package from being accidentally published to | ||||
| # pub.dev using `flutter pub publish`. This is preferred for private packages. | ||||
| @@ -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.13.22+186 # When changing this, update the tag in main() accordingly | ||||
| version: 0.13.26+190 # When changing this, update the tag in main() accordingly | ||||
|  | ||||
| environment: | ||||
|   sdk: '>=2.18.2 <3.0.0' | ||||
| @@ -55,9 +55,13 @@ dependencies: | ||||
|     git: | ||||
|       url: https://github.com/ImranR98/android_package_installer | ||||
|       ref: main | ||||
|   android_package_manager: | ||||
|     git: | ||||
|         url: https://github.com/ImranR98/android_package_manager | ||||
|         ref: master | ||||
|   share_plus: ^7.0.0 | ||||
|   installed_apps: ^1.3.1 | ||||
|   package_archive_info: ^0.1.0 | ||||
|   installed_apps: ^1.3.1 # TODO: Remove when android_package_manager supports getting icon as UInt8List and versionCode | ||||
|   package_archive_info: ^0.1.0 # TODO: Remove when android_package_manager supports getting versionCode | ||||
|   android_alarm_manager_plus: ^3.0.0 | ||||
|   sqflite: ^2.2.0+3 | ||||
|   easy_localization: ^3.0.1 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user