1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-02 12:47:41 +02:00

Mobile: Resolves #8490: Add option to autodetect theme (#8498)

This commit is contained in:
Henry Heino 2023-07-18 06:46:11 -07:00 committed by GitHub
parent 4e1ee87269
commit 9c8fbe831f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 8 deletions

View File

@ -443,6 +443,7 @@ packages/app-mobile/tools/buildInjectedJs.js
packages/app-mobile/utils/ShareExtension.js packages/app-mobile/utils/ShareExtension.js
packages/app-mobile/utils/ShareUtils.js packages/app-mobile/utils/ShareUtils.js
packages/app-mobile/utils/TlsUtils.js packages/app-mobile/utils/TlsUtils.js
packages/app-mobile/utils/autodetectTheme.js
packages/app-mobile/utils/checkPermissions.js packages/app-mobile/utils/checkPermissions.js
packages/app-mobile/utils/createRootStyle.js packages/app-mobile/utils/createRootStyle.js
packages/app-mobile/utils/debounce.js packages/app-mobile/utils/debounce.js

1
.gitignore vendored
View File

@ -428,6 +428,7 @@ packages/app-mobile/tools/buildInjectedJs.js
packages/app-mobile/utils/ShareExtension.js packages/app-mobile/utils/ShareExtension.js
packages/app-mobile/utils/ShareUtils.js packages/app-mobile/utils/ShareUtils.js
packages/app-mobile/utils/TlsUtils.js packages/app-mobile/utils/TlsUtils.js
packages/app-mobile/utils/autodetectTheme.js
packages/app-mobile/utils/checkPermissions.js packages/app-mobile/utils/checkPermissions.js
packages/app-mobile/utils/createRootStyle.js packages/app-mobile/utils/createRootStyle.js
packages/app-mobile/utils/debounce.js packages/app-mobile/utils/debounce.js

View File

@ -15,7 +15,7 @@ interface FolderPickerProps {
folders: FolderEntity[]; folders: FolderEntity[];
placeholder?: string; placeholder?: string;
darkText?: boolean; darkText?: boolean;
themeId?: string; themeId?: number;
} }

View File

@ -86,6 +86,7 @@ interface ScreenHeaderProps {
shouldUpgradeSyncTarget?: boolean; shouldUpgradeSyncTarget?: boolean;
showShouldUpgradeSyncTargetMessage?: boolean; showShouldUpgradeSyncTargetMessage?: boolean;
themeId: number;
} }
interface ScreenHeaderState { interface ScreenHeaderState {
@ -100,7 +101,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
} }
private styles() { private styles() {
const themeId = Setting.value('theme'); const themeId = this.props.themeId;
if (this.cachedStyles[themeId]) return this.cachedStyles[themeId]; if (this.cachedStyles[themeId]) return this.cachedStyles[themeId];
this.cachedStyles = {}; this.cachedStyles = {};
@ -297,7 +298,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
} }
public render() { public render() {
const themeId = Setting.value('theme'); const themeId = this.props.themeId;
function sideMenuButton(styles: any, onPress: OnPressCallback) { function sideMenuButton(styles: any, onPress: OnPressCallback) {
return ( return (
<TouchableOpacity <TouchableOpacity

View File

@ -104,7 +104,7 @@
<string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationPortraitUpsideDown</string>
</array> </array>
<key>UIUserInterfaceStyle</key> <key>UIUserInterfaceStyle</key>
<string>Light</string> <string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>NSFaceIDUsageDescription</key> <key>NSFaceIDUsageDescription</key>

View File

@ -29,7 +29,7 @@ import SyncTargetOneDrive from '@joplin/lib/SyncTargetOneDrive';
import initProfile from '@joplin/lib/services/profileConfig/initProfile'; import initProfile from '@joplin/lib/services/profileConfig/initProfile';
const VersionInfo = require('react-native-version-info').default; const VersionInfo = require('react-native-version-info').default;
const { Keyboard, BackHandler, View, StatusBar, Platform, Dimensions } = require('react-native'); const { Keyboard, BackHandler, View, StatusBar, Platform, Dimensions } = require('react-native');
import { AppState as RNAppState, EmitterSubscription, Linking, NativeEventSubscription } from 'react-native'; import { AppState as RNAppState, EmitterSubscription, Linking, NativeEventSubscription, Appearance } from 'react-native';
import getResponsiveValue from './components/getResponsiveValue'; import getResponsiveValue from './components/getResponsiveValue';
import NetInfo from '@react-native-community/netinfo'; import NetInfo from '@react-native-community/netinfo';
const DropdownAlert = require('react-native-dropdownalert').default; const DropdownAlert = require('react-native-dropdownalert').default;
@ -118,6 +118,7 @@ import { getCurrentProfile } from '@joplin/lib/services/profileConfig';
import { getDatabaseName, getProfilesRootDir, getResourceDir, setDispatch } from './services/profiles'; import { getDatabaseName, getProfilesRootDir, getResourceDir, setDispatch } from './services/profiles';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { parseShareCache } from '@joplin/lib/services/share/reducer'; import { parseShareCache } from '@joplin/lib/services/share/reducer';
import autodetectTheme, { onSystemColorSchemeChange } from './utils/autodetectTheme';
type SideMenuPosition = 'left' | 'right'; type SideMenuPosition = 'left' | 'right';
@ -186,6 +187,14 @@ const generalMiddleware = (store: any) => (next: any) => async (action: any) =>
void reg.scheduleSync(null, null, true); void reg.scheduleSync(null, null, true);
} }
if (
action.type === 'AUTODETECT_THEME'
|| action.type === 'SETTING_UPDATE_ALL'
|| (action.type === 'SETTING_UPDATE_ONE' && ['themeAutoDetect', 'preferredLightTheme', 'preferredDarkTheme'].includes(action.key))
) {
autodetectTheme();
}
if (action.type === 'NAV_GO' && action.routeName === 'Notes') { if (action.type === 'NAV_GO' && action.routeName === 'Notes') {
Setting.setValue('activeFolderId', newState.selectedFolderId); Setting.setValue('activeFolderId', newState.selectedFolderId);
} }
@ -712,6 +721,7 @@ class AppComponent extends React.Component {
private urlOpenListener_: EmitterSubscription|null = null; private urlOpenListener_: EmitterSubscription|null = null;
private appStateChangeListener_: NativeEventSubscription|null = null; private appStateChangeListener_: NativeEventSubscription|null = null;
private themeChangeListener_: NativeEventSubscription|null = null;
public constructor() { public constructor() {
super(); super();
@ -849,6 +859,11 @@ class AppComponent extends React.Component {
this.appStateChangeListener_ = RNAppState.addEventListener('change', this.onAppStateChange_); this.appStateChangeListener_ = RNAppState.addEventListener('change', this.onAppStateChange_);
this.unsubscribeScreenWidthChangeHandler_ = Dimensions.addEventListener('change', this.handleScreenWidthChange_); this.unsubscribeScreenWidthChangeHandler_ = Dimensions.addEventListener('change', this.handleScreenWidthChange_);
this.themeChangeListener_ = Appearance.addChangeListener(
({ colorScheme }) => onSystemColorSchemeChange(colorScheme)
);
onSystemColorSchemeChange(Appearance.getColorScheme());
setupQuickActions(this.props.dispatch, this.props.selectedFolderId); setupQuickActions(this.props.dispatch, this.props.selectedFolderId);
await setupNotifications(this.props.dispatch); await setupNotifications(this.props.dispatch);
@ -868,6 +883,11 @@ class AppComponent extends React.Component {
this.urlOpenListener_ = null; this.urlOpenListener_ = null;
} }
if (this.themeChangeListener_) {
this.themeChangeListener_.remove();
this.themeChangeListener_ = null;
}
if (this.unsubscribeScreenWidthChangeHandler_) { if (this.unsubscribeScreenWidthChangeHandler_) {
this.unsubscribeScreenWidthChangeHandler_.remove(); this.unsubscribeScreenWidthChangeHandler_.remove();
this.unsubscribeScreenWidthChangeHandler_ = null; this.unsubscribeScreenWidthChangeHandler_ = null;

View File

@ -0,0 +1,38 @@
import Logger from '@joplin/lib/Logger';
import Setting from '@joplin/lib/models/Setting';
import { Appearance, ColorSchemeName } from 'react-native';
const logger = Logger.create('autodetectTheme');
let systemColorScheme: ColorSchemeName|null = null;
// We export an `onThemeChange`, rather than using `Appearance.getColorScheme()` directly
// to work around https://github.com/facebook/react-native/issues/36061. On some devices,
// `Appearance.getColorScheme()` returns incorrect values.
export const onSystemColorSchemeChange = (newColorScheme: ColorSchemeName|null) => {
if (systemColorScheme !== newColorScheme) {
systemColorScheme = newColorScheme;
autodetectTheme();
}
};
const autodetectTheme = () => {
if (!Setting.value('themeAutoDetect')) {
logger.info('Theme autodetect disabled, not switching theme to match system.');
return;
}
const colorScheme = systemColorScheme;
logger.debug(
'Autodetecting theme. getColorScheme returns', Appearance.getColorScheme(),
'and the expected theme is', systemColorScheme
);
if (colorScheme === 'dark') {
Setting.setValue('theme', Setting.value('preferredDarkTheme'));
} else {
Setting.setValue('theme', Setting.value('preferredLightTheme'));
}
};
export default autodetectTheme;

View File

@ -6,4 +6,5 @@ export interface AppState extends State {
route: any; route: any;
smartFilterId: string; smartFilterId: string;
noteSideMenuOptions: any; noteSideMenuOptions: any;
themeId: number;
} }

View File

@ -840,7 +840,7 @@ class Setting extends BaseModel {
value: false, value: false,
type: SettingItemType.Bool, type: SettingItemType.Bool,
section: 'appearance', section: 'appearance',
appTypes: [AppType.Desktop], appTypes: [AppType.Mobile, AppType.Desktop],
public: true, public: true,
label: () => _('Automatically switch theme to match system theme'), label: () => _('Automatically switch theme to match system theme'),
storage: SettingStorage.File, storage: SettingStorage.File,
@ -854,7 +854,7 @@ class Setting extends BaseModel {
show: (settings) => { show: (settings) => {
return settings['themeAutoDetect']; return settings['themeAutoDetect'];
}, },
appTypes: [AppType.Desktop], appTypes: [AppType.Mobile, AppType.Desktop],
isEnum: true, isEnum: true,
label: () => _('Preferred light theme'), label: () => _('Preferred light theme'),
section: 'appearance', section: 'appearance',
@ -870,7 +870,7 @@ class Setting extends BaseModel {
show: (settings) => { show: (settings) => {
return settings['themeAutoDetect']; return settings['themeAutoDetect'];
}, },
appTypes: [AppType.Desktop], appTypes: [AppType.Mobile, AppType.Desktop],
isEnum: true, isEnum: true,
label: () => _('Preferred dark theme'), label: () => _('Preferred dark theme'),
section: 'appearance', section: 'appearance',