Skip to content

Commit

Permalink
(#30) Implement preferences settings to hide system apps
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcmgit committed Feb 22, 2023
1 parent ecd7579 commit 43eb2d9
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 40 deletions.
93 changes: 89 additions & 4 deletions lib/pages/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import '../utils/stringify_uri_location.dart';
import '../widgets/app_icon_button.dart';
import '../widgets/app_version_info.dart';
import '../widgets/horizontal_rule.dart';
import '../widgets/material_you_dialog_shape.dart';

class SettingsPage extends StatefulWidget {
const SettingsPage({super.key});
Expand Down Expand Up @@ -71,6 +70,9 @@ class _SettingsPageState extends State<SettingsPage>
const AppFontFamilySettingsTile(),
const AppLocalizationSettingsTile(),
const HorizontalRule(),
SettingsTileTitle('Preferences'),
const AppBooleanPreferencesSettingsTile(),
const HorizontalRule(),
const AppVersionInfo(),
],
),
Expand Down Expand Up @@ -195,7 +197,7 @@ class _ChangeThemeDialogState extends State<ChangeThemeDialog>
animation: themeStore,
builder: (BuildContext context, Widget? child) {
return SimpleDialog(
shape: const MaterialYouDialogShape(),
// shape: const MaterialYouDialogShape(),
backgroundColor: context.theme.colorScheme.background,
title: Text(context.strings.theme),
children: <Widget>[
Expand Down Expand Up @@ -269,7 +271,7 @@ class _ChangeThemeFontFamilyDialogState
animation: themeStore,
builder: (BuildContext context, Widget? child) {
return SimpleDialog(
shape: const MaterialYouDialogShape(),
// shape: const MaterialYouDialogShape(),
backgroundColor: context.theme.colorScheme.background,
title: Text(context.strings.fontFamily),
children: <Widget>[
Expand All @@ -289,6 +291,89 @@ class _ChangeThemeFontFamilyDialogState
}
}

class AppBooleanPreferencesSettingsTile extends StatefulWidget {
const AppBooleanPreferencesSettingsTile({super.key});

@override
State<AppBooleanPreferencesSettingsTile> createState() =>
_AppBooleanPreferencesSettingsTileState();
}

class _AppBooleanPreferencesSettingsTileState
extends State<AppBooleanPreferencesSettingsTile> with SettingsStoreMixin {
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: settingsStore,
builder: (BuildContext context, Widget? child) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
for (final SettingsBoolPreference preference
in SettingsBoolPreference.values)
InkWell(
onTap: () => settingsStore.toggleBoolPreference(preference),
child: ListTile(
tileColor: Colors.transparent,
contentPadding: const EdgeInsets.symmetric(
horizontal: k10dp,
),
enableFeedback: true,
isThreeLine: true,
trailing: Switch(
trackColor: MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return context.primaryColor;
}
return context.scaffoldBackgroundColor;
},
),
overlayColor: MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
return context.theme.highlightColor;
},
),
thumbColor: MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (context.isDark) {
return context.theme.disabledColor;
}
return context.theme.dividerColor;
}

return context.isDark
? context.theme.disabledColor
: context.theme.disabledColor.withOpacity(.2);
},
),
splashRadius: k12dp,
thumbIcon: MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return Icon(Icons.check, color: context.primaryColor);
}
return null;
},
),
activeColor: context.primaryColor,
value: settingsStore.getBoolPreference(preference),
onChanged: (bool value) => settingsStore
.setBoolPreference(preference, value: value),
),
title: Text(preference.getNameString(context.strings)),
subtitle:
Text(preference.getDescriptionString(context.strings)),
),
),
],
);
},
);
}
}

class AppLocalizationSettingsTile extends StatefulWidget {
const AppLocalizationSettingsTile({super.key});

Expand Down Expand Up @@ -356,7 +441,7 @@ class _ChangeAppLocalizationDialogState
animation: localizationStore,
builder: (BuildContext context, Widget? child) {
return SimpleDialog(
shape: const MaterialYouDialogShape(),
// shape: const MaterialYouDialogShape(),
backgroundColor: context.theme.colorScheme.background,
title: Text(context.strings.language),
children: <Widget>[
Expand Down
2 changes: 1 addition & 1 deletion lib/screens/app_list_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:flutter_shared_tools/constant/constant.dart';
import 'package:flutter_shared_tools/extensions/extensions.dart';

import '../stores/contextual_menu_store.dart';
import '../stores/device_apps.dart';
import '../stores/device_apps_store.dart';
import '../stores/theme_store.dart';
import '../widgets/loading.dart';
import '../widgets/multi_animated_builder.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'stores/apk_list_store.dart';
import 'stores/bottom_navigation_store.dart';
import 'stores/contextual_menu_store.dart';
import 'stores/device_apps.dart';
import 'stores/device_apps_store.dart';
import 'stores/key_value_storage.dart';
import 'stores/localization_store.dart';
import 'stores/settings_store.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/stores/apk_list_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:shared_storage/shared_storage.dart';
import '../setup.dart';
import '../utils/is_disposed_mixin.dart';
import '../utils/throttle.dart';
import 'device_apps.dart';
import 'device_apps_store.dart';
import 'settings_store.dart';

class ApkListStoreMixin {
Expand Down
37 changes: 29 additions & 8 deletions lib/stores/device_apps.dart → lib/stores/device_apps_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ class ApplicationSearchResult implements Comparable<ApplicationSearchResult> {
}
}

class DeviceAppsStore extends ChangeNotifier with IsDisposedMixin {
class DeviceAppsStore extends ChangeNotifier
with IsDisposedMixin, SettingsStoreMixin {
/// Id length to avoid filename conflict on extract Apk
static const int kIdLength = 5;

Expand All @@ -169,13 +170,23 @@ class DeviceAppsStore extends ChangeNotifier with IsDisposedMixin {
/// List of all device applications
/// - Include system apps
/// - Include app icons
List<PackageInfo> get apps => List<PackageInfo>.unmodifiable(
_apps.values.toList()
..sort(
(PackageInfo a, PackageInfo b) =>
a.name!.toLowerCase().compareTo(b.name!.toLowerCase()),
),
);
List<PackageInfo> get apps {
final bool displaySystemApps = settingsStore
.getBoolPreference(SettingsBoolPreference.displaySystemApps);

return List<PackageInfo>.unmodifiable(
_apps.values
.where(
(PackageInfo package) =>
package.isSystemPackage == displaySystemApps,
)
.toList()
..sort(
(PackageInfo a, PackageInfo b) =>
a.name!.toLowerCase().compareTo(b.name!.toLowerCase()),
),
);
}

final Map<String, PackageInfo> _apps = <String, PackageInfo>{};

Expand Down Expand Up @@ -205,6 +216,7 @@ class DeviceAppsStore extends ChangeNotifier with IsDisposedMixin {

@override
void dispose() {
_disposeSettingsStoreListener();
_disposeAppChangeListener();
_disposeAppStreamListener();
super.dispose();
Expand Down Expand Up @@ -263,10 +275,19 @@ class DeviceAppsStore extends ChangeNotifier with IsDisposedMixin {

StreamSubscription<PackageInfo>? _appsStreamSubscription;

void _setupSettingsStoreListener() {
settingsStore.addListener(notifyListeners);
}

void _disposeSettingsStoreListener() {
settingsStore.removeListener(notifyListeners);
}

/// Load all device packages
///
/// You need call this method before any action
Future<void> loadPackages() async {
_setupSettingsStoreListener();
_setupInstallAndUninstallListener();

isLoading = true;
Expand Down
79 changes: 78 additions & 1 deletion lib/stores/settings_store.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_storage/saf.dart';

Expand All @@ -17,6 +18,9 @@ class SettingsStore extends ChangeNotifier {
/// If you need it to make IO operations call [getExportLocationIfItExists] instead.
Uri? exportLocation;

final Map<SettingsBoolPreference, bool> _boolPreferences =
<SettingsBoolPreference, bool>{};

late SharedPreferences prefs;

static const String kExportLocation = 'exportLocation';
Expand Down Expand Up @@ -49,6 +53,19 @@ class SettingsStore extends ChangeNotifier {
prefs = await SharedPreferences.getInstance();

await getAndSetExportLocationIfItExists();
await _loadBoolPreferences();
}

Future<void> _loadBoolPreferences() async {
for (final SettingsBoolPreference preference
in SettingsBoolPreference.values) {
if (!prefs.containsKey(preference.storageKey)) {
await prefs.setBool(preference.storageKey, preference.defaultValue);
}

_boolPreferences[preference] =
prefs.getBool(preference.storageKey) ?? preference.defaultValue;
}
}

Future<void> _setExportLocation(Uri? location) async {
Expand Down Expand Up @@ -82,5 +99,65 @@ class SettingsStore extends ChangeNotifier {
}
}

Future<void> reset() async => _setExportLocation(null);
Future<void> reset() async {
await _setExportLocation(null);
await _resetAllBoolPreferences();
}

Future<void> _resetAllBoolPreferences() async {
for (final SettingsBoolPreference preference
in SettingsBoolPreference.values) {
await resetBoolPreference(preference);
}
}

Future<void> resetBoolPreference(SettingsBoolPreference preference) {
return setBoolPreference(preference, value: preference.defaultValue);
}

bool getBoolPreference(SettingsBoolPreference preference) {
return _boolPreferences[preference] ?? preference.defaultValue;
}

Future<void> toggleBoolPreference(SettingsBoolPreference preference) {
return setBoolPreference(preference, value: !getBoolPreference(preference));
}

Future<void> setBoolPreference(
SettingsBoolPreference preference, {
required bool value,
}) async {
await prefs.setBool(preference.storageKey, value);
_boolPreferences[preference] = value;
notifyListeners();
}
}

enum SettingsBoolPreference {
displaySystemApps(defaultValue: false),
displayAppIcons(defaultValue: true);

const SettingsBoolPreference({required this.defaultValue});

String getNameString(AppLocalizations localizations) {
switch (this) {
case SettingsBoolPreference.displaySystemApps:
return 'Show system apps';
case SettingsBoolPreference.displayAppIcons:
return 'Show app icons';
}
}

String getDescriptionString(AppLocalizations localizations) {
switch (this) {
case SettingsBoolPreference.displaySystemApps:
return 'Whether or not the home app list should include system apps.';
case SettingsBoolPreference.displayAppIcons:
return 'If enabled the home app list will display app icons.';
}
}

final bool defaultValue;

String get storageKey => 'bool__preference__unique__key__${toString()}';
}
14 changes: 2 additions & 12 deletions lib/stores/theme_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ enum AppTheme {
case AppTheme.darkBlood:
return strings.darkBlood;
}

throw Exception(
'For some reason when compiling the Flutter SDK claims we cannot left this "null" case, so lets just throw an exception here to prevent this ghost bug, this may be fixed in the next releases.',
);
}

static AppTheme parseCurrentThemeFromString(String appThemeString) {
Expand Down Expand Up @@ -256,10 +252,6 @@ class ThemeStore extends ChangeNotifier {
? _darkDimmedThemeData()
: _lightDefaultThemeData();
}

throw Exception(
'For some reason when compiling the Flutter SDK claims we cannot left this "null" case, so lets just throw an exception here to prevent this ghost bug, this may be fixed in the next releases.',
);
}

Brightness get currentThemeBrightness {
Expand All @@ -277,10 +269,6 @@ class ThemeStore extends ChangeNotifier {
case AppTheme.followSystem:
return SchedulerBinding.instance.platformDispatcher.platformBrightness;
}

throw Exception(
'For some reason when compiling the Flutter SDK claims we cannot left this "null" case, so lets just throw an exception here to prevent this ghost bug, this may be fixed in the next releases.',
);
}

AppTheme get currentTheme => _currentTheme;
Expand Down Expand Up @@ -418,6 +406,8 @@ ThemeData createThemeData({
primary: primaryColor,
secondary: secondaryColor,
background: backgroundColor,
outline: disabledColor,
),
useMaterial3: true,
);
}
2 changes: 1 addition & 1 deletion lib/widgets/contextual_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:pixelarticons/pixel.dart';
import 'package:pixelarticons/pixelarticons.dart';

import '../stores/contextual_menu_store.dart';
import '../stores/device_apps.dart';
import '../stores/device_apps_store.dart';
import '../utils/app_localization_strings.dart';
import 'app_icon_button.dart';
import 'sliver_app_top_bar.dart';
Expand Down
7 changes: 0 additions & 7 deletions lib/widgets/material_you_dialog_shape.dart

This file was deleted.

Loading

0 comments on commit 43eb2d9

Please sign in to comment.