diff --git a/.flutter b/.flutter index 35c388a..09de023 160000 --- a/.flutter +++ b/.flutter @@ -1 +1 @@ -Subproject commit 35c388afb57ef061d06a39b537336c87e0e3d1b1 +Subproject commit 09de023485e95e6d1225c2baa44b8feb85e0d45f diff --git a/assets/translations/bs.json b/assets/translations/bs.json index 3537c57..fb958ac 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Stay one version behind latest", "refreshBeforeDownload": "Refresh app details before download", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sort Method", "removeAppQuestion": { "one": "Želite li ukloniti aplikaciju?", "other": "Želite li ukloniti aplikacije?" diff --git a/assets/translations/cs.json b/assets/translations/cs.json index 8635c23..4f0c527 100644 --- a/assets/translations/cs.json +++ b/assets/translations/cs.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější", "refreshBeforeDownload": "Obnovení údajů o aplikaci před stažením", "tencentAppStore": "Tencent App Store", + "name": "Název", + "smartname": "Název (Smart)", + "sortMethod": "Metoda třídění", "removeAppQuestion": { "one": "Odstranit Apku?", "other": "Odstranit Apky?" diff --git a/assets/translations/da.json b/assets/translations/da.json index f4d625c..ca82fa6 100644 --- a/assets/translations/da.json +++ b/assets/translations/da.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Forbliv én version bagud den seneste", "refreshBeforeDownload": "Opdater app-detaljer før download", "tencentAppStore": "Tencent App Store", + "name": "Navn", + "smartname": "Navn (Smart)", + "sortMethod": "Sorteringsmetode", "removeAppQuestion": { "one": "Fjern app?", "other": "Fjern apps?" diff --git a/assets/translations/de.json b/assets/translations/de.json index f478db1..62a8ac8 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben", "refreshBeforeDownload": "App-Details vor dem Download aktualisieren", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sortierverfahren", "removeAppQuestion": { "one": "App entfernen?", "other": "Apps entfernen?" diff --git a/assets/translations/en-EO.json b/assets/translations/en-EO.json index 26eeb10..26b3b67 100644 --- a/assets/translations/en-EO.json +++ b/assets/translations/en-EO.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Stay one version behind latest", "refreshBeforeDownload": "Refresh app details before download", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sort Method", "removeAppQuestion": { "one": "Forigi la aplikaĵon?", "other": "Forigi la aplikaĵojn?" diff --git a/assets/translations/en.json b/assets/translations/en.json index d4c8689..e745dfd 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Stay one version behind latest", "refreshBeforeDownload": "Refresh app details before download", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sort Method", "removeAppQuestion": { "one": "Remove App?", "other": "Remove Apps?" diff --git a/assets/translations/es.json b/assets/translations/es.json index b0b7873..4fec5d3 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Mantenerse una versión por detrás de la última", "refreshBeforeDownload": "Actualiza los datos de la aplicación antes de descargarla", "tencentAppStore": "Tencent App Store", + "name": "Nombre", + "smartname": "Nombre (Smart)", + "sortMethod": "Método de clasificación", "removeAppQuestion": { "one": "¿Eliminar aplicación?", "other": "¿Eliminar aplicaciones?" diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 4e72fca..50fa808 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "یک نسخه از آخرین نسخه پشت سر بگذارید", "refreshBeforeDownload": "قبل از دانلود، جزئیات برنامه را بازخوانی کنید", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sort Method", "removeAppQuestion": { "one": "برنامه حذف شود؟", "other": "برنامه ها حذف شوند؟" diff --git a/assets/translations/fr.json b/assets/translations/fr.json index bb5e021..26ee458 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Rester une version en arrière de la dernière", "refreshBeforeDownload": "Actualiser les détails de l'application avant de la télécharger", "tencentAppStore": "Tencent App Store", + "name": "Nom", + "smartname": "Nom (Smart)", + "sortMethod": "Méthode de tri", "removeAppQuestion": { "one": "Supprimer l'application ?", "other": "Supprimer les applications ?" diff --git a/assets/translations/hu.json b/assets/translations/hu.json index 2bc413b..b5b8355 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Maradjon egy verzióval a legújabb mögött", "refreshBeforeDownload": "Az alkalmazás adatainak frissítése a letöltés előtt", "tencentAppStore": "Tencent Appstore", + "name": "Név", + "smartname": "Név (Smart)", + "sortMethod": "Rendezési módszer", "removeAppQuestion": { "one": "Eltávolítja az alkalmazást?", "other": "Eltávolítja az alkalmazásokat?" diff --git a/assets/translations/id.json b/assets/translations/id.json index 0356fe0..0686b17 100644 --- a/assets/translations/id.json +++ b/assets/translations/id.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru", "refreshBeforeDownload": "Segarkan detail aplikasi sebelum mengunduh", "tencentAppStore": "Tencent App Store", + "name": "Nama", + "smartname": "Nama (Cerdas)", + "sortMethod": "Metode Penyortiran", "removeAppQuestion": { "one": "Hapus aplikasi?", "other": "Hapus aplikasi?" diff --git a/assets/translations/it.json b/assets/translations/it.json index 5c7ddad..c41ac63 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente", "refreshBeforeDownload": "Aggiornare i dettagli dell'app prima del download", "tencentAppStore": "Tencent App Store", + "name": "Nome", + "smartname": "Nome (intelligente)", + "sortMethod": "Metodo di ordinamento", "removeAppQuestion": { "one": "Rimuovere l'app?", "other": "Rimuovere le app?" diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 9763ef1..3fef6a7 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "最新のバージョンから1つ前のものを使用する", "refreshBeforeDownload": "ダウンロード前にアプリの詳細を更新する", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "名前(スマート)", + "sortMethod": "ソート方法", "removeAppQuestion": { "one": "アプリを削除しますか?", "other": "アプリを削除しますか?" diff --git a/assets/translations/ko.json b/assets/translations/ko.json index de433fb..11dd4a8 100644 --- a/assets/translations/ko.json +++ b/assets/translations/ko.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "최신 버전보다 한 버전 뒤에 머무르기", "refreshBeforeDownload": "다운로드 전에 앱 세부 정보 새로 고침", "tencentAppStore": "텐센트 앱 스토어", + "name": "이름", + "smartname": "이름(스마트)", + "sortMethod": "정렬 방법", "removeAppQuestion": { "one": "앱을 제거하시겠습니까?", "other": "앱을 제거하시겠습니까?" diff --git a/assets/translations/nl.json b/assets/translations/nl.json index beef021..3393987 100644 --- a/assets/translations/nl.json +++ b/assets/translations/nl.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Blijf een versie achter op de nieuwste", "refreshBeforeDownload": "Vernieuw app details voor download", "tencentAppStore": "Tencent App Store", + "name": "Naam", + "smartname": "Naam (Slim)", + "sortMethod": "Sorteermethode", "removeAppQuestion": { "one": "App verwijderen?", "other": "Apps verwijderen?" diff --git a/assets/translations/pl.json b/assets/translations/pl.json index 7123d1a..54be7b3 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Pozostań jedną wersję w tyle za najnowszą", "refreshBeforeDownload": "Odśwież szczegóły aplikacji przed pobraniem", "tencentAppStore": "Tencent App Store", + "name": "Nazwa", + "smartname": "Nazwa (Smart)", + "sortMethod": "Metoda sortowania", "removeAppQuestion": { "one": "Usunąć aplikację?", "few": "Usunąć aplikacje?", diff --git a/assets/translations/pt.json b/assets/translations/pt.json index 717a30a..d2e07bd 100644 --- a/assets/translations/pt.json +++ b/assets/translations/pt.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Manter-se uma versão atrás da mais recente", "refreshBeforeDownload": "Atualizar os detalhes da aplicação antes da transferência", "tencentAppStore": "Tencent App Store", + "name": "Nome", + "smartname": "Nome (Smart)", + "sortMethod": "Método de ordenação", "removeAppQuestion": { "one": "Remover aplicativo?", "other": "Remover aplicativos?" diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 05b1246..4f3d70b 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Не отставайте от последней версии", "refreshBeforeDownload": "Обновляйте информацию о приложении перед загрузкой", "tencentAppStore": "Tencent App Store", + "name": "Имя", + "smartname": "Имя (умное)", + "sortMethod": "Метод сортировки", "removeAppQuestion": { "one": "Удалить приложение?", "other": "Удалить приложения?" diff --git a/assets/translations/standardize.js b/assets/translations/standardize.js index b077689..53c7a6f 100644 --- a/assets/translations/standardize.js +++ b/assets/translations/standardize.js @@ -13,7 +13,10 @@ const neverAutoTranslate = { obtainiumExportHyphenatedLowercase: ['*'], theme: ['de'], appId: ['de'], - placeholder: ['pl'] + placeholder: ['pl'], + importExport: ['fr'], + url: ['fr'], + tencentAppStore: ['*'] } const translateText = async (text, targetLang, authKey) => { @@ -76,40 +79,49 @@ const main = async () => { const translationKeys = Object.keys(templateTranslation) for (let j in translationKeys) { const k = translationKeys[j] - if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) { - const lang = file.split('/').pop().split('.')[0] - if (!neverAutoTranslate[k] || (neverAutoTranslate[k].indexOf('*') < 0 && neverAutoTranslate[k].indexOf(lang) < 0)) { - const reportLine = `${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}` - if (deeplAPIKey) { - const translateFunc = async (str) => { - const response = await translateText(str, lang, deeplAPIKey) - if (response.translations) { - return response.translations[0].text - } else { - throw JSON.stringify(response) - } - } - try { - if (typeof templateTranslation[k] == 'string') { - thisTranslation[k] = await translateFunc(thisTranslation[k]) - } else { - const subKeys = Object.keys(templateTranslation[k]) - for (let n in subKeys) { - const kk = subKeys[n] - thisTranslation[k][kk] = await translateFunc(thisTranslation[k][kk]) + try { + if (JSON.stringify(thisTranslation[k]) == JSON.stringify(templateTranslation[k])) { + const lang = file.split('/').pop().split('.')[0] + if (!neverAutoTranslate[k] || (neverAutoTranslate[k].indexOf('*') < 0 && neverAutoTranslate[k].indexOf(lang) < 0)) { + const reportLine = `${file} :::: ${k} :::: ${JSON.stringify(thisTranslation[k])}` + if (deeplAPIKey) { + const translateFunc = async (str) => { + await new Promise((resolve, reject) => { + setTimeout(() => { + resolve() + }, Math.random() * 1000); // Try to avoid rate limit + }) + const response = await translateText(str, lang, deeplAPIKey) + if (response.translations) { + return response.translations[0].text + } else { + throw JSON.stringify(response) } } - } catch (e) { - if (typeof e == 'string') { - console.log(`${reportLine} :::: ${e}`) - } else { - throw e + try { + if (typeof templateTranslation[k] == 'string') { + thisTranslation[k] = await translateFunc(thisTranslation[k]) + } else { + const subKeys = Object.keys(templateTranslation[k]) + for (let n in subKeys) { + const kk = subKeys[n] + thisTranslation[k][kk] = await translateFunc(thisTranslation[k][kk]) + } + } + } catch (e) { + if (typeof e == 'string') { + console.log(`${reportLine} :::: ${e}`) + } else { + throw e + } } + } else { + console.log(reportLine) } - } else { - console.log(reportLine) } } + } catch (err) { + console.error(err) } } fs.writeFileSync(file, `${JSON.stringify(thisTranslation, null, ' ')}\n`) diff --git a/assets/translations/sv.json b/assets/translations/sv.json index e56cbed..08a3ecd 100644 --- a/assets/translations/sv.json +++ b/assets/translations/sv.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Håll dig en version bakom den senaste", "refreshBeforeDownload": "Uppdatera appdetaljerna före nedladdning", "tencentAppStore": "Tencent App Store", + "name": "Namn", + "smartname": "Namn (Smart)", + "sortMethod": "Sorteringsmetod", "removeAppQuestion": { "one": "Ta Bort App?", "other": "Ta Bort Appar?" diff --git a/assets/translations/tr.json b/assets/translations/tr.json index d62875c..9873950 100644 --- a/assets/translations/tr.json +++ b/assets/translations/tr.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın", "refreshBeforeDownload": "İndirmeden önce uygulama ayrıntılarını yenileyin", "tencentAppStore": "Tencent App Store", + "name": "İsim", + "smartname": "İsim (Akıllı)", + "sortMethod": "Sıralama Yöntemi", "removeAppQuestion": { "one": "Uygulamayı Kaldır?", "other": "Uygulamaları Kaldır?" diff --git a/assets/translations/uk.json b/assets/translations/uk.json index 0cb6d3a..de5843e 100644 --- a/assets/translations/uk.json +++ b/assets/translations/uk.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою", "refreshBeforeDownload": "Оновіть інформацію про програму перед завантаженням", "tencentAppStore": "Tencent App Store", + "name": "Ім'я", + "smartname": "Ім'я (Smart)", + "sortMethod": "Метод сортування", "removeAppQuestion": { "one": "Видалити застосунок?", "other": "Видалити застосунки?" diff --git a/assets/translations/vi.json b/assets/translations/vi.json index 495a7b9..c871e17 100644 --- a/assets/translations/vi.json +++ b/assets/translations/vi.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Stay one version behind latest", "refreshBeforeDownload": "Refresh app details before download", "tencentAppStore": "Tencent App Store", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sort Method", "removeAppQuestion": { "one": "Gỡ ứng dụng?", "other": "Gỡ ứng dụng?" diff --git a/assets/translations/zh-Hant-TW.json b/assets/translations/zh-Hant-TW.json index b1f6983..1b635c5 100644 --- a/assets/translations/zh-Hant-TW.json +++ b/assets/translations/zh-Hant-TW.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "Stay one version behind latest", "refreshBeforeDownload": "Refresh app details before download", "tencentAppStore": "騰訊應用寶", + "name": "Name", + "smartname": "Name (Smart)", + "sortMethod": "Sort Method", "removeAppQuestion": { "one": "移除應用程式?", "other": "移除應用程式?" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index f115f73..40884ff 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -319,6 +319,9 @@ "stayOneVersionBehind": "比最新版本晚一个版本", "refreshBeforeDownload": "下载前刷新应用程序详细信息", "tencentAppStore": "腾讯应用宝", + "name": "名称", + "smartname": "姓名(智能)", + "sortMethod": "排序方法", "removeAppQuestion": { "one": "是否删除应用?", "other": "是否删除应用?" diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index ab246e6..f2490cc 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -75,8 +75,18 @@ class GitHub extends AppSource { ], [GeneratedFormSwitch('verifyLatestTag', label: tr('verifyLatestTag'))], [ - GeneratedFormSwitch('dontSortReleasesList', - label: tr('dontSortReleasesList')) + GeneratedFormDropdown( + 'sortMethodChoice', + [ + MapEntry('date', tr('releaseDate')), + MapEntry('smartname', tr('smartname')), + MapEntry('none', tr('none')), + MapEntry('smartname-datefallback', + '${tr('smartname')} x ${tr('releaseDate')}'), + MapEntry('name', tr('name')), + ], + label: tr('sortMethod'), + defaultValue: 'date') ], [ GeneratedFormSwitch('useLatestAssetDateAsReleaseDate', @@ -244,10 +254,10 @@ class GitHub extends AppSource { ? additionalSettings['filterReleaseNotesByRegEx'] : null; bool verifyLatestTag = additionalSettings['verifyLatestTag'] == true; - bool dontSortReleasesList = - additionalSettings['dontSortReleasesList'] == true; bool useLatestAssetDateAsReleaseDate = additionalSettings['useLatestAssetDateAsReleaseDate'] == true; + String sortMethod = + additionalSettings['sortMethodChoice'] ?? 'smartname-datefallback'; dynamic latestRelease; if (verifyLatestTag) { var temp = requestUrl.split('?'); @@ -316,7 +326,7 @@ class GitHub extends AppSource { ? getPublishDateFromRelease(rel) : getNewestAssetDateFromRelease(rel); - if (dontSortReleasesList) { + if (sortMethod == 'none') { releases = releases.reversed.toList(); } else { releases.sort((a, b) { @@ -330,22 +340,30 @@ class GitHub extends AppSource { } else { var nameA = a['tag_name'] ?? a['name']; var nameB = b['tag_name'] ?? b['name']; - var stdFormats = findStandardFormatsForVersion(nameA, true) - .intersection(findStandardFormatsForVersion(nameB, true)); - if (stdFormats.isNotEmpty) { - var reg = RegExp(stdFormats.first); - var matchA = reg.firstMatch(nameA); - var matchB = reg.firstMatch(nameB); - return compareAlphaNumeric( - (nameA as String).substring(matchA!.start, matchA.end), - (nameB as String).substring(matchB!.start, matchB.end)); - } else { + var stdFormats = findStandardFormatsForVersion(nameA, false) + .intersection(findStandardFormatsForVersion(nameB, false)); + if (sortMethod == 'date' || + (sortMethod == 'smartname-datefallback' && + stdFormats.isEmpty)) { return (getReleaseDateFromRelease( a, useLatestAssetDateAsReleaseDate) ?? DateTime(1)) .compareTo(getReleaseDateFromRelease( b, useLatestAssetDateAsReleaseDate) ?? DateTime(0)); + } else { + if (sortMethod != 'name' && stdFormats.isNotEmpty) { + var reg = RegExp(stdFormats.last); + var matchA = reg.firstMatch(nameA); + var matchB = reg.firstMatch(nameB); + return compareAlphaNumeric( + (nameA as String).substring(matchA!.start, matchA.end), + (nameB as String).substring(matchB!.start, matchB.end)); + } else { + // 'name' + return compareAlphaNumeric( + (nameA as String), (nameB as String)); + } } } }); diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index 4f5c8c3..4c0cd2f 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -120,7 +120,7 @@ class GitLab extends AppSource { Map additionalSettings) async { String? PAT = await getPATIfAny(hostChanged ? additionalSettings : {}); String optionalAuth = (PAT != null) ? 'private_token=$PAT' : ''; - return '$apkUrl?$optionalAuth'; + return '$apkUrl${(Uri.parse(apkUrl).query.isEmpty ? '?' : '&')}$optionalAuth'; } @override diff --git a/lib/app_sources/html.dart b/lib/app_sources/html.dart index adf8068..88f40ab 100644 --- a/lib/app_sources/html.dart +++ b/lib/app_sources/html.dart @@ -212,6 +212,10 @@ class HTML extends AppSource { required: true, additionalValidators: [(value) => regExValidator(value)]) ], + [ + GeneratedFormSwitch('autoApkFilterByArch', + label: tr('autoApkFilterByArch'), defaultValue: false) + ], ]; HTML() { additionalSourceAppSpecificSettingFormItems = [ @@ -315,6 +319,10 @@ class HTML extends AppSource { if (intLinks.isEmpty) { throw NoReleasesError(note: currentUrl); } else { + if (additionalSettings['intermediateLink'][i]['autoApkFilterByArch'] == + true) { + intLinks = await filterApksByArch(intLinks); + } currentUrl = intLinks.last.key; } } diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index bd61c7e..fac1257 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -9,6 +9,7 @@ import 'package:battery_plus/battery_plus.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart' as http; import 'package:crypto/crypto.dart'; +import 'dart:typed_data'; import 'package:android_intent_plus/flag.dart'; import 'package:android_package_installer/android_package_installer.dart'; @@ -345,18 +346,44 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt, // Perform the download var received = 0; double? progress; + DateTime? lastProgressUpdate; // Track last progress update time if (rangeStart > 0 && fullContentLength != null) { received = rangeStart; } - await response.stream.map((s) { - received += s.length; - progress = - (fullContentLength != null ? (received / fullContentLength) * 100 : 30); - if (onProgress != null) { - onProgress(progress); - } - return s; - }).pipe(sink); + const downloadUIUpdateInterval = Duration(milliseconds: 500); + const downloadBufferSize = 32 * 1024; // 32KB + final downloadBuffer = BytesBuilder(); + await response.stream + .map((chunk) { + received += chunk.length; + final now = DateTime.now(); + if (onProgress != null && + (lastProgressUpdate == null || + now.difference(lastProgressUpdate!) >= + downloadUIUpdateInterval)) { + progress = fullContentLength != null + ? (received / fullContentLength) * 100 + : 30; + onProgress(progress); + lastProgressUpdate = now; + } + return chunk; + }) + .transform(StreamTransformer, List>.fromHandlers( + handleData: (List data, EventSink> s) { + downloadBuffer.add(data); + if (downloadBuffer.length >= downloadBufferSize) { + s.add(downloadBuffer.takeBytes()); + } + }, + handleDone: (EventSink> s) { + if (downloadBuffer.isNotEmpty) { + s.add(downloadBuffer.takeBytes()); + } + s.close(); + }, + )) + .pipe(sink); await sink.close(); progress = null; if (onProgress != null) { diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 51ab933..6084fb9 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -152,6 +152,10 @@ appJSONCompatibilityModifiers(Map json) { if (additionalSettings['autoApkFilterByArch'] == null) { additionalSettings['autoApkFilterByArch'] = false; } + // GitHub "don't sort" option to new dropdown format + if (additionalSettings['dontSortReleasesList'] == true) { + additionalSettings['sortMethodChoice'] = 'none'; + } if (source.runtimeType == HTML().runtimeType) { // HTML key rename if (originalAdditionalSettings['sortByFileNamesNotLinks'] != null) { @@ -474,6 +478,23 @@ List> getApkUrlsFromUrls(List urls) => return MapEntry(apkSegs.isNotEmpty ? apkSegs.last : segments.last, e); }).toList(); +Future>> filterApksByArch( + List> apkUrls) async { + if (apkUrls.length > 1) { + var abis = (await DeviceInfoPlugin().androidInfo).supportedAbis; + for (var abi in abis) { + var urls2 = apkUrls + .where((element) => RegExp('.*$abi.*').hasMatch(element.key)) + .toList(); + if (urls2.isNotEmpty && urls2.length < apkUrls.length) { + apkUrls = urls2; + break; + } + } + } + return apkUrls; +} + getSourceRegex(List hosts) { return '(${hosts.join('|').replaceAll('.', '\\.')})'; } @@ -984,18 +1005,8 @@ class SourceProvider { if (apk.apkUrls.isEmpty && !trackOnly) { throw NoAPKError(); } - if (apk.apkUrls.length > 1 && - additionalSettings['autoApkFilterByArch'] == true) { - var abis = (await DeviceInfoPlugin().androidInfo).supportedAbis; - for (var abi in abis) { - var urls2 = apk.apkUrls - .where((element) => RegExp('.*$abi.*').hasMatch(element.key)) - .toList(); - if (urls2.isNotEmpty && urls2.length < apk.apkUrls.length) { - apk.apkUrls = urls2; - break; - } - } + if (additionalSettings['autoApkFilterByArch'] == true) { + apk.apkUrls = await filterApksByArch(apk.apkUrls); } var name = currentApp != null ? currentApp.name.trim() : ''; name = name.isNotEmpty ? name : apk.names.name; diff --git a/pubspec.lock b/pubspec.lock index 550d2e0..803a8ee 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -80,10 +80,10 @@ packages: dependency: transitive description: name: archive - sha256: "528579c7e4579719f04b21eeeeddfd73a18b31dabc22766893b7d1be7f49b967" + sha256: "0c64e928dcbefddecd234205422bcfc2b5e6d31be0b86fef0d0dd48d7b4c9742" url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "4.0.4" args: dependency: transitive description: @@ -232,10 +232,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "72d146c6d7098689ff5c5f66bcf593ac11efc530095385356e131070333e64da" + sha256: "306b78788d1bb569edb7c55d622953c2414ca12445b41c9117963e03afc5c513" url: "https://pub.dev" source: hosted - version: "11.3.0" + version: "11.3.3" device_info_plus_platform_interface: dependency: transitive description: @@ -304,10 +304,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "6f6bfa8797f296965bdc3e1f702574ab49a540c19b9237b401e7c2b25dfe594c" + sha256: "7423298f08f6fc8cce05792bae329f9a93653fc9c08712831b1a55540127995d" url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "9.0.2" fixnum: dependency: transitive description: @@ -349,10 +349,10 @@ packages: dependency: "direct main" description: name: flutter_charset_detector - sha256: d7c11a82c2c51cb35a010b42c64001afb8a9e4d7be1f57620604d386d3467ad1 + sha256: "21f6fe8172fbfe3ba9d2fe0dba3702ba07f682315e829a68d49185a0c80d5ad0" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" flutter_charset_detector_android: dependency: transitive description: @@ -381,10 +381,10 @@ packages: dependency: transitive description: name: flutter_charset_detector_web - sha256: b547194e97e15d2cca17e957ad7f373b48abf35080e645ac5b6976d129b0265d + sha256: e3ac65f94b12f4887937b21a19365d7927db816840cb93274e3861241cb0e9f2 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.0.0" flutter_fgbg: dependency: "direct main" description: @@ -498,10 +498,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" + sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3" url: "https://pub.dev" source: hosted - version: "2.0.24" + version: "2.0.27" flutter_test: dependency: "direct dev" description: flutter @@ -592,14 +592,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.19.0" - js: - dependency: transitive - description: - name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" - source: hosted - version: "0.7.2" json_annotation: dependency: transitive description: @@ -716,10 +708,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12" url: "https://pub.dev" source: hosted - version: "2.2.15" + version: "2.2.16" path_provider_foundation: dependency: transitive description: @@ -900,10 +892,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 + sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.8" shared_preferences_foundation: dependency: transitive description: @@ -1107,10 +1099,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" + sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4" url: "https://pub.dev" source: hosted - version: "6.3.14" + version: "6.3.15" url_launcher_ios: dependency: transitive description: @@ -1187,10 +1179,10 @@ packages: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" webview_flutter: dependency: "direct main" description: @@ -1203,10 +1195,10 @@ packages: dependency: transitive description: name: webview_flutter_android - sha256: "512c26ccc5b8a571fd5d13ec994b7509f142ff6faf85835e243dde3538fdc713" + sha256: "631093a7fbd93e9690ac61d8c8f3e857efbc189fc33f712b9ad6c01a623517ef" url: "https://pub.dev" source: hosted - version: "4.3.2" + version: "4.3.3" webview_flutter_platform_interface: dependency: transitive description: @@ -1219,10 +1211,10 @@ packages: dependency: transitive description: name: webview_flutter_wkwebview - sha256: d7403ef4f042714c9ee2b26eaac4cadae7394cb0d4e608b1dd850c3ff96bd893 + sha256: c49a98510080378b1525132f407a92c3dcd3b7145bef04fb8137724aadcf1cf0 url: "https://pub.dev" source: hosted - version: "3.18.2" + version: "3.18.4" win32: dependency: transitive description: @@ -1235,10 +1227,10 @@ packages: dependency: transitive description: name: win32_registry - sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" url: "https://pub.dev" source: hosted - version: "1.1.5" + version: "2.1.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index da21bea..af6cd79 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,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: 1.1.45+2302 +version: 1.1.46+2303 environment: sdk: ^3.6.0 @@ -86,7 +86,7 @@ dependencies: markdown: any flutter_typeahead: ^5.2.0 battery_plus: ^6.1.0 - flutter_charset_detector: ^4.0.0 + flutter_charset_detector: ^5.0.0 dev_dependencies: flutter_test: sdk: flutter