mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-04 07:13:28 +01:00 
			
		
		
		
	Added import/export
This commit is contained in:
		@@ -1,4 +1,7 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:obtainium/services/apps_provider.dart';
 | 
			
		||||
import 'package:obtainium/services/settings_provider.dart';
 | 
			
		||||
import 'package:provider/provider.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
			
		||||
@@ -13,6 +16,7 @@ class SettingsPage extends StatefulWidget {
 | 
			
		||||
class _SettingsPageState extends State<SettingsPage> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    AppsProvider appsProvider = context.read<AppsProvider>();
 | 
			
		||||
    SettingsProvider settingsProvider = context.watch<SettingsProvider>();
 | 
			
		||||
    if (settingsProvider.prefs == null) {
 | 
			
		||||
      settingsProvider.initializeSettings();
 | 
			
		||||
@@ -104,17 +108,129 @@ class _SettingsPageState extends State<SettingsPage> {
 | 
			
		||||
                          settingsProvider.updateInterval = value;
 | 
			
		||||
                        }
 | 
			
		||||
                      }),
 | 
			
		||||
                  const SizedBox(
 | 
			
		||||
                    height: 32,
 | 
			
		||||
                  ),
 | 
			
		||||
                  Row(
 | 
			
		||||
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
 | 
			
		||||
                    children: [
 | 
			
		||||
                      ElevatedButton(
 | 
			
		||||
                          onPressed: appsProvider.apps.isEmpty
 | 
			
		||||
                              ? null
 | 
			
		||||
                              : () {
 | 
			
		||||
                                  appsProvider.exportApps().then((String path) {
 | 
			
		||||
                                    ScaffoldMessenger.of(context).showSnackBar(
 | 
			
		||||
                                      SnackBar(
 | 
			
		||||
                                          content: Text('Exported to $path')),
 | 
			
		||||
                                    );
 | 
			
		||||
                                  });
 | 
			
		||||
                                },
 | 
			
		||||
                          child: const Text('Export Apps')),
 | 
			
		||||
                      ElevatedButton(
 | 
			
		||||
                          onPressed: () {
 | 
			
		||||
                            showDialog(
 | 
			
		||||
                                context: context,
 | 
			
		||||
                                builder: (BuildContext ctx) {
 | 
			
		||||
                                  final formKey = GlobalKey<FormState>();
 | 
			
		||||
                                  final jsonInputController =
 | 
			
		||||
                                      TextEditingController();
 | 
			
		||||
 | 
			
		||||
                                  return AlertDialog(
 | 
			
		||||
                                    scrollable: true,
 | 
			
		||||
                                    title: const Text('Import Apps'),
 | 
			
		||||
                                    content: Column(children: [
 | 
			
		||||
                                      const Text(
 | 
			
		||||
                                          'Copy the contents of the Obtainium export file and paste them into the field below:'),
 | 
			
		||||
                                      Form(
 | 
			
		||||
                                        key: formKey,
 | 
			
		||||
                                        child: TextFormField(
 | 
			
		||||
                                          minLines: 7,
 | 
			
		||||
                                          maxLines: 7,
 | 
			
		||||
                                          decoration: const InputDecoration(
 | 
			
		||||
                                              helperText:
 | 
			
		||||
                                                  'Obtainium export data'),
 | 
			
		||||
                                          controller: jsonInputController,
 | 
			
		||||
                                          validator: (value) {
 | 
			
		||||
                                            if (value == null ||
 | 
			
		||||
                                                value.isEmpty) {
 | 
			
		||||
                                              return 'Please enter your Obtainium export data';
 | 
			
		||||
                                            }
 | 
			
		||||
                                            bool isJSON = true;
 | 
			
		||||
                                            try {
 | 
			
		||||
                                              jsonDecode(value);
 | 
			
		||||
                                            } catch (e) {
 | 
			
		||||
                                              isJSON = false;
 | 
			
		||||
                                            }
 | 
			
		||||
                                            if (!isJSON) {
 | 
			
		||||
                                              return 'Invalid input';
 | 
			
		||||
                                            }
 | 
			
		||||
                                            return null;
 | 
			
		||||
                                          },
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      )
 | 
			
		||||
                                    ]),
 | 
			
		||||
                                    actions: [
 | 
			
		||||
                                      TextButton(
 | 
			
		||||
                                          onPressed: () {
 | 
			
		||||
                                            if (formKey.currentState!
 | 
			
		||||
                                                .validate()) {
 | 
			
		||||
                                              appsProvider
 | 
			
		||||
                                                  .importApps(
 | 
			
		||||
                                                      jsonInputController
 | 
			
		||||
                                                          .value.text)
 | 
			
		||||
                                                  .then((value) {
 | 
			
		||||
                                                ScaffoldMessenger.of(context)
 | 
			
		||||
                                                    .showSnackBar(
 | 
			
		||||
                                                  SnackBar(
 | 
			
		||||
                                                      content: Text(
 | 
			
		||||
                                                          '$value Apps Imported')),
 | 
			
		||||
                                                );
 | 
			
		||||
                                              }).catchError((e) {
 | 
			
		||||
                                                ScaffoldMessenger.of(context)
 | 
			
		||||
                                                    .showSnackBar(
 | 
			
		||||
                                                  SnackBar(
 | 
			
		||||
                                                      content:
 | 
			
		||||
                                                          Text(e.toString())),
 | 
			
		||||
                                                );
 | 
			
		||||
                                              }).whenComplete(() {
 | 
			
		||||
                                                Navigator.of(context).pop();
 | 
			
		||||
                                              });
 | 
			
		||||
                                            }
 | 
			
		||||
                                          },
 | 
			
		||||
                                          child: const Text('Import')),
 | 
			
		||||
                                      TextButton(
 | 
			
		||||
                                          onPressed: () {
 | 
			
		||||
                                            Navigator.of(context).pop();
 | 
			
		||||
                                          },
 | 
			
		||||
                                          child: const Text('Cancel'))
 | 
			
		||||
                                    ],
 | 
			
		||||
                                  );
 | 
			
		||||
                                });
 | 
			
		||||
                          },
 | 
			
		||||
                          child: const Text('Import Apps'))
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                  const Spacer(),
 | 
			
		||||
                  Row(
 | 
			
		||||
                    mainAxisAlignment: MainAxisAlignment.end,
 | 
			
		||||
                    mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                    children: [
 | 
			
		||||
                      ElevatedButton.icon(
 | 
			
		||||
                      TextButton.icon(
 | 
			
		||||
                        style: ButtonStyle(
 | 
			
		||||
                          foregroundColor:
 | 
			
		||||
                              MaterialStateProperty.resolveWith<Color>(
 | 
			
		||||
                                  (Set<MaterialState> states) {
 | 
			
		||||
                            return Colors.grey;
 | 
			
		||||
                          }),
 | 
			
		||||
                        ),
 | 
			
		||||
                        onPressed: () {
 | 
			
		||||
                          launchUrlString(settingsProvider.sourceUrl,
 | 
			
		||||
                              mode: LaunchMode.externalApplication);
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: const Icon(Icons.code),
 | 
			
		||||
                        label: const Text('Source'),
 | 
			
		||||
                        label: Text(
 | 
			
		||||
                          'Source',
 | 
			
		||||
                          style: Theme.of(context).textTheme.caption,
 | 
			
		||||
                        ),
 | 
			
		||||
                      )
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,7 @@ class AppsProvider with ChangeNotifier {
 | 
			
		||||
    await InstallPlugin.installApk(downloadFile.path, 'dev.imranr.obtainium');
 | 
			
		||||
 | 
			
		||||
    apps[appId]!.app.installedVersion = apps[appId]!.app.latestVersion;
 | 
			
		||||
    saveApp(apps[appId]!.app);
 | 
			
		||||
    await saveApp(apps[appId]!.app);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Directory> getAppsDir() async {
 | 
			
		||||
@@ -236,6 +236,40 @@ class AppsProvider with ChangeNotifier {
 | 
			
		||||
    return updateAppIds;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<String> exportApps() async {
 | 
			
		||||
    Directory? exportDir = Directory('/storage/emulated/0/Download');
 | 
			
		||||
    String path = 'Downloads';
 | 
			
		||||
    if (!exportDir.existsSync()) {
 | 
			
		||||
      exportDir = await getExternalStorageDirectory();
 | 
			
		||||
      path = exportDir!.path;
 | 
			
		||||
    }
 | 
			
		||||
    File export = File(
 | 
			
		||||
        '${exportDir!.path}/obtainium-export-${DateTime.now().millisecondsSinceEpoch}.json');
 | 
			
		||||
    export.writeAsStringSync(
 | 
			
		||||
        jsonEncode(apps.values.map((e) => e.app.toJson()).toList()));
 | 
			
		||||
    return path;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<int> importApps(String appsJSON) async {
 | 
			
		||||
    // FilePickerResult? result = await FilePicker.platform.pickFiles();
 | 
			
		||||
 | 
			
		||||
    // if (result != null) {
 | 
			
		||||
    // String appsJSON = File(result.files.single.path!).readAsStringSync();
 | 
			
		||||
    List<App> importedApps = (jsonDecode(appsJSON) as List<dynamic>)
 | 
			
		||||
        .map((e) => App.fromJson(e))
 | 
			
		||||
        .toList();
 | 
			
		||||
    for (App a in importedApps) {
 | 
			
		||||
      a.installedVersion =
 | 
			
		||||
          apps.containsKey(a.id) ? apps[a]?.app.installedVersion : null;
 | 
			
		||||
      await saveApp(a);
 | 
			
		||||
    }
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
    return importedApps.length;
 | 
			
		||||
    // } else {
 | 
			
		||||
    // User canceled the picker
 | 
			
		||||
    // }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void dispose() {
 | 
			
		||||
    IsolateNameServer.removePortNameMapping('downloader_send_port');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user