mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-17 15:16:43 +02:00
Enable auto-export on update checks
This commit is contained in:
@ -254,6 +254,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remover App?",
|
"one": "Remover App?",
|
||||||
"other": "Remover Apps?"
|
"other": "Remover Apps?"
|
||||||
|
@ -111,7 +111,7 @@
|
|||||||
"dark": "Tamna",
|
"dark": "Tamna",
|
||||||
"light": "Svijetla",
|
"light": "Svijetla",
|
||||||
"followSystem": "Pratite sistem",
|
"followSystem": "Pratite sistem",
|
||||||
"obtainium": "Obtainium",
|
"obtainium": "Obtainium",
|
||||||
"materialYou": "Material You",
|
"materialYou": "Material You",
|
||||||
"useBlackTheme": "Koristite čisto crnu tamnu temu",
|
"useBlackTheme": "Koristite čisto crnu tamnu temu",
|
||||||
"appSortBy": "Aplikacije sortirane po",
|
"appSortBy": "Aplikacije sortirane po",
|
||||||
@ -251,7 +251,9 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
"removeAppQuestion": {
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
|
"removeAppQuestion": {
|
||||||
"one": "Želite li ukloniti aplikaciju?",
|
"one": "Želite li ukloniti aplikaciju?",
|
||||||
"other": "Želite li ukloniti aplikacije?"
|
"other": "Želite li ukloniti aplikacije?"
|
||||||
},
|
},
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App entfernen?",
|
"one": "App entfernen?",
|
||||||
"other": "Apps entfernen?"
|
"other": "Apps entfernen?"
|
||||||
|
@ -254,6 +254,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remove App?",
|
"one": "Remove App?",
|
||||||
"other": "Remove Apps?"
|
"other": "Remove Apps?"
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "¿Eliminar Aplicación?",
|
"one": "¿Eliminar Aplicación?",
|
||||||
"other": "¿Eliminar Aplicaciones?"
|
"other": "¿Eliminar Aplicaciones?"
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "برنامه حذف شود؟",
|
"one": "برنامه حذف شود؟",
|
||||||
"other": "برنامه ها حذف شوند؟"
|
"other": "برنامه ها حذف شوند؟"
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Supprimer l'application ?",
|
"one": "Supprimer l'application ?",
|
||||||
"other": "Supprimer les applications ?"
|
"other": "Supprimer les applications ?"
|
||||||
|
@ -250,6 +250,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Eltávolítja az alkalmazást?",
|
"one": "Eltávolítja az alkalmazást?",
|
||||||
"other": "Eltávolítja az alkalmazást?"
|
"other": "Eltávolítja az alkalmazást?"
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Rimuovere l'app?",
|
"one": "Rimuovere l'app?",
|
||||||
"other": "Rimuovere le app?"
|
"other": "Rimuovere le app?"
|
||||||
|
@ -252,6 +252,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
|
@ -257,6 +257,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Usunąć aplikację?",
|
"one": "Usunąć aplikację?",
|
||||||
"few": "Usunąć aplikacje?",
|
"few": "Usunąć aplikacje?",
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Удалить приложение?",
|
"one": "Удалить приложение?",
|
||||||
"other": "Удалить приложения?"
|
"other": "Удалить приложения?"
|
||||||
|
@ -252,6 +252,8 @@
|
|||||||
"versionExtractionRegEx": "Version Extraction RegEx",
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
"matchGroupToUse": "Match Group to Use",
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"highlightTouchTargets": "Highlight less obvious touch targets",
|
"highlightTouchTargets": "Highlight less obvious touch targets",
|
||||||
|
"pickExportDir": "Pick Export Directory",
|
||||||
|
"autoExportOnUpdateCheckKeepNum": "Auto-export on update check (keep last N auto-exports)",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "是否删除应用?",
|
"one": "是否删除应用?",
|
||||||
"other": "是否删除应用?"
|
"other": "是否删除应用?"
|
||||||
|
@ -124,10 +124,7 @@ class HTML extends AppSource {
|
|||||||
additionalValidators: [
|
additionalValidators: [
|
||||||
(value) {
|
(value) {
|
||||||
value ??= '1';
|
value ??= '1';
|
||||||
if (int.tryParse(value) == null) {
|
return intValidator(value);
|
||||||
return tr('invalidInput');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
@ -74,6 +74,11 @@ class AppsPageState extends State<AppsPage> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
refreshingSince = null;
|
refreshingSince = null;
|
||||||
});
|
});
|
||||||
|
if (settingsProvider.autoExportOnUpdateCheckKeepNum > 0) {
|
||||||
|
appsProvider.exportApps(isAuto: true).then((value) {
|
||||||
|
appsProvider.trimAutoExports();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,8 +104,12 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
|
|
||||||
runObtainiumExport() {
|
runObtainiumExport() {
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
appsProvider.exportApps().then((String path) {
|
appsProvider
|
||||||
showError(tr('exportedTo', args: [path]), context);
|
.exportApps(pickOnly: settingsProvider.exportDir == null)
|
||||||
|
.then((String? result) {
|
||||||
|
if (result != null) {
|
||||||
|
showError(tr('exportedTo', args: [result]), context);
|
||||||
|
}
|
||||||
}).catchError((e) {
|
}).catchError((e) {
|
||||||
showError(e, context);
|
showError(e, context);
|
||||||
});
|
});
|
||||||
@ -310,7 +314,10 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
importInProgress
|
importInProgress
|
||||||
? null
|
? null
|
||||||
: runObtainiumExport,
|
: runObtainiumExport,
|
||||||
child: Text(tr('obtainiumExport')))),
|
child: Text(tr(
|
||||||
|
settingsProvider.exportDir != null
|
||||||
|
? 'obtainiumExport'
|
||||||
|
: 'pickExportDirKeepLastN')))),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
),
|
),
|
||||||
@ -323,6 +330,48 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
child: Text(tr('obtainiumImport'))))
|
child: Text(tr('obtainiumImport'))))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (settingsProvider.exportDir != null)
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
GeneratedForm(
|
||||||
|
items: [
|
||||||
|
[
|
||||||
|
GeneratedFormTextField(
|
||||||
|
'autoExportOnUpdateCheckKeepNum',
|
||||||
|
label: tr(
|
||||||
|
'autoExportOnUpdateCheckKeepNum'),
|
||||||
|
required: false,
|
||||||
|
defaultValue: settingsProvider
|
||||||
|
.autoExportOnUpdateCheckKeepNum
|
||||||
|
.toString(),
|
||||||
|
textInputType: const TextInputType
|
||||||
|
.numberWithOptions(),
|
||||||
|
additionalValidators: [
|
||||||
|
(value) {
|
||||||
|
value ??= settingsProvider
|
||||||
|
.autoExportOnUpdateCheckKeepNum
|
||||||
|
.toString();
|
||||||
|
return intValidator(value,
|
||||||
|
positive: true);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]
|
||||||
|
],
|
||||||
|
onValueChanges: (value, valid, isBuilding) {
|
||||||
|
if (valid && !isBuilding) {
|
||||||
|
if (value[
|
||||||
|
'autoExportOnUpdateCheckKeepNum'] !=
|
||||||
|
null) {
|
||||||
|
settingsProvider
|
||||||
|
.autoExportOnUpdateCheckKeepNum =
|
||||||
|
int.parse(value[
|
||||||
|
'autoExportOnUpdateCheckKeepNum']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
if (importInProgress)
|
if (importInProgress)
|
||||||
const Column(
|
const Column(
|
||||||
children: [
|
children: [
|
||||||
@ -399,7 +448,7 @@ class _ImportExportPageState extends State<ImportExportPage> {
|
|||||||
fontStyle: FontStyle.italic, fontSize: 12)),
|
fontStyle: FontStyle.italic, fontSize: 12)),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
)))
|
)))
|
||||||
]));
|
]));
|
||||||
|
@ -16,6 +16,7 @@ import 'package:device_info_plus/device_info_plus.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:obtainium/app_sources/html.dart';
|
||||||
import 'package:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.dart';
|
||||||
import 'package:obtainium/components/generated_form_modal.dart';
|
import 'package:obtainium/components/generated_form_modal.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
@ -31,6 +32,7 @@ import 'package:obtainium/providers/source_provider.dart';
|
|||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:android_intent_plus/android_intent.dart';
|
import 'package:android_intent_plus/android_intent.dart';
|
||||||
import 'package:flutter_archive/flutter_archive.dart';
|
import 'package:flutter_archive/flutter_archive.dart';
|
||||||
|
import 'package:shared_storage/shared_storage.dart' as saf;
|
||||||
|
|
||||||
final pm = AndroidPackageManager();
|
final pm = AndroidPackageManager();
|
||||||
|
|
||||||
@ -167,7 +169,8 @@ class AppsProvider with ChangeNotifier {
|
|||||||
if (cacheDirs?.isNotEmpty ?? false) {
|
if (cacheDirs?.isNotEmpty ?? false) {
|
||||||
APKDir = cacheDirs!.first;
|
APKDir = cacheDirs!.first;
|
||||||
} else {
|
} else {
|
||||||
APKDir = Directory('${await settingsProvider.getAppDir()}/apks');
|
APKDir =
|
||||||
|
Directory('${(await getExternalStorageDirectory())!.path}/apks');
|
||||||
if (!APKDir.existsSync()) {
|
if (!APKDir.existsSync()) {
|
||||||
APKDir.createSync();
|
APKDir.createSync();
|
||||||
}
|
}
|
||||||
@ -676,7 +679,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
|
|
||||||
Future<Directory> getAppsDir() async {
|
Future<Directory> getAppsDir() async {
|
||||||
Directory appsDir =
|
Directory appsDir =
|
||||||
Directory('${await settingsProvider.getAppDir()}/app_data');
|
Directory('${(await getExternalStorageDirectory())!.path}/app_data');
|
||||||
if (!appsDir.existsSync()) {
|
if (!appsDir.existsSync()) {
|
||||||
appsDir.createSync();
|
appsDir.createSync();
|
||||||
}
|
}
|
||||||
@ -1091,32 +1094,58 @@ class AppsProvider with ChangeNotifier {
|
|||||||
return updateAppIds;
|
return updateAppIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> exportApps() async {
|
Future<String?> exportApps({bool pickOnly = false, isAuto = false}) async {
|
||||||
if ((await DeviceInfoPlugin().androidInfo).version.sdkInt <= 29) {
|
if (isAuto) {
|
||||||
if (await Permission.storage.isDenied) {
|
logs.add('Started auto-export.');
|
||||||
await Permission.storage.request();
|
}
|
||||||
|
var exportDir = settingsProvider.exportDir;
|
||||||
|
if (exportDir == null || pickOnly) {
|
||||||
|
await settingsProvider.pickExportDirKeepLastN();
|
||||||
|
exportDir = settingsProvider.exportDir;
|
||||||
|
}
|
||||||
|
if (exportDir == null) {
|
||||||
|
throw ObtainiumError(tr('unexpectedError'));
|
||||||
|
}
|
||||||
|
String? returnPath;
|
||||||
|
if (!pickOnly) {
|
||||||
|
var result = await saf.createFile(exportDir,
|
||||||
|
displayName:
|
||||||
|
'${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().toIso8601String().replaceAll(':', '-')}${isAuto ? '-auto' : ''}.json',
|
||||||
|
mimeType: 'application/json',
|
||||||
|
content: jsonEncode(apps.values.map((e) => e.app.toJson()).toList()));
|
||||||
|
if (result == null) {
|
||||||
|
throw ObtainiumError(tr('unexpectedError'));
|
||||||
}
|
}
|
||||||
if (await Permission.storage.isDenied) {
|
returnPath =
|
||||||
throw ObtainiumError(tr('storagePermissionDenied'));
|
exportDir.pathSegments.join('/').replaceFirst('tree/primary:', '');
|
||||||
|
}
|
||||||
|
return returnPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> trimAutoExports() async {
|
||||||
|
var exportDir = settingsProvider.exportDir;
|
||||||
|
if (exportDir != null) {
|
||||||
|
var files = await saf
|
||||||
|
.listFiles(exportDir, columns: [saf.DocumentFileColumn.id]).toList();
|
||||||
|
var maxCount = settingsProvider.autoExportOnUpdateCheckKeepNum;
|
||||||
|
if (files.length > maxCount) {
|
||||||
|
files.sort((a, b) {
|
||||||
|
if (a.name == null) {
|
||||||
|
return -1;
|
||||||
|
} else if (b.name == null) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return compareAlphaNumeric(a.name!, b.name!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
files = files.reversed.toList();
|
||||||
|
logs.add(
|
||||||
|
'Deleting auto-exports older than ${files[maxCount - 1].uri.pathSegments.last}.');
|
||||||
|
files.sublist(maxCount).forEach((f) {
|
||||||
|
saf.delete(f.uri);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Directory? exportDir = Directory('/storage/emulated/0/Download');
|
|
||||||
String path = 'Downloads'; // TODO: See if hardcoding this can be avoided
|
|
||||||
var downloadsAccessible = false;
|
|
||||||
try {
|
|
||||||
downloadsAccessible = exportDir.existsSync();
|
|
||||||
} catch (e) {
|
|
||||||
logs.add('Error accessing Downloads (will use fallback): $e');
|
|
||||||
}
|
|
||||||
if (!downloadsAccessible) {
|
|
||||||
exportDir = Directory(await settingsProvider.getAppDir());
|
|
||||||
path = exportDir.path;
|
|
||||||
}
|
|
||||||
File export = File(
|
|
||||||
'${exportDir.path}/${tr('obtainiumExportHyphenatedLowercase')}-${DateTime.now().millisecondsSinceEpoch}.json');
|
|
||||||
export.writeAsStringSync(
|
|
||||||
jsonEncode(apps.values.map((e) => e.app.toJson()).toList()));
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> importApps(String appsJSON) async {
|
Future<int> importApps(String appsJSON) async {
|
||||||
@ -1402,6 +1431,10 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
|
|||||||
if (toNotify.isNotEmpty) {
|
if (toNotify.isNotEmpty) {
|
||||||
notificationsProvider.notify(UpdateNotification(toNotify));
|
notificationsProvider.notify(UpdateNotification(toNotify));
|
||||||
}
|
}
|
||||||
|
if (appsProvider.settingsProvider.autoExportOnUpdateCheckKeepNum > 0) {
|
||||||
|
await appsProvider.exportApps(isAuto: true);
|
||||||
|
await appsProvider.trimAutoExports();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If you're done checking and found some silently installable updates, schedule another task which will run in install mode
|
// If you're done checking and found some silently installable updates, schedule another task which will run in install mode
|
||||||
if (didCompleteChecking && toInstall.isNotEmpty) {
|
if (didCompleteChecking && toInstall.isNotEmpty) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Exposes functions used to save/load app settings
|
// Exposes functions used to save/load app settings
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -363,52 +362,41 @@ class SettingsProvider with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getAppDir() async {
|
Uri? get exportDir {
|
||||||
return prefs?.getString('appDir') ?? defaultAppDir!;
|
var uriString = prefs?.getString('exportDir');
|
||||||
|
if (uriString != null) {
|
||||||
|
return Uri.parse(uriString);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pickAppDir({bool useDefault = false}) async {
|
Future<void> pickExportDirKeepLastN({bool remove = false}) async {
|
||||||
var existingSAFPerms = (await saf.persistedUriPermissions()) ?? [];
|
var existingSAFPerms = (await saf.persistedUriPermissions()) ?? [];
|
||||||
var currentAppDir = await getAppDir();
|
var currentOneWayDataSyncDir = exportDir;
|
||||||
if (currentAppDir != defaultAppDir) {
|
Uri? newOneWayDataSyncDir;
|
||||||
currentAppDir = currentAppDir.replaceFirst(
|
if (!remove) {
|
||||||
'/storage/emulated/0/', '/tree/primary%3A');
|
newOneWayDataSyncDir = (await saf.openDocumentTree());
|
||||||
}
|
}
|
||||||
String? newAppDir;
|
if (currentOneWayDataSyncDir?.path != newOneWayDataSyncDir?.path) {
|
||||||
if (!useDefault) {
|
if (newOneWayDataSyncDir == null) {
|
||||||
var target = (await saf.openDocumentTree());
|
prefs?.remove('exportDir');
|
||||||
if (target != null) {
|
} else {
|
||||||
newAppDir = target.path
|
prefs?.setString('exportDir', newOneWayDataSyncDir.toString());
|
||||||
.replaceFirst('/tree/primary%3A', '/storage/emulated/0/');
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
newAppDir = defaultAppDir;
|
|
||||||
}
|
|
||||||
newAppDir ??= defaultAppDir;
|
|
||||||
if (currentAppDir != newAppDir) {
|
|
||||||
moveDirectoryContents(Directory(currentAppDir), Directory(newAppDir!));
|
|
||||||
prefs?.setString('appDir', newAppDir);
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
for (var e in existingSAFPerms) {
|
for (var e in existingSAFPerms) {
|
||||||
await saf.releasePersistableUriPermission(e.uri);
|
await saf.releasePersistableUriPermission(e.uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void moveDirectoryContents(Directory sourceDir, Directory destinationDir) {
|
int get autoExportOnUpdateCheckKeepNum {
|
||||||
if (!destinationDir.existsSync()) {
|
return prefs?.getInt('autoExportOnUpdateCheckKeepNum') ?? 0;
|
||||||
destinationDir.createSync(recursive: true);
|
|
||||||
}
|
}
|
||||||
List<FileSystemEntity> contents = sourceDir.listSync();
|
|
||||||
for (FileSystemEntity entity in contents) {
|
set autoExportOnUpdateCheckKeepNum(int val) {
|
||||||
String newPath = '${destinationDir.path}/${entity.uri.pathSegments.last}';
|
prefs?.setInt('autoExportOnUpdateCheckKeepNum', val);
|
||||||
if (entity is File) {
|
notifyListeners();
|
||||||
entity.renameSync(newPath);
|
|
||||||
} else if (entity is Directory) {
|
|
||||||
Directory newDestinationDir = Directory(newPath);
|
|
||||||
moveDirectoryContents(entity, newDestinationDir);
|
|
||||||
entity.deleteSync(recursive: true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,6 +521,20 @@ regExValidator(String? value) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intValidator(String? value, {bool positive = false}) {
|
||||||
|
if (value == null) {
|
||||||
|
return tr('invalidInput');
|
||||||
|
}
|
||||||
|
var num = int.tryParse(value);
|
||||||
|
if (num == null) {
|
||||||
|
return tr('invalidInput');
|
||||||
|
}
|
||||||
|
if (positive && num <= 0) {
|
||||||
|
return tr('invalidInput');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
class SourceProvider {
|
class SourceProvider {
|
||||||
// Add more source classes here so they are available via the service
|
// Add more source classes here so they are available via the service
|
||||||
List<AppSource> get sources => [
|
List<AppSource> get sources => [
|
||||||
|
Reference in New Issue
Block a user