MM-39711 - Gekidou - Clock functionality [1] (#6362)

This commit is contained in:
Avinash Lingaloo
2022-06-13 16:07:03 +04:00
committed by GitHub
parent 707625501f
commit c365ecea54
9 changed files with 254 additions and 6 deletions

View File

@@ -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,

View 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;

View 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;

View File

@@ -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, () =>

View File

@@ -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

View 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;

View 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));

View File

@@ -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>

View File

@@ -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, youll need to do so through your login provider.",
"user.settings.general.firstName": "First Name",