forked from Ivasoft/mattermost-mobile
MM-39711 - Gekidou - Clock functionality [1] (#6362)
This commit is contained in:
@@ -43,6 +43,7 @@ export const SELECT_TEAM = 'SelectTeam';
|
||||
export const SERVER = 'Server';
|
||||
export const SETTINGS = 'Settings';
|
||||
export const SETTINGS_DISPLAY = 'SettingsDisplay';
|
||||
export const SETTINGS_DISPLAY_CLOCK = 'SettingsDisplayClock';
|
||||
export const SETTINGS_DISPLAY_THEME = 'SettingsDisplayTheme';
|
||||
export const SETTINGS_NOTIFICATION = 'SettingsNotification';
|
||||
export const SETTINGS_NOTIFICATION_AUTO_RESPONDER = 'SettingsNotificationAutoResponder';
|
||||
@@ -98,6 +99,7 @@ export default {
|
||||
SERVER,
|
||||
SETTINGS,
|
||||
SETTINGS_DISPLAY,
|
||||
SETTINGS_DISPLAY_CLOCK,
|
||||
SETTINGS_DISPLAY_THEME,
|
||||
SETTINGS_NOTIFICATION,
|
||||
SETTINGS_NOTIFICATION_AUTO_RESPONDER,
|
||||
|
||||
26
app/hooks/android_back_handler.tsx
Normal file
26
app/hooks/android_back_handler.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {EffectCallback, useEffect} from 'react';
|
||||
import {BackHandler} from 'react-native';
|
||||
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
|
||||
const useAndroidHardwareBackHandler = (componentId: string, callback: EffectCallback) => {
|
||||
useEffect(() => {
|
||||
const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
|
||||
if (EphemeralStore.getNavigationTopComponentId() === componentId) {
|
||||
callback();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return () => {
|
||||
backHandler.remove();
|
||||
};
|
||||
}, [componentId]);
|
||||
};
|
||||
|
||||
export default useAndroidHardwareBackHandler;
|
||||
24
app/hooks/navigation_button_pressed.tsx
Normal file
24
app/hooks/navigation_button_pressed.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DependencyList, EffectCallback, useEffect} from 'react';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
const useNavButtonPressed = (navButtonId: string, componentId: string, callback: EffectCallback, deps?: DependencyList) => {
|
||||
useEffect(() => {
|
||||
const unsubscribe = Navigation.events().registerComponentListener({
|
||||
navigationButtonPressed: ({buttonId}: { buttonId: string }) => {
|
||||
if (buttonId === navButtonId) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
}, componentId);
|
||||
|
||||
return () => {
|
||||
unsubscribe.remove();
|
||||
};
|
||||
}, deps);
|
||||
};
|
||||
|
||||
export default useNavButtonPressed;
|
||||
|
||||
@@ -154,21 +154,24 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.SETTINGS_DISPLAY:
|
||||
screen = withServerDatabase(require('@screens/settings/display').default);
|
||||
break;
|
||||
case Screens.SETTINGS_DISPLAY_CLOCK:
|
||||
screen = withServerDatabase(require('@screens/settings/display_clock').default);
|
||||
break;
|
||||
case Screens.SETTINGS_DISPLAY_THEME:
|
||||
screen = withServerDatabase(require('@screens/settings/display_theme').default);
|
||||
break;
|
||||
case Screens.SETTINGS_NOTIFICATION:
|
||||
screen = withServerDatabase(require('@screens/settings/notifications').default);
|
||||
break;
|
||||
case Screens.SETTINGS_NOTIFICATION_AUTO_RESPONDER:
|
||||
screen = withServerDatabase(require('@screens/settings/notification_auto_responder').default);
|
||||
break;
|
||||
case Screens.SETTINGS_NOTIFICATION_MENTION:
|
||||
screen = withServerDatabase(require('@screens/settings/notification_mention').default);
|
||||
break;
|
||||
case Screens.SETTINGS_NOTIFICATION_PUSH:
|
||||
screen = withServerDatabase(require('@screens/settings/notification_push').default);
|
||||
break;
|
||||
case Screens.SETTINGS_NOTIFICATION_AUTO_RESPONDER:
|
||||
screen = withServerDatabase(require('@screens/settings/notification_auto_responder').default);
|
||||
break;
|
||||
case Screens.SNACK_BAR: {
|
||||
const snackBarScreen = withServerDatabase(require('@screens/snack_bar').default);
|
||||
Navigation.registerComponent(Screens.SNACK_BAR, () =>
|
||||
|
||||
@@ -57,6 +57,12 @@ const Display = ({isTimezoneEnabled, isThemeSwitchingEnabled}: DisplayProps) =>
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
const goToClockDisplaySettings = preventDoubleTap(() => {
|
||||
const screen = Screens.SETTINGS_DISPLAY_CLOCK;
|
||||
const title = intl.formatMessage({id: 'display_settings.clockDisplay', defaultMessage: 'Clock Display'});
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges={['left', 'right']}
|
||||
@@ -76,7 +82,7 @@ const Display = ({isTimezoneEnabled, isThemeSwitchingEnabled}: DisplayProps) =>
|
||||
)}
|
||||
<SettingOption
|
||||
optionName='clock'
|
||||
onPress={onPressHandler}
|
||||
onPress={goToClockDisplaySettings}
|
||||
/>
|
||||
{isTimezoneEnabled && (
|
||||
<SettingOption
|
||||
|
||||
153
app/screens/settings/display_clock/display_clock.tsx
Normal file
153
app/screens/settings/display_clock/display_clock.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {StatusBar, View} from 'react-native';
|
||||
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import {savePreference} from '@actions/remote/preference';
|
||||
import Block from '@components/block';
|
||||
import OptionItem from '@components/option_item';
|
||||
import {Preferences} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||
import useNavButtonPressed from '@hooks/navigation_button_pressed';
|
||||
import {t} from '@i18n';
|
||||
import {popTopScreen, setButtons} from '@screens/navigation';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
const footer = {
|
||||
id: t('settings_display.clock.preferTime'),
|
||||
defaultMessage: 'Select how you prefer time displayed.',
|
||||
};
|
||||
|
||||
const edges: Edge[] = ['left', 'right'];
|
||||
const CLOCK_TYPE = {
|
||||
NORMAL: 'NORMAL',
|
||||
MILITARY: 'MILITARY',
|
||||
} as const;
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
wrapper: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.06),
|
||||
flex: 1,
|
||||
paddingTop: 35,
|
||||
},
|
||||
divider: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
height: 1,
|
||||
},
|
||||
containerStyle: {
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const SAVE_CLOCK_BUTTON_ID = 'settings_display.clock.save.button';
|
||||
|
||||
type DisplayClockProps = {
|
||||
componentId: string;
|
||||
currentUserId: string;
|
||||
hasMilitaryTimeFormat: boolean;
|
||||
}
|
||||
const DisplayClock = ({componentId, currentUserId, hasMilitaryTimeFormat}: DisplayClockProps) => {
|
||||
const theme = useTheme();
|
||||
const [isMilitaryTimeFormat, setIsMilitaryTimeFormat] = useState(hasMilitaryTimeFormat);
|
||||
const serverUrl = useServerUrl();
|
||||
const intl = useIntl();
|
||||
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
const saveButton = useMemo(() => {
|
||||
return {
|
||||
id: SAVE_CLOCK_BUTTON_ID,
|
||||
enabled: false,
|
||||
showAsAction: 'always' as const,
|
||||
testID: 'settings_display.save.button',
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
text: intl.formatMessage({id: 'settings.display.militaryClock.save', defaultMessage: 'Save'}),
|
||||
};
|
||||
}, [theme.sidebarHeaderTextColor]);
|
||||
|
||||
const onSelectClockPreference = useCallback((clockType: keyof typeof CLOCK_TYPE) => {
|
||||
setIsMilitaryTimeFormat(clockType === CLOCK_TYPE.MILITARY);
|
||||
}, []);
|
||||
|
||||
const close = () => popTopScreen(componentId);
|
||||
|
||||
const saveClockDisplayPreference = () => {
|
||||
const timePreference: PreferenceType = {
|
||||
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
|
||||
name: 'use_military_time',
|
||||
user_id: currentUserId,
|
||||
value: `${isMilitaryTimeFormat}`,
|
||||
};
|
||||
|
||||
savePreference(serverUrl, [timePreference]);
|
||||
close();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const buttons = {
|
||||
rightButtons: [{
|
||||
...saveButton,
|
||||
enabled: hasMilitaryTimeFormat !== isMilitaryTimeFormat,
|
||||
}],
|
||||
};
|
||||
setButtons(componentId, buttons);
|
||||
}, [componentId, saveButton, isMilitaryTimeFormat]);
|
||||
|
||||
useEffect(() => {
|
||||
setButtons(componentId, {
|
||||
rightButtons: [saveButton],
|
||||
});
|
||||
}, []);
|
||||
|
||||
useAndroidHardwareBackHandler(componentId, close);
|
||||
useNavButtonPressed(SAVE_CLOCK_BUTTON_ID, componentId, saveClockDisplayPreference, [isMilitaryTimeFormat]);
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges={edges}
|
||||
style={styles.container}
|
||||
testID='settings_display.screen'
|
||||
>
|
||||
<StatusBar/>
|
||||
<View style={styles.wrapper}>
|
||||
<Block
|
||||
disableHeader={true}
|
||||
footerText={footer}
|
||||
>
|
||||
<OptionItem
|
||||
action={onSelectClockPreference}
|
||||
containerStyle={styles.containerStyle}
|
||||
label={intl.formatMessage({id: 'settings_display.clock.normal', defaultMessage: '12-hour clock (example: 4:00 PM)'})}
|
||||
selected={!isMilitaryTimeFormat}
|
||||
testID='clock_display_settings.normal_clock.action'
|
||||
type='select'
|
||||
value={CLOCK_TYPE.NORMAL}
|
||||
/>
|
||||
<View style={styles.divider}/>
|
||||
<OptionItem
|
||||
action={onSelectClockPreference}
|
||||
containerStyle={styles.containerStyle}
|
||||
label={intl.formatMessage({id: 'settings_display.clock.military', defaultMessage: '24-hour clock (example: 16:00)'})}
|
||||
selected={isMilitaryTimeFormat}
|
||||
testID='clock_display_settings.military_clock.action'
|
||||
type='select'
|
||||
value={CLOCK_TYPE.MILITARY}
|
||||
/>
|
||||
</Block>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default DisplayClock;
|
||||
29
app/screens/settings/display_clock/index.tsx
Normal file
29
app/screens/settings/display_clock/index.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {Preferences} from '@constants';
|
||||
import {getPreferenceAsBool} from '@helpers/api/preference';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeCurrentUserId} from '@queries/servers/system';
|
||||
import {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
import DisplayClock from './display_clock';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
return {
|
||||
currentUserId: observeCurrentUserId(database),
|
||||
hasMilitaryTimeFormat: queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).
|
||||
observeWithColumns(['value']).pipe(
|
||||
switchMap(
|
||||
(preferences) => of$(getPreferenceAsBool(preferences, Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', false)),
|
||||
),
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(DisplayClock));
|
||||
@@ -41,7 +41,7 @@ const CustomTheme = ({customTheme, setTheme}: CustomThemeProps) => {
|
||||
action={setTheme}
|
||||
type='select'
|
||||
value={customTheme.type}
|
||||
label={intl.formatMessage({id: 'user.settings.display.custom_theme', defaultMessage: 'Custom Theme'})}
|
||||
label={intl.formatMessage({id: 'settings_display.custom_theme', defaultMessage: 'Custom Theme'})}
|
||||
selected={theme.type?.toLowerCase() === customTheme.type?.toLowerCase()}
|
||||
/>
|
||||
</Block>
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"custom_status.suggestions.working_from_home": "Working from home",
|
||||
"date_separator.today": "Today",
|
||||
"date_separator.yesterday": "Yesterday",
|
||||
"display_settings.clockDisplay": "Clock Display",
|
||||
"display_settings.theme": "Theme",
|
||||
"download.error": "Unable to download the file. Try again later",
|
||||
"edit_post.editPost": "Edit the post...",
|
||||
@@ -660,8 +661,13 @@
|
||||
"servers.login": "Log in",
|
||||
"servers.logout": "Log out",
|
||||
"servers.remove": "Remove",
|
||||
"settings_display.clock.military": "24-hour clock (example: 16:00)",
|
||||
"settings_display.clock.normal": "12-hour clock (example: 4:00 PM)",
|
||||
"settings_display.clock.preferTime": "Select how you prefer time displayed.",
|
||||
"settings_display.custom_theme": "Custom Theme",
|
||||
"settings.about": "About {appTitle}",
|
||||
"settings.display": "Display",
|
||||
"settings.display.militaryClock.save": "Save",
|
||||
"settings.notifications": "Notifications",
|
||||
"snack.bar.favorited.channel": "This channel was favorited",
|
||||
"snack.bar.link.copied": "Link copied to clipboard",
|
||||
@@ -712,7 +718,6 @@
|
||||
"unreads.empty.title": "No more unreads",
|
||||
"user.edit_profile.email.auth_service": "Login occurs through {service}. Email cannot be updated. Email address used for notifications is {email}.",
|
||||
"user.edit_profile.email.web_client": "Email must be updated using a web client or desktop application.",
|
||||
"user.settings.display.custom_theme": "Custom Theme",
|
||||
"user.settings.general.email": "Email",
|
||||
"user.settings.general.field_handled_externally": "Some fields below are handled through your login provider. If you want to change them, you’ll need to do so through your login provider.",
|
||||
"user.settings.general.firstName": "First Name",
|
||||
|
||||
Reference in New Issue
Block a user