From 0f7e3ec41dffa576d6930c1fd4d0da971847c9f2 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Tue, 23 Aug 2022 21:41:45 -0400 Subject: [PATCH] Added settings page --- lib/main.dart | 48 +++++++++-- lib/pages/settings.dart | 78 +++++++++++++++-- lib/services/apps_provider.dart | 8 +- lib/services/settings_provider.dart | 47 +++++++++++ pubspec.lock | 124 ++++++++++++++++++++++++++++ pubspec.yaml | 6 +- 6 files changed, 293 insertions(+), 18 deletions(-) create mode 100644 lib/services/settings_provider.dart diff --git a/lib/main.dart b/lib/main.dart index 2bb2603..7a1e78e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:obtainium/pages/home.dart'; import 'package:obtainium/services/apps_provider.dart'; +import 'package:obtainium/services/settings_provider.dart'; import 'package:obtainium/services/source_service.dart'; import 'package:provider/provider.dart'; import 'package:workmanager/workmanager.dart'; @@ -16,8 +17,8 @@ void backgroundUpdateCheck() { String message = updates.length == 1 ? '${updates[0].name} has an update.' : '${(updates.length == 2 ? '${updates[0].name} and ${updates[1].name}' : '${updates[0].name} and ${updates.length - 1} more apps')} have updates.'; - appsProvider.downloaderNotifications.cancel(2); - appsProvider.notify( + await appsProvider.downloaderNotifications.cancel(2); + await appsProvider.notify( 2, 'Updates Available', message, @@ -45,7 +46,10 @@ void main() async { initialDelay: const Duration(minutes: 15), constraints: Constraints(networkType: NetworkType.connected)); runApp(MultiProvider( - providers: [ChangeNotifierProvider(create: (context) => AppsProvider())], + providers: [ + ChangeNotifierProvider(create: (context) => AppsProvider()), + ChangeNotifierProvider(create: (context) => SettingsProvider()) + ], child: const MyApp(), )); } @@ -59,9 +63,34 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return DynamicColorBuilder( builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { + // Initialize the settings provider (if needed) and perform first-run actions if needed + SettingsProvider settingsProvider = context.watch(); + if (settingsProvider.prefs == null) { + settingsProvider.initializeSettings().then((_) { + bool isFirstRun = settingsProvider.checkAndFlipFirstRun(); + if (isFirstRun) { + AppsProvider appsProvider = context.read(); + appsProvider + .notify( + 3, + 'Permission Notification', + 'This is a transient notification used to trigger the Android 13 notification permission prompt', + 'PERMISSION_NOTIFICATION', + 'Permission Notifications', + 'A transient notification used to trigger the Android 13 notification permission prompt', + important: false) + .whenComplete(() { + appsProvider.downloaderNotifications.cancel(3); + }); + } + }); + } + ColorScheme lightColorScheme; ColorScheme darkColorScheme; - if (lightDynamic != null && darkDynamic != null) { + if (lightDynamic != null && + darkDynamic != null && + settingsProvider.colour == ColourSettings.materialYou) { lightColorScheme = lightDynamic.harmonized(); darkColorScheme = darkDynamic.harmonized(); } else { @@ -74,10 +103,15 @@ class MyApp extends StatelessWidget { title: 'Obtainium', theme: ThemeData( useMaterial3: true, - colorScheme: lightColorScheme, + colorScheme: settingsProvider.theme == ThemeSettings.dark + ? darkColorScheme + : lightColorScheme, fontFamily: 'Metropolis'), - darkTheme: - ThemeData(useMaterial3: true, colorScheme: darkColorScheme), + darkTheme: ThemeData( + useMaterial3: true, + colorScheme: settingsProvider.theme == ThemeSettings.light + ? lightColorScheme + : darkColorScheme), home: const HomePage()); }); } diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 065f50e..d0ab394 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:obtainium/services/settings_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher_string.dart'; class SettingsPage extends StatefulWidget { const SettingsPage({super.key}); @@ -10,11 +13,74 @@ class SettingsPage extends StatefulWidget { class _SettingsPageState extends State { @override Widget build(BuildContext context) { - return Center( - child: Text( - 'No Configurable Settings Yet.', - style: Theme.of(context).textTheme.bodyLarge, - textAlign: TextAlign.center, - )); + SettingsProvider settingsProvider = context.watch(); + if (settingsProvider.prefs == null) { + settingsProvider.initializeSettings(); + } + return Padding( + padding: const EdgeInsets.all(16), + child: settingsProvider.prefs == null + ? Container() + : Column( + children: [ + DropdownButtonFormField( + decoration: const InputDecoration(labelText: 'Theme'), + value: settingsProvider.theme, + items: const [ + DropdownMenuItem( + value: ThemeSettings.dark, + child: Text('Dark'), + ), + DropdownMenuItem( + value: ThemeSettings.light, + child: Text('Light'), + ), + DropdownMenuItem( + value: ThemeSettings.system, + child: Text('Follow System'), + ) + ], + onChanged: (value) { + if (value != null) { + settingsProvider.theme = value; + } + }), + const SizedBox( + height: 16, + ), + DropdownButtonFormField( + decoration: const InputDecoration(labelText: 'Colour'), + value: settingsProvider.colour, + items: const [ + DropdownMenuItem( + value: ColourSettings.basic, + child: Text('Obtainium'), + ), + DropdownMenuItem( + value: ColourSettings.materialYou, + child: Text('Material You'), + ) + ], + onChanged: (value) { + if (value != null) { + settingsProvider.colour = value; + } + }), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ElevatedButton.icon( + onPressed: () { + launchUrlString(settingsProvider.sourceUrl, + mode: LaunchMode.externalApplication); + }, + icon: const Icon(Icons.code), + label: const Text('Source'), + ) + ], + ), + ], + )); } } diff --git a/lib/services/apps_provider.dart b/lib/services/apps_provider.dart index 99f86f3..4320442 100644 --- a/lib/services/apps_provider.dart +++ b/lib/services/apps_provider.dart @@ -51,7 +51,8 @@ class AppsProvider with ChangeNotifier { } Future notify(int id, String title, String message, String channelCode, - String channelName, String channelDescription) { + String channelName, String channelDescription, + {bool important = true}) { return downloaderNotifications.show( id, title, @@ -59,8 +60,8 @@ class AppsProvider with ChangeNotifier { NotificationDetails( android: AndroidNotificationDetails(channelCode, channelName, channelDescription: channelDescription, - importance: Importance.max, - priority: Priority.max, + importance: important ? Importance.max : Importance.min, + priority: important ? Priority.max : Priority.min, groupKey: 'dev.imranr.obtainium.$channelCode'))); } @@ -98,6 +99,7 @@ class AppsProvider with ChangeNotifier { } if (!isForeground) { + await downloaderNotifications.cancel(1); await notify( 1, 'Complete App Installation', diff --git a/lib/services/settings_provider.dart b/lib/services/settings_provider.dart new file mode 100644 index 0000000..0d897d6 --- /dev/null +++ b/lib/services/settings_provider.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +enum ThemeSettings { system, light, dark } + +enum ColourSettings { basic, materialYou } + +class SettingsProvider with ChangeNotifier { + SharedPreferences? prefs; + + String sourceUrl = 'https://github.com/ImranR98/Obtainium'; + + // Not done in constructor as we want to be able to await it + Future initializeSettings() async { + prefs = await SharedPreferences.getInstance(); + notifyListeners(); + } + + ThemeSettings get theme { + return ThemeSettings + .values[prefs?.getInt('theme') ?? ThemeSettings.system.index]; + } + + set theme(ThemeSettings t) { + print(t); + prefs?.setInt('theme', t.index); + notifyListeners(); + } + + ColourSettings get colour { + return ColourSettings + .values[prefs?.getInt('colour') ?? ColourSettings.basic.index]; + } + + set colour(ColourSettings t) { + prefs?.setInt('colour', t.index); + notifyListeners(); + } + + checkAndFlipFirstRun() { + bool result = prefs?.getBool('firstRun') ?? true; + if (result) { + prefs?.setBool('firstRun', false); + } + return result; + } +} diff --git a/pubspec.lock b/pubspec.lock index 83ed880..86e0978 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -172,6 +172,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" html: dependency: "direct main" description: @@ -207,6 +212,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" json_annotation: dependency: transitive description: @@ -340,6 +352,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.0.3" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.15" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" sky_engine: dependency: transitive description: flutter @@ -401,6 +469,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.5" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.17" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.17" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.13" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3b283f7..8eb33fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,15 +37,17 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 path_provider: ^2.0.11 - flutter_fgbg: ^0.2.0 + flutter_fgbg: ^0.2.0 # Try removing reliance on this flutter_local_notifications: ^9.7.0 provider: ^6.0.3 http: ^0.13.5 webview_flutter: ^3.0.4 workmanager: ^0.5.0 dynamic_color: ^1.5.3 - install_plugin_v2: ^1.0.0 + install_plugin_v2: ^1.0.0 # Try replacing this html: ^0.15.0 + shared_preferences: ^2.0.15 + url_launcher: ^6.1.5 dev_dependencies: