Browse Source

Follow system night mode when available

keplyx 1 year ago
parent
commit
9ec986574f
8 changed files with 57 additions and 17 deletions
  1. 2
    6
      App.js
  2. 1
    0
      app.json
  3. 2
    1
      package.json
  4. 38
    7
      screens/SettingsScreen.js
  5. 1
    0
      translations/en.json
  6. 3
    2
      translations/fr.json
  7. 5
    0
      utils/AsyncStorageManager.js
  8. 5
    1
      utils/ThemeManager.js

+ 2
- 6
App.js View File

@@ -42,6 +42,7 @@ export default class App extends React.Component<Props, State> {
42 42
         super();
43 43
         LocaleManager.initTranslations();
44 44
         this.onIntroDone = this.onIntroDone.bind(this);
45
+        SplashScreen.preventAutoHide();
45 46
     }
46 47
 
47 48
     /**
@@ -84,13 +85,9 @@ export default class App extends React.Component<Props, State> {
84 85
 
85 86
     async loadAssetsAsync() {
86 87
         // Wait for custom fonts to be loaded before showing the app
87
-        // console.log("loading Fonts");
88
-        SplashScreen.preventAutoHide();
89
-        // console.log("loading preferences");
90 88
         await AsyncStorageManager.getInstance().loadPreferences();
91 89
         ThemeManager.getInstance().setUpdateThemeCallback(() => this.updateTheme());
92
-        // console.log("loading Expo token");
93
-        await NotificationsManager.initExpoToken();
90
+        // await NotificationsManager.initExpoToken();
94 91
         this.onLoadFinished();
95 92
     }
96 93
 
@@ -122,7 +119,6 @@ export default class App extends React.Component<Props, State> {
122 119
                 isAprilFools={this.state.showAprilFools && !this.state.showIntro}
123 120
             />;
124 121
         } else {
125
-
126 122
             return (
127 123
                 <PaperProvider theme={this.state.currentTheme}>
128 124
                     <NavigationContainer theme={this.state.currentTheme}>

+ 1
- 0
app.json View File

@@ -13,6 +13,7 @@
13 13
     "version": "1.5.2",
14 14
     "orientation": "portrait",
15 15
     "primaryColor": "#be1522",
16
+    "userInterfaceStyle": "automatic",
16 17
     "icon": "./assets/android.icon.png",
17 18
     "splash": {
18 19
       "backgroundColor": "#be1522",

+ 2
- 1
package.json View File

@@ -34,7 +34,8 @@
34 34
     "react-native-render-html": "^4.1.2",
35 35
     "react-native-safe-area-context": "0.6.0",
36 36
     "react-native-screens": "2.0.0-alpha.12",
37
-    "react-native-webview": "7.4.3"
37
+    "react-native-webview": "7.4.3",
38
+    "react-native-appearance": "~0.3.1"
38 39
   },
39 40
   "devDependencies": {
40 41
     "babel-preset-expo": "^8.0.0"

+ 38
- 7
screens/SettingsScreen.js View File

@@ -7,6 +7,7 @@ import i18n from "i18n-js";
7 7
 import AsyncStorageManager from "../utils/AsyncStorageManager";
8 8
 import NotificationsManager from "../utils/NotificationsManager";
9 9
 import {Card, List, Switch, ToggleButton} from 'react-native-paper';
10
+import {Appearance} from "react-native-appearance";
10 11
 
11 12
 type Props = {
12 13
     navigation: Object,
@@ -14,6 +15,7 @@ type Props = {
14 15
 
15 16
 type State = {
16 17
     nightMode: boolean,
18
+    nightModeFollowSystem: boolean,
17 19
     proxiwashNotifPickerSelected: string,
18 20
     startScreenPickerSelected: string,
19 21
 };
@@ -24,6 +26,8 @@ type State = {
24 26
 export default class SettingsScreen extends React.Component<Props, State> {
25 27
     state = {
26 28
         nightMode: ThemeManager.getNightMode(),
29
+        nightModeFollowSystem: AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.current === '1' &&
30
+        Appearance.getColorScheme() !== 'no-preference',
27 31
         proxiwashNotifPickerSelected: AsyncStorageManager.getInstance().preferences.proxiwashNotifications.current,
28 32
         startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current,
29 33
     };
@@ -31,12 +35,14 @@ export default class SettingsScreen extends React.Component<Props, State> {
31 35
     onProxiwashNotifPickerValueChange: Function;
32 36
     onStartScreenPickerValueChange: Function;
33 37
     onToggleNightMode: Function;
38
+    onToggleNightModeFollowSystem: Function;
34 39
 
35 40
     constructor() {
36 41
         super();
37 42
         this.onProxiwashNotifPickerValueChange = this.onProxiwashNotifPickerValueChange.bind(this);
38 43
         this.onStartScreenPickerValueChange = this.onStartScreenPickerValueChange.bind(this);
39 44
         this.onToggleNightMode = this.onToggleNightMode.bind(this);
45
+        this.onToggleNightModeFollowSystem = this.onToggleNightModeFollowSystem.bind(this);
40 46
     }
41 47
 
42 48
     /**
@@ -119,6 +125,18 @@ export default class SettingsScreen extends React.Component<Props, State> {
119 125
         this.setState({nightMode: !this.state.nightMode});
120 126
     }
121 127
 
128
+    onToggleNightModeFollowSystem() {
129
+        const value = !this.state.nightModeFollowSystem;
130
+        this.setState({nightModeFollowSystem: value});
131
+        let key = AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.key;
132
+        AsyncStorageManager.getInstance().savePref(key, value ? '1' : '0');
133
+        if (value) {
134
+            const nightMode = Appearance.getColorScheme() === 'dark';
135
+            ThemeManager.getInstance().setNightMode(nightMode);
136
+            this.setState({nightMode: nightMode});
137
+        }
138
+    }
139
+
122 140
     /**
123 141
      * Get a list item using a checkbox control
124 142
      *
@@ -128,7 +146,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
128 146
      * @param subtitle The text to display as this list item subtitle
129 147
      * @returns {React.Node}
130 148
      */
131
-    getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string) {
149
+    getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string, state: boolean) {
132 150
         return (
133 151
             <List.Item
134 152
                 title={title}
@@ -136,7 +154,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
136 154
                 left={props => <List.Icon {...props} icon={icon}/>}
137 155
                 right={props =>
138 156
                     <Switch
139
-                        value={this.state.nightMode}
157
+                        value={state}
140 158
                         onValueChange={onPressCallback}
141 159
                     />}
142 160
             />
@@ -149,14 +167,27 @@ export default class SettingsScreen extends React.Component<Props, State> {
149 167
                 <Card style={{margin: 5}}>
150 168
                     <Card.Title title={i18n.t('settingsScreen.generalCard')}/>
151 169
                     <List.Section>
152
-                        {this.getToggleItem(
153
-                            this.onToggleNightMode,
170
+                        {Appearance.getColorScheme() !== 'no-preference' ? this.getToggleItem(
171
+                            this.onToggleNightModeFollowSystem,
154 172
                             'theme-light-dark',
155
-                            i18n.t('settingsScreen.nightMode'),
173
+                            i18n.t('settingsScreen.nightModeAuto'),
156 174
                             this.state.nightMode ?
157 175
                                 i18n.t('settingsScreen.nightModeSubOn') :
158
-                                i18n.t('settingsScreen.nightModeSubOff')
159
-                        )}
176
+                                i18n.t('settingsScreen.nightModeSubOff'),
177
+                            this.state.nightModeFollowSystem
178
+                        ) : null}
179
+                        {
180
+                            Appearance.getColorScheme() === 'no-preference' || !this.state.nightModeFollowSystem ?
181
+                            this.getToggleItem(
182
+                                this.onToggleNightMode,
183
+                                'theme-light-dark',
184
+                                i18n.t('settingsScreen.nightMode'),
185
+                                this.state.nightMode ?
186
+                                    i18n.t('settingsScreen.nightModeSubOn') :
187
+                                    i18n.t('settingsScreen.nightModeSubOff'),
188
+                                this.state.nightMode
189
+                            ) : null
190
+                        }
160 191
                         <List.Accordion
161 192
                             title={i18n.t('settingsScreen.startScreen')}
162 193
                             description={i18n.t('settingsScreen.startScreenSub')}

+ 1
- 0
translations/en.json View File

@@ -67,6 +67,7 @@
67 67
     "nightMode": "Night Mode",
68 68
     "nightModeSubOn": "Your eyes are at peace",
69 69
     "nightModeSubOff": "Your eyes are burning",
70
+    "nightModeAuto": "Follow system dark mode",
70 71
     "startScreen": "Start Screen",
71 72
     "startScreenSub": "Select which screen to start the app on",
72 73
     "proxiwashNotifReminder": "Machine running reminder",

+ 3
- 2
translations/fr.json View File

@@ -65,8 +65,9 @@
65 65
   "settingsScreen": {
66 66
     "generalCard": "Général",
67 67
     "nightMode": "Mode Nuit",
68
-    "nightModeSubOn": "Vos yeux brulent",
69
-    "nightModeSubOff": "Vos yeux vous remercient",
68
+    "nightModeSubOn": "Vos yeux vous remercient",
69
+    "nightModeSubOff": "Vos yeux brulent",
70
+    "nightModeAuto": "Mode nuit système",
70 71
     "startScreen": "Écran de démarrage",
71 72
     "startScreenSub": "Choisissez l'écran utilisé au démarrage",
72 73
     "proxiwashNotifReminder": "Rappel de machine en cours",

+ 5
- 0
utils/AsyncStorageManager.js View File

@@ -44,6 +44,11 @@ export default class AsyncStorageManager {
44 44
             default: '[]',
45 45
             current: '',
46 46
         },
47
+        nightModeFollowSystem: {
48
+            key: 'nightModeFollowSystem',
49
+            default: '1',
50
+            current: '',
51
+        },
47 52
         nightMode: {
48 53
             key: 'nightMode',
49 54
             default: '0',

+ 5
- 1
utils/ThemeManager.js View File

@@ -3,6 +3,9 @@
3 3
 import AsyncStorageManager from "./AsyncStorageManager";
4 4
 import {DarkTheme, DefaultTheme} from 'react-native-paper';
5 5
 import AprilFoolsManager from "./AprilFoolsManager";
6
+import { Appearance } from 'react-native-appearance';
7
+
8
+const colorScheme = Appearance.getColorScheme();
6 9
 
7 10
 /**
8 11
  * Singleton class used to manage themes
@@ -107,7 +110,8 @@ export default class ThemeManager {
107 110
      * @returns {boolean} Night mode state
108 111
      */
109 112
     static getNightMode(): boolean {
110
-        return AsyncStorageManager.getInstance().preferences.nightMode.current === '1';
113
+        return AsyncStorageManager.getInstance().preferences.nightMode.current === '1' ||
114
+            AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.current === '1' && colorScheme === 'dark';
111 115
     }
112 116
 
113 117
     /**

Loading…
Cancel
Save