Skip to content

Commit 827528b

Browse files
committed
Added Theming + License page.
Added the ability to select a Theme. During that process the nav bar was rewritten to ensure it properly uses the theme colors. This is also true for the card with buttons. Additionally, moved the privacy/impressum to the drawer and added a View Licence Page to the settings.
1 parent 6be5919 commit 827528b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1047
-370
lines changed

assets/images/RR-Icon_Black.png

31.9 KB
Loading

assets/images/RR-Icon_Green.png

31.1 KB
Loading

google_fonts/NotoSans-Black.ttf

543 KB
Binary file not shown.

google_fonts/NotoSans-BlackItalic.ttf

394 KB
Binary file not shown.

google_fonts/NotoSans-Bold.ttf

544 KB
Binary file not shown.

google_fonts/NotoSans-BoldItalic.ttf

392 KB
Binary file not shown.

google_fonts/NotoSans-ExtraBold.ttf

544 KB
Binary file not shown.
392 KB
Binary file not shown.

google_fonts/NotoSans-ExtraLight.ttf

546 KB
Binary file not shown.
398 KB
Binary file not shown.

google_fonts/NotoSans-Italic.ttf

394 KB
Binary file not shown.

google_fonts/NotoSans-Light.ttf

542 KB
Binary file not shown.

google_fonts/NotoSans-LightItalic.ttf

396 KB
Binary file not shown.

google_fonts/NotoSans-Medium.ttf

542 KB
Binary file not shown.
393 KB
Binary file not shown.

google_fonts/NotoSans-Regular.ttf

543 KB
Binary file not shown.

google_fonts/NotoSans-SemiBold.ttf

544 KB
Binary file not shown.
392 KB
Binary file not shown.

google_fonts/NotoSans-Thin.ttf

548 KB
Binary file not shown.

google_fonts/NotoSans-ThinItalic.ttf

400 KB
Binary file not shown.

google_fonts/OFL.txt

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
Copyright 2015-2021 Google LLC. All Rights Reserved.
2+
3+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
4+
This license is copied below, and is also available with a FAQ at:
5+
http://scripts.sil.org/OFL
6+
7+
8+
-----------------------------------------------------------
9+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10+
-----------------------------------------------------------
11+
12+
PREAMBLE
13+
The goals of the Open Font License (OFL) are to stimulate worldwide
14+
development of collaborative font projects, to support the font creation
15+
efforts of academic and linguistic communities, and to provide a free and
16+
open framework in which fonts may be shared and improved in partnership
17+
with others.
18+
19+
The OFL allows the licensed fonts to be used, studied, modified and
20+
redistributed freely as long as they are not sold by themselves. The
21+
fonts, including any derivative works, can be bundled, embedded,
22+
redistributed and/or sold with any software provided that any reserved
23+
names are not used by derivative works. The fonts and derivatives,
24+
however, cannot be released under any other type of license. The
25+
requirement for fonts to remain under this license does not apply
26+
to any document created using the fonts or their derivatives.
27+
28+
DEFINITIONS
29+
"Font Software" refers to the set of files released by the Copyright
30+
Holder(s) under this license and clearly marked as such. This may
31+
include source files, build scripts and documentation.
32+
33+
"Reserved Font Name" refers to any names specified as such after the
34+
copyright statement(s).
35+
36+
"Original Version" refers to the collection of Font Software components as
37+
distributed by the Copyright Holder(s).
38+
39+
"Modified Version" refers to any derivative made by adding to, deleting,
40+
or substituting -- in part or in whole -- any of the components of the
41+
Original Version, by changing formats or by porting the Font Software to a
42+
new environment.
43+
44+
"Author" refers to any designer, engineer, programmer, technical
45+
writer or other person who contributed to the Font Software.
46+
47+
PERMISSION & CONDITIONS
48+
Permission is hereby granted, free of charge, to any person obtaining
49+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
50+
redistribute, and sell modified and unmodified copies of the Font
51+
Software, subject to the following conditions:
52+
53+
1) Neither the Font Software nor any of its individual components,
54+
in Original or Modified Versions, may be sold by itself.
55+
56+
2) Original or Modified Versions of the Font Software may be bundled,
57+
redistributed and/or sold with any software, provided that each copy
58+
contains the above copyright notice and this license. These can be
59+
included either as stand-alone text files, human-readable headers or
60+
in the appropriate machine-readable metadata fields within text or
61+
binary files as long as those fields can be easily viewed by the user.
62+
63+
3) No Modified Version of the Font Software may use the Reserved Font
64+
Name(s) unless explicit written permission is granted by the corresponding
65+
Copyright Holder. This restriction only applies to the primary font name as
66+
presented to the users.
67+
68+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69+
Software shall not be used to promote, endorse or advertise any
70+
Modified Version, except to acknowledge the contribution(s) of the
71+
Copyright Holder(s) and the Author(s) or with their explicit written
72+
permission.
73+
74+
5) The Font Software, modified or unmodified, in part or in whole,
75+
must be distributed entirely under this license, and must not be
76+
distributed under any other license. The requirement for fonts to
77+
remain under this license does not apply to any document created
78+
using the Font Software.
79+
80+
TERMINATION
81+
This license becomes null and void if any of the above conditions are
82+
not met.
83+
84+
DISCLAIMER
85+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93+
OTHER DEALINGS IN THE FONT SOFTWARE.

lib/app/app_setup.dart

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import 'dart:io';
22

33
import 'package:flutter/foundation.dart';
4+
import 'package:flutter/services.dart';
45
import 'package:hive_flutter/hive_flutter.dart';
56
import 'package:mobileraker/datasource/moonraker_database_client.dart';
67
import 'package:mobileraker/domain/hive/gcode_macro.dart';
7-
import 'package:mobileraker/domain/hive/macro_group.dart';
88
import 'package:mobileraker/domain/hive/machine.dart';
9+
import 'package:mobileraker/domain/hive/macro_group.dart';
910
import 'package:mobileraker/domain/hive/temperature_preset.dart';
1011
import 'package:mobileraker/domain/hive/webcam_setting.dart';
1112
import 'package:mobileraker/repository/machine_hive_repository.dart';
@@ -113,3 +114,10 @@ Future<void> setupCat() async {
113114
return Purchases.setup('goog_uzbmaMIthLRzhDyQpPsmvOXbaCK');
114115
}
115116
}
117+
118+
setupLicenseRegistry() {
119+
LicenseRegistry.addLicense(() async* {
120+
final license = await rootBundle.loadString('google_fonts/OFL.txt');
121+
yield LicenseEntryWithLineBreaks(['google_fonts'], license);
122+
});
123+
}

lib/main.dart

+26-20
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ import 'package:mobileraker/service/notification_service.dart';
1212
import 'package:mobileraker/ui/components/bottomsheet/setup_bottom_sheet_ui.dart';
1313
import 'package:mobileraker/ui/components/dialog/setup_dialog_ui.dart';
1414
import 'package:mobileraker/ui/components/snackbar/setup_snackbar.dart';
15+
import 'package:mobileraker/ui/components/theme_builder.dart';
1516
import 'package:mobileraker/ui/theme_setup.dart';
1617
import 'package:mobileraker/util/misc.dart';
1718
import 'package:stacked_services/stacked_services.dart';
1819

1920
import 'app/app_setup.router.dart';
20-
import 'service/setting_service.dart';
21-
import 'ui/views/setting/setting_viewmodel.dart';
2221

2322
String? initialRoute;
2423

@@ -37,7 +36,9 @@ Future<void> main() async {
3736
setupBottomSheetUi();
3837
await FirebaseAnalytics.instance.logAppOpen();
3938
await setupCat();
39+
setupLicenseRegistry();
4040
initialRoute = await selectInitialRoute();
41+
4142
runApp(EasyLocalization(
4243
child: MyApp(),
4344
supportedLocales: [Locale('en'), Locale('de')],
@@ -48,27 +49,32 @@ Future<void> main() async {
4849
}
4950

5051
class MyApp extends StatelessWidget {
51-
5252
// This widget is the root of your application.
5353
@override
5454
Widget build(BuildContext context) {
55-
return MaterialApp(
56-
title: 'Mobileraker',
57-
theme: getLightTheme(context),
58-
darkTheme: getDarkTheme(context),
59-
navigatorKey: StackedService.navigatorKey,
60-
onGenerateRoute: StackedRouter().onGenerateRoute,
61-
initialRoute: initialRoute,
62-
localizationsDelegates: [
63-
FormBuilderLocalizations.delegate,
64-
...context.localizationDelegates
65-
],
66-
supportedLocales: context.supportedLocales,
67-
locale: context.locale,
68-
navigatorObservers: [
69-
StackedService.routeObserver,
70-
FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance),
71-
],
55+
return ThemeBuilder(
56+
themePacks: getThemePacks(context),
57+
builder: (BuildContext context,ThemeData? regularTheme,ThemeData? darkTheme,ThemeMode? themeMode) {
58+
return MaterialApp(
59+
title: 'Mobileraker',
60+
theme: regularTheme,
61+
darkTheme: darkTheme,
62+
themeMode: themeMode,
63+
navigatorKey: StackedService.navigatorKey,
64+
onGenerateRoute: StackedRouter().onGenerateRoute,
65+
initialRoute: initialRoute,
66+
localizationsDelegates: [
67+
FormBuilderLocalizations.delegate,
68+
...context.localizationDelegates
69+
],
70+
supportedLocales: context.supportedLocales,
71+
locale: context.locale,
72+
navigatorObservers: [
73+
StackedService.routeObserver,
74+
FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance),
75+
],
76+
);
77+
},
7278
);
7379
}
7480
}

lib/service/setting_service.dart

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const String emsKey = 'ems_setting';
44
const String showBabyAlwaysKey = 'always_babystepping_setting';
55
const String useTextInputForNumKey = 'text_inpt_for_num_fields';
66
const String startWithOverviewKey = 'start_with_overview';
7+
const String selectedThemePackKey = 'selectedThemePack';
78

89
/// Settings related to the App!
910
class SettingService {
@@ -16,4 +17,12 @@ class SettingService {
1617
bool readBool(String key, [bool fallback = false]) {
1718
return _boxSettings.get(key) ?? fallback;
1819
}
20+
21+
Future<void> writeInt(String key, int val) {
22+
return _boxSettings.put(key, val);
23+
}
24+
25+
int readInt(String key, [int fallback = 0]) {
26+
return _boxSettings.get(key) ?? fallback;
27+
}
1928
}

lib/service/ui/theme_service.dart

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import 'dart:math';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:mobileraker/app/app_setup.locator.dart';
5+
import 'package:mobileraker/service/setting_service.dart';
6+
import 'package:mobileraker/ui/themes/theme_pack.dart';
7+
import 'package:provider/provider.dart';
8+
import 'package:rxdart/subjects.dart';
9+
10+
class ThemeService {
11+
ThemeService({required this.themePacks}) {
12+
assert(themePacks.isNotEmpty, 'No ThemePacks provided!');
13+
int themeIndex = min(_settingService.readInt(selectedThemePackKey), themePacks.length-1);
14+
_initialTheme = ThemeModel(themePacks[themeIndex], selectedMode);
15+
_themesController = BehaviorSubject.seeded(_initialTheme);
16+
}
17+
18+
final _settingService = locator<SettingService>();
19+
20+
late final ThemeModel _initialTheme;
21+
final List<ThemePack> themePacks;
22+
23+
ThemeModel get initalTheme => _initialTheme;
24+
25+
ThemeMode selectedMode = ThemeMode.system;
26+
27+
Stream<ThemeModel> get themesStream => _themesController.stream;
28+
late BehaviorSubject<ThemeModel> _themesController;
29+
30+
ThemePack get selectedThemePack => _themesController.value.themePack;
31+
32+
ThemeData get selectedTheme => selectedThemePack.lightTheme;
33+
34+
bool get isDarkMode => selectedMode == ThemeMode.dark;
35+
36+
bool get isLightMode => selectedMode == ThemeMode.light;
37+
38+
selectThemePack(ThemePack themePack) {
39+
_themesController.add(ThemeModel(themePack, selectedMode));
40+
_settingService.writeInt(selectedThemePackKey, themePacks.indexOf(themePack));
41+
}
42+
}
43+
44+
45+
extension ThemeServiceContext on BuildContext {
46+
ThemeService get themeService => Provider.of<ThemeService>(this, listen: false);
47+
}
48+
49+
@immutable
50+
class ThemeModel {
51+
ThemeModel(this.themePack, this.themeMode);
52+
53+
final ThemePack themePack;
54+
final ThemeMode themeMode;
55+
}

lib/ui/components/bottomsheet/setup_bottom_sheet_ui.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class _NonPrintingBottomSheet
4747
return Container(
4848
padding: const EdgeInsets.fromLTRB(25, 15, 25, 10),
4949
decoration: BoxDecoration(
50-
color: isDark ? themeData.primaryColor : Colors.white,
50+
color: themeData.bottomSheetTheme.modalBackgroundColor,
5151
borderRadius: BorderRadius.only(
5252
topLeft: Radius.circular(15), topRight: Radius.circular(15)),
5353
),

lib/ui/components/card_with_button.dart

+33-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flex_color_scheme/flex_color_scheme.dart';
12
import 'package:flutter/material.dart';
23

34
class CardWithButton extends StatelessWidget {
@@ -14,12 +15,21 @@ class CardWithButton extends StatelessWidget {
1415

1516
final double width;
1617
final Color? backgroundColor;
17-
final Widget child;
18+
final Builder child;
1819
final Widget buttonChild;
1920
final VoidCallback? onTap;
2021

2122
@override
2223
Widget build(BuildContext context) {
24+
var themeData = Theme.of(context);
25+
var _backgroundColor =
26+
backgroundColor ?? themeData.colorScheme.surfaceVariant;
27+
var _onBackgroundColor = (ThemeData.estimateBrightnessForColor(_backgroundColor) ==
28+
Brightness.dark
29+
? Colors.white.blendAlpha(themeData.colorScheme.primary.brighten(20), 0)
30+
: Colors.black
31+
.blendAlpha(themeData.colorScheme.primary.brighten(20), 0));
32+
2333
return Container(
2434
width: width,
2535
padding: CardTheme.of(context).margin ?? const EdgeInsets.all(4),
@@ -29,23 +39,36 @@ class CardWithButton extends StatelessWidget {
2939
Container(
3040
alignment: Alignment.centerLeft,
3141
decoration: BoxDecoration(
32-
color: backgroundColor ?? Theme.of(context).primaryColorLight,
42+
color: _backgroundColor,
3343
borderRadius:
3444
BorderRadius.vertical(top: Radius.circular(radius))),
3545
child: Padding(
3646
padding: const EdgeInsets.fromLTRB(12, 18, 12, 12),
37-
child: child,
47+
child: Theme(
48+
data: themeData.copyWith(
49+
textTheme: themeData.textTheme.apply(
50+
bodyColor: _onBackgroundColor, displayColor: _onBackgroundColor),
51+
iconTheme:
52+
themeData.iconTheme.copyWith(color: _onBackgroundColor)),
53+
child: DefaultTextStyle(
54+
style: TextStyle(color: _onBackgroundColor),
55+
child: child,
56+
)),
3857
),
3958
),
4059
TextButton(
4160
style: TextButton.styleFrom(
42-
primary: Colors.white,
43-
backgroundColor: Theme.of(context).primaryColor,
44-
minimumSize: const Size.fromHeight(48),
45-
padding: EdgeInsets.zero,
46-
shape: RoundedRectangleBorder(
47-
borderRadius: BorderRadius.vertical(bottom: Radius.circular(radius)),
48-
)),
61+
minimumSize: const Size.fromHeight(48),
62+
padding: EdgeInsets.zero,
63+
shape: RoundedRectangleBorder(
64+
borderRadius:
65+
BorderRadius.vertical(bottom: Radius.circular(radius)),
66+
),
67+
primary: themeData.colorScheme.onPrimary,
68+
backgroundColor: themeData.colorScheme.primary,
69+
// onPrimary: Theme.of(context).colorScheme.onSecondary,
70+
onSurface: themeData.colorScheme.onPrimary,
71+
),
4972
child: buttonChild,
5073
onPressed: onTap,
5174
)

0 commit comments

Comments
 (0)