Skip to content
This repository has been archived by the owner on Aug 9, 2023. It is now read-only.

Commit

Permalink
Adding theme picker, fixes #55
Browse files Browse the repository at this point in the history
  • Loading branch information
sterrenb committed May 14, 2020
1 parent 340b341 commit 30745d4
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 34 deletions.
6 changes: 5 additions & 1 deletion lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@ class KIcons {
static const IconData sleep = MaterialCommunityIcons.sleep;
static const IconData wake = MaterialCommunityIcons.bell_ring;

static const IconData summary = Ionicons.md_stats;
static const IconData themeSystem = Feather.sunrise;
static const IconData themeLight = Feather.sun;
static const IconData themeDark = Feather.moon;


static const IconData dashboard = MaterialCommunityIcons.view_dashboard;
static const IconData clients = MaterialCommunityIcons.laptop_windows;
static const IconData domains =
MaterialCommunityIcons.checkbox_multiple_blank_circle_outline;
static const IconData summary = Ionicons.md_stats;
static const IconData permittedDomains = Icons.check;
static const IconData blockedDomains = Icons.close;
static const IconData manyQueriesLive = MaterialIcons.view_stream;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,17 @@ extension DateTimeWithRelative on DateTime {

String get formattedTime => Jiffy(this).format('h:mm:ss a');
}

extension StringExtension on String {
String get capitalize {
if (this == null) {
throw ArgumentError("this: $this");
}

if (this.isEmpty) {
return this;
}

return this[0].toUpperCase() + this.substring(1);
}
}
3 changes: 1 addition & 2 deletions lib/features/pihole_api/data/models/over_time_data.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import 'package:flutter/foundation.dart';
import 'package:flutterhole/features/pihole_api/data/models/convert.dart';
import 'package:flutterhole/core/convert.dart';
import 'package:flutterhole/features/pihole_api/data/models/model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'over_time_data.freezed.dart';

part 'over_time_data.g.dart';

Map<DateTime, int> _valueToDatesOverTime(dynamic value) {
Expand Down
2 changes: 1 addition & 1 deletion lib/features/pihole_api/data/models/query_data.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutterhole/features/pihole_api/data/models/convert.dart';
import 'package:flutterhole/core/convert.dart';
import 'package:flutterhole/features/pihole_api/data/models/model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterhole/constants.dart';
import 'package:flutterhole/core/convert.dart';
import 'package:flutterhole/dependency_injection.dart';
import 'package:flutterhole/features/pihole_api/blocs/pi_connection_bloc.dart';
import 'package:flutterhole/features/pihole_api/data/models/convert.dart';
import 'package:flutterhole/features/pihole_api/data/models/pi_status.dart';
import 'package:flutterhole/features/pihole_api/data/models/toggle_status.dart';
import 'package:flutterhole/widgets/layout/timer_builder.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutterhole/constants.dart';
import 'package:flutterhole/features/pihole_api/data/models/convert.dart';
import 'package:flutterhole/core/convert.dart';
import 'package:flutterhole/features/pihole_api/data/models/query_data.dart';

IconData _queryStatusToIconData(QueryStatus queryStatus) {
Expand Down
1 change: 1 addition & 0 deletions lib/features/routing/services/router_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ abstract class RouterService {
static const String home = '/';
static const String settings = '/settings';
static const String allPiholes = '/all-piholes';
static const String userPreferences = '/user-preferences';
static const String log = '/log';
static const String about = '/about';
static const String privacy = '/privacy';
Expand Down
6 changes: 6 additions & 0 deletions lib/features/routing/services/router_service_sailor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutterhole/features/routing/presentation/pages/about_page.dart'
import 'package:flutterhole/features/routing/services/router_service.dart';
import 'package:flutterhole/features/settings/presentation/pages/all_pihole_settings_page.dart';
import 'package:flutterhole/features/settings/presentation/pages/settings_page.dart';
import 'package:flutterhole/features/settings/presentation/pages/user_preferences_page.dart';
import 'package:injectable/injectable.dart';
import 'package:sailor/sailor.dart';

Expand Down Expand Up @@ -41,6 +42,11 @@ class RouterServiceSailor implements RouterService {
builder: (context, args, params) {
return AllPiholeSettingsPage();
}),
SailorRoute(
name: RouterService.userPreferences,
builder: (context, args, params) {
return UserPreferencesPage();
}),
SailorRoute(
name: RouterService.about,
builder: (context, args, params) {
Expand Down
8 changes: 7 additions & 1 deletion lib/features/settings/presentation/blocs/settings_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:dartz/dartz.dart';
import 'package:flutter/foundation.dart';
import 'package:flutterhole/core/models/failures.dart';
import 'package:flutterhole/dependency_injection.dart';
import 'package:flutterhole/features/pihole_api/blocs/pi_connection_bloc.dart';
import 'package:flutterhole/features/settings/data/models/pihole_settings.dart';
import 'package:flutterhole/features/settings/data/repositories/settings_repository.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
Expand Down Expand Up @@ -51,9 +52,13 @@ abstract class SettingsEvent with _$SettingsEvent {
class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
SettingsBloc([
SettingsRepository settingsRepository,
]) : _settingsRepository = settingsRepository ?? getIt<SettingsRepository>();
PiConnectionBloc piConnectionBloc,
])
: _settingsRepository = settingsRepository ?? getIt<SettingsRepository>(),
_piConnectionBloc = piConnectionBloc ?? getIt<PiConnectionBloc>();

final SettingsRepository _settingsRepository;
final PiConnectionBloc _piConnectionBloc;

@override
SettingsState get initialState => SettingsStateInitial();
Expand Down Expand Up @@ -133,6 +138,7 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
yield SettingsStateFailure(failure);
},
(success) async* {
_piConnectionBloc.add(PiConnectionEvent.ping());
yield* _init();
},
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutterhole/dependency_injection.dart';
import 'package:flutterhole/features/settings/services/preference_service.dart';

class ThemeModeNotifier extends ChangeNotifier {
ThemeMode _themeMode = getIt<PreferenceService>().get(KPrefs.activeThemeMode);

ThemeMode get themeMode => _themeMode;

void update() {
_themeMode = getIt<PreferenceService>().get(KPrefs.activeThemeMode);
print('returning $_themeMode');
notifyListeners();
}
}
12 changes: 10 additions & 2 deletions lib/features/settings/presentation/pages/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:flutterhole/constants.dart';
import 'package:flutterhole/dependency_injection.dart';
import 'package:flutterhole/features/routing/presentation/widgets/default_drawer.dart';
import 'package:flutterhole/features/routing/services/router_service.dart';
import 'package:flutterhole/features/settings/presentation/pages/user_preferences_page.dart';
import 'package:flutterhole/features/settings/presentation/widgets/pihole_theme_builder.dart';

class SettingsPage extends StatelessWidget {
Expand All @@ -17,7 +16,7 @@ class SettingsPage extends StatelessWidget {
),
body: ListView(
children: <Widget>[
UserPreferencesListTile(),
// UserPreferencesListTile(),
ListTile(
title: Text('My Piholes'),
leading: Icon(KIcons.pihole),
Expand All @@ -26,6 +25,15 @@ class SettingsPage extends StatelessWidget {
getIt<RouterService>().push(RouterService.allPiholes);
},
),
ListTile(
title: Text('Preferences'),
leading: Icon(KIcons.preferences),
trailing: Icon(KIcons.open),
onTap: () {
getIt<RouterService>().push(RouterService.userPreferences);
},
),

],
),
),
Expand Down
100 changes: 99 additions & 1 deletion lib/features/settings/presentation/pages/user_preferences_page.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,120 @@
import 'package:flutter/material.dart';
import 'package:flutterhole/constants.dart';
import 'package:flutterhole/core/convert.dart';
import 'package:flutterhole/features/settings/presentation/notifiers/theme_mode_notifier.dart';
import 'package:flutterhole/features/settings/presentation/widgets/pihole_theme_builder.dart';
import 'package:flutterhole/features/settings/services/preference_service.dart';
import 'package:flutterhole/widgets/layout/list_title.dart';
import 'package:preferences/preferences.dart';
import 'package:provider/provider.dart';

class UserPreferencesListTile extends StatelessWidget {
class UserPreferencesPage extends StatefulWidget {
@override
_UserPreferencesPageState createState() => _UserPreferencesPageState();
}

class _UserPreferencesPageState extends State<UserPreferencesPage> {
void _onThemeSelect() {
Provider.of<ThemeModeNotifier>(context, listen: false).update();
}

@override
Widget build(BuildContext context) {
return PiholeThemeBuilder(
child: Scaffold(
appBar: AppBar(
title: Text('Preferences'),
),
body: ListView(
children: <Widget>[
ListTitle('Customization'),
RadioPreference(
'${ThemeModeEnumMap[ThemeMode.system].capitalize} theme',
'${ThemeModeEnumMap[ThemeMode.system]}',
KPrefs.activeThemeMode,
isDefault: true,
onSelect: _onThemeSelect,
leading: Icon(KIcons.themeSystem),
),
RadioPreference(
'${ThemeModeEnumMap[ThemeMode.light].capitalize} theme',
'${ThemeModeEnumMap[ThemeMode.light]}',
KPrefs.activeThemeMode,
onSelect: _onThemeSelect,
leading: Icon(KIcons.themeLight),
),
RadioPreference(
'${ThemeModeEnumMap[ThemeMode.dark].capitalize} theme',
'${ThemeModeEnumMap[ThemeMode.dark]}',
KPrefs.activeThemeMode,
onSelect: _onThemeSelect,
leading: Icon(KIcons.themeDark),
),
ListTitle('Data'),
SwitchPreference(
'Use numbers API',
KPrefs.useNumbersApi,
defaultVal: true,
desc:
'If enabled, the dashboard will fetch number trivia from the Numbers API.',
),
],
),
),
);
}
}

class UserPreferencesListTile extends StatefulWidget {
const UserPreferencesListTile({
Key key,
}) : super(key: key);

@override
_UserPreferencesListTileState createState() =>
_UserPreferencesListTileState();
}

class _UserPreferencesListTileState extends State<UserPreferencesListTile> {
void _onThemeSelect() {
Provider.of<ThemeModeNotifier>(context, listen: false).update();
}

@override
Widget build(BuildContext context) {
return PreferencePageLink(
'Preferences',
page: PreferencePage([
PreferenceTitle('Theme'),
RadioPreference(
'${ThemeModeEnumMap[ThemeMode.system].capitalize} theme',
'${ThemeModeEnumMap[ThemeMode.system]}',
KPrefs.activeThemeMode,
isDefault: true,
onSelect: _onThemeSelect,
leading: Icon(KIcons.themeSystem),
),
RadioPreference(
'${ThemeModeEnumMap[ThemeMode.light].capitalize} theme',
'${ThemeModeEnumMap[ThemeMode.light]}',
KPrefs.activeThemeMode,
onSelect: _onThemeSelect,
leading: Icon(KIcons.themeLight),
),
RadioPreference(
'${ThemeModeEnumMap[ThemeMode.dark].capitalize} theme',
'${ThemeModeEnumMap[ThemeMode.dark]}',
KPrefs.activeThemeMode,
onSelect: _onThemeSelect,
leading: Icon(KIcons.themeDark),
),
PreferenceTitle('Data'),
SwitchPreference(
'Use numbers API',
KPrefs.useNumbersApi,
defaultVal: true,
desc:
'If enabled, the dashboard will fetch number trivia from the Numbers API.',
),
]),
leading: Icon(KIcons.preferences),
Expand Down
38 changes: 28 additions & 10 deletions lib/features/settings/services/preference_service.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
import 'package:flutter/material.dart';
import 'package:flutterhole/core/models/exceptions.dart';
import 'package:injectable/injectable.dart';
import 'package:preferences/preferences.dart';

enum Pref {
enum PrefType {
string,
bool,
int,
double,
stringList,
themeMode,
}

class KPrefs {
KPrefs._();

static const String useNumbersApi = 'useNumbersApi';
static const String activeThemeMode = 'themeMode';

static const Map<String, Pref> prefs = {
useNumbersApi: Pref.bool,
static const Map<String, PrefType> prefs = {
useNumbersApi: PrefType.bool,
activeThemeMode: PrefType.themeMode,
};
}

const ThemeModeEnumMap = {
ThemeMode.system: 'system',
ThemeMode.light: 'light',
ThemeMode.dark: 'dark',
};

const ThemeModeMapEnum = {
'system': ThemeMode.system,
'light': ThemeMode.light,
'dark': ThemeMode.dark,
};

@prod
@preResolve
@singleton
Expand All @@ -36,22 +52,24 @@ class PreferenceService {
if (type == null) throw PiException.notFound();

switch (type) {
case Pref.string:
case PrefType.string:
return PrefService.getString(key);
case Pref.bool:
case PrefType.bool:
return PrefService.getBool(key);

case Pref.int:
case PrefType.int:
return PrefService.getInt(key);

case Pref.double:
case PrefType.double:
return PrefService.getDouble(key);

case Pref.stringList:
case PrefType.stringList:
return PrefService.getStringList(key);
case PrefType.themeMode:
final String value = PrefService.getString(key) ?? 'system';
// print('returning ${ThemeModeMapEnum[value]} for $key, $value');

default:
return PrefService.get(key);
return ThemeModeMapEnum[value];
}
}
}

0 comments on commit 30745d4

Please sign in to comment.