MM-39711 - Gekidou Settings Timezone (#6384)

This commit is contained in:
Avinash Lingaloo 2022-06-24 14:52:05 +04:00 committed by GitHub
parent adfb90eb59
commit fe3f0cc892
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 470 additions and 30 deletions

View file

@ -12,7 +12,6 @@ import {prepareMyPreferences, queryPreferencesByCategoryAndName} from '@queries/
import {prepareCommonSystemValues, getCommonSystemValues} from '@queries/servers/system';
import {prepareMyTeams} from '@queries/servers/team';
import {getCurrentUser} from '@queries/servers/user';
import TeamModel from '@typings/database/models/servers/team';
import {isDMorGM, selectDefaultChannelForTeam} from '@utils/channel';
import {fetchMissingDirectChannelsInfo, fetchMyChannelsForTeam, MyChannelsRequest} from './channel';
@ -23,6 +22,7 @@ import {ConfigAndLicenseRequest, fetchConfigAndLicense} from './systems';
import {fetchMyTeams, MyTeamsRequest} from './team';
import type {Model} from '@nozbe/watermelondb';
import type TeamModel from '@typings/database/models/servers/team';
export async function retryInitialTeamAndChannel(serverUrl: string) {
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;

View file

@ -867,3 +867,15 @@ export const fetchTeamAndChannelMembership = async (serverUrl: string, userId: s
return {error};
}
};
export const getAllSupportedTimezones = async (serverUrl: string) => {
try {
const client = NetworkManager.getClient(serverUrl);
const allTzs = await client.getTimezones();
return allTzs;
} catch (error) {
// eslint-disable-next-line no-console
console.log('FAILED TO GET ALL TIMEZONES', error);
return [];
}
};

View file

@ -30,8 +30,8 @@ export type SearchProps = TextInputProps & {
containerStyle?: StyleProp<ViewStyle>;
inputContainerStyle?: StyleProp<ViewStyle>;
inputStyle?: StyleProp<TextStyle>;
loadingProps?: ActivityIndicatorProps;
leftIconContainerStyle?: StyleProp<ViewStyle>;
loadingProps?: ActivityIndicatorProps;
onCancel?(): void;
onClear?(): void;
rightIconContainerStyle?: StyleProp<ViewStyle>;

View file

@ -8,7 +8,6 @@ export const BOTTOM_SHEET = 'BottomSheet';
export const BROWSE_CHANNELS = 'BrowseChannels';
export const CHANNEL = 'Channel';
export const CHANNEL_ADD_PEOPLE = 'ChannelAddPeople';
export const CHANNEL_EDIT = 'ChannelEdit';
export const CHANNEL_INFO = 'ChannelInfo';
export const CHANNEL_MENTION = 'ChannelMention';
export const CODE = 'Code';
@ -45,6 +44,8 @@ export const SETTINGS = 'Settings';
export const SETTINGS_DISPLAY = 'SettingsDisplay';
export const SETTINGS_DISPLAY_CLOCK = 'SettingsDisplayClock';
export const SETTINGS_DISPLAY_THEME = 'SettingsDisplayTheme';
export const SETTINGS_DISPLAY_TIMEZONE = 'SettingsDisplayTimezone';
export const SETTINGS_DISPLAY_TIMEZONE_SELECT = 'SettingsDisplayTimezoneSelect';
export const SETTINGS_NOTIFICATION = 'SettingsNotification';
export const SETTINGS_NOTIFICATION_AUTO_RESPONDER = 'SettingsNotificationAutoResponder';
export const SETTINGS_NOTIFICATION_MENTION = 'SettingsNotificationMention';
@ -101,6 +102,8 @@ export default {
SETTINGS_DISPLAY,
SETTINGS_DISPLAY_CLOCK,
SETTINGS_DISPLAY_THEME,
SETTINGS_DISPLAY_TIMEZONE,
SETTINGS_DISPLAY_TIMEZONE_SELECT,
SETTINGS_NOTIFICATION,
SETTINGS_NOTIFICATION_AUTO_RESPONDER,
SETTINGS_NOTIFICATION_MENTION,

View file

@ -1,9 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {
transformGroupRecord,
} from '@database/operator/server_data_operator/transformers/group';
import {transformGroupRecord} from '@database/operator/server_data_operator/transformers/group';
import {createTestConnection} from '@database/operator/utils/create_test_connection';
import {OperationType} from '@typings/database/enums';

View file

@ -7,10 +7,10 @@ import {switchMap} from 'rxjs/operators';
import {Preferences} from '@constants';
import {MM_TABLES} from '@constants/database';
import PostModel from '@typings/database/models/servers/post';
import {queryPreferencesByCategoryAndName} from './preference';
import type PostModel from '@typings/database/models/servers/post';
import type PostInChannelModel from '@typings/database/models/servers/posts_in_channel';
import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread';

View file

@ -6,11 +6,11 @@ import {Database, Model, Q} from '@nozbe/watermelondb';
import {Preferences} from '@constants';
import {MM_TABLES} from '@constants/database';
import {getPreferenceValue} from '@helpers/api/preference';
import {ServerDatabase} from '@typings/database/database';
import {getCurrentTeamId} from './system';
import type ServerDataOperator from '@database/operator/server_data_operator';
import type {ServerDatabase} from '@typings/database/database';
import type PreferenceModel from '@typings/database/models/servers/preference';
const {SERVER: {PREFERENCE}} = MM_TABLES;

View file

@ -8,10 +8,11 @@ import {switchMap} from 'rxjs/operators';
import {observeConfig} from '@queries/servers/system';
import {observeCurrentUser} from '@queries/servers/user';
import {WithDatabaseArgs} from '@typings/database/database';
import EditProfile from './edit_profile';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const config = observeConfig(database);

View file

@ -14,11 +14,11 @@ import {observeChannelsByCategoryChannelSortOrder, observeChannelsByLastPostAtIn
import {observeNotifyPropsByChannels, queryChannelsByNames} from '@queries/servers/channel';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {observeCurrentChannelId, observeCurrentUserId, observeLastUnreadChannelId} from '@queries/servers/system';
import {WithDatabaseArgs} from '@typings/database/database';
import {getDirectChannelName} from '@utils/channel';
import CategoryBody from './category_body';
import type {WithDatabaseArgs} from '@typings/database/database';
import type CategoryModel from '@typings/database/models/servers/category';
import type ChannelModel from '@typings/database/models/servers/channel';
import type PreferenceModel from '@typings/database/models/servers/preference';

View file

@ -12,9 +12,9 @@ import CompassIcon from '@components/compass_icon';
import NetworkManager from '@managers/network_manager';
import {observeConfig} from '@queries/servers/system';
import {observeUser} from '@queries/servers/user';
import {WithDatabaseArgs} from '@typings/database/database';
import type {Client} from '@client/rest';
import type {WithDatabaseArgs} from '@typings/database/database';
import type UserModel from '@typings/database/models/servers/user';
interface NotificationIconProps {

View file

@ -160,6 +160,12 @@ Navigation.setLazyComponentRegistrator((screenName) => {
case Screens.SETTINGS_DISPLAY_THEME:
screen = withServerDatabase(require('@screens/settings/display_theme').default);
break;
case Screens.SETTINGS_DISPLAY_TIMEZONE:
screen = withServerDatabase(require('@screens/settings/display_timezone').default);
break;
case Screens.SETTINGS_DISPLAY_TIMEZONE_SELECT:
screen = withServerDatabase(require('@screens/settings/display_timezone_select').default);
break;
case Screens.SETTINGS_NOTIFICATION:
screen = withServerDatabase(require('@screens/settings/notifications').default);
break;

View file

@ -10,11 +10,12 @@ import {observePost} from '@queries/servers/post';
import {observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
import {queryMyTeamsByIds, queryTeamByName} from '@queries/servers/team';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {WithDatabaseArgs} from '@typings/database/database';
import PostModel from '@typings/database/models/servers/post';
import Permalink from './permalink';
import type {WithDatabaseArgs} from '@typings/database/database';
type OwnProps = {
postId: PostModel['id'];
teamName?: string;

View file

@ -8,10 +8,10 @@ import {switchMap} from 'rxjs/operators';
import {observePost} from '@queries/servers/post';
import {observeUser} from '@queries/servers/user';
import {WithDatabaseArgs} from '@typings/database/database';
import Reactor from './reactor';
import type {WithDatabaseArgs} from '@typings/database/database';
import type ReactionModel from '@typings/database/models/servers/reaction';
const enhance = withObservables(['reaction'], ({database, reaction}: {reaction: ReactionModel} & WithDatabaseArgs) => ({

View file

@ -3,7 +3,7 @@
import React from 'react';
import {useIntl} from 'react-intl';
import {Alert, Platform, ScrollView, View} from 'react-native';
import {Platform, ScrollView, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {Screens} from '@constants';
@ -44,11 +44,6 @@ const Display = ({isTimezoneEnabled, isThemeSwitchingEnabled}: DisplayProps) =>
const theme = useTheme();
const styles = getStyleSheet(theme);
const intl = useIntl();
const onPressHandler = () => {
return Alert.alert(
'The functionality you are trying to use has not yet been implemented.',
);
};
const goToThemeSettings = preventDoubleTap(() => {
const screen = Screens.SETTINGS_DISPLAY_THEME;
@ -63,6 +58,13 @@ const Display = ({isTimezoneEnabled, isThemeSwitchingEnabled}: DisplayProps) =>
goToScreen(screen, title);
});
const goToTimezoneSettings = preventDoubleTap(() => {
const screen = Screens.SETTINGS_DISPLAY_TIMEZONE;
const title = intl.formatMessage({id: 'display_settings.timezone', defaultMessage: 'Timezone'});
goToScreen(screen, title);
});
return (
<SafeAreaView
edges={['left', 'right']}
@ -87,7 +89,7 @@ const Display = ({isTimezoneEnabled, isThemeSwitchingEnabled}: DisplayProps) =>
{isTimezoneEnabled && (
<SettingOption
optionName='timezone'
onPress={onPressHandler}
onPress={goToTimezoneSettings}
/>
)}
<View style={styles.divider}/>

View file

@ -7,10 +7,11 @@ import {combineLatest, of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {observeAllowedThemesKeys, observeConfigBooleanValue} from '@queries/servers/system';
import {WithDatabaseArgs} from '@typings/database/database';
import DisplaySettings from './display';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const isTimezoneEnabled = observeConfigBooleanValue(database, 'ExperimentalTimezone');

View file

@ -3,7 +3,7 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl} from 'react-intl';
import {StatusBar, View} from 'react-native';
import {View} from 'react-native';
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
import {savePreference} from '@actions/remote/preference';
@ -119,7 +119,6 @@ const DisplayClock = ({componentId, currentUserId, hasMilitaryTimeFormat}: Displ
style={styles.container}
testID='settings_display.screen'
>
<StatusBar/>
<View style={styles.wrapper}>
<Block
disableHeader={true}

View file

@ -10,10 +10,11 @@ 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';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
currentUserId: observeCurrentUserId(database),

View file

@ -9,10 +9,11 @@ import {
observeCurrentTeamId,
observeCurrentUserId,
} from '@queries/servers/system';
import {WithDatabaseArgs} from '@typings/database/database';
import DisplayTheme from './display_theme';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const currentTeamId = observeCurrentTeamId(database);
const currentUserId = observeCurrentUserId(database);

View file

@ -0,0 +1,163 @@
// 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 {View} from 'react-native';
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
import {updateMe} from '@actions/remote/user';
import OptionItem from '@components/option_item';
import {Screens} 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 {goToScreen, popTopScreen, setButtons} from '@screens/navigation';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {getDeviceTimezone} from '@utils/timezone';
import {getTimezoneRegion, getUserTimezoneProps} from '@utils/user';
import type UserModel from '@typings/database/models/servers/user';
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
container: {
flex: 1,
},
wrapper: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.06),
flex: 1,
paddingTop: 35,
},
divider: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
height: 1,
},
separator: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
height: 1,
marginLeft: 15,
},
content: {
paddingHorizontal: 8,
},
};
});
const edges: Edge[] = ['left', 'right'];
const SAVE_TIMEZONE_BUTTON_ID = 'save_timezone';
type DisplayTimezoneProps = {
currentUser: UserModel;
componentId: string;
}
const DisplayTimezone = ({currentUser, componentId}: DisplayTimezoneProps) => {
const intl = useIntl();
const serverUrl = useServerUrl();
const timezone = useMemo(() => getUserTimezoneProps(currentUser), [currentUser.timezone]);
const [userTimezone, setUserTimezone] = useState(timezone);
const theme = useTheme();
const styles = getStyleSheet(theme);
const updateAutomaticTimezone = (useAutomaticTimezone: boolean) => {
const automaticTimezone = getDeviceTimezone();
setUserTimezone((prev) => ({
...prev,
useAutomaticTimezone,
automaticTimezone,
}));
};
const updateManualTimezone = (mtz: string) => {
setUserTimezone({
useAutomaticTimezone: false,
automaticTimezone: '',
manualTimezone: mtz,
});
};
const goToSelectTimezone = preventDoubleTap(() => {
const screen = Screens.SETTINGS_DISPLAY_TIMEZONE_SELECT;
const title = intl.formatMessage({id: 'settings_display.timezone.select', defaultMessage: 'Select Timezone'});
const passProps = {
selectedTimezone: timezone.manualTimezone,
onBack: updateManualTimezone,
};
goToScreen(screen, title, passProps);
});
const close = () => popTopScreen(componentId);
const saveTimezone = useCallback(() => {
const timeZone = {
useAutomaticTimezone: userTimezone.useAutomaticTimezone.toString(),
automaticTimezone: userTimezone.automaticTimezone,
manualTimezone: userTimezone.manualTimezone,
};
updateMe(serverUrl, {timezone: timeZone});
close();
}, [userTimezone, currentUser.timezone, serverUrl]);
const saveButton = useMemo(() => {
return {
id: SAVE_TIMEZONE_BUTTON_ID,
enabled: false,
showAsAction: 'always' as const,
testID: 'notification_settings.auto_res.save.button',
color: theme.sidebarHeaderTextColor,
text: intl.formatMessage({id: 'settings.save', defaultMessage: 'Save'}),
};
}, [theme.sidebarHeaderTextColor]);
useEffect(() => {
const buttons = {
rightButtons: [{
...saveButton,
enabled: timezone.useAutomaticTimezone !== userTimezone.useAutomaticTimezone,
}],
};
setButtons(componentId, buttons);
}, [componentId, currentUser.timezone]);
useNavButtonPressed(SAVE_TIMEZONE_BUTTON_ID, componentId, saveTimezone, [saveTimezone]);
useAndroidHardwareBackHandler(componentId, close);
return (
<SafeAreaView
edges={edges}
style={styles.container}
>
<View style={styles.wrapper}>
<View style={styles.divider}/>
<OptionItem
action={updateAutomaticTimezone}
containerStyle={styles.content}
description={getTimezoneRegion(userTimezone.automaticTimezone)}
label={intl.formatMessage({id: 'settings_display.timezone.automatically', defaultMessage: 'Set automatically'})}
selected={userTimezone.useAutomaticTimezone}
type='toggle'
/>
{!userTimezone.useAutomaticTimezone && (
<View>
<View style={styles.separator}/>
<OptionItem
action={goToSelectTimezone}
containerStyle={styles.content}
description={getTimezoneRegion(userTimezone.manualTimezone)}
label={intl.formatMessage({id: 'settings_display.timezone.manual', defaultMessage: 'Change timezone'})}
type='arrow'
/>
</View>
)}
<View style={styles.divider}/>
</View>
</SafeAreaView>
);
};
export default DisplayTimezone;

View file

@ -0,0 +1,20 @@
// 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 {observeCurrentUser} from '@queries/servers/user';
import DisplayTimezone from './display_timezone';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
currentUser: observeCurrentUser(database),
};
});
export default withDatabase(enhanced(DisplayTimezone));

View file

@ -0,0 +1,143 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useState} from 'react';
import {useIntl} from 'react-intl';
import {FlatList, View} from 'react-native';
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
import {getAllSupportedTimezones} from '@actions/remote/user';
import Search from '@components/search';
import {List} from '@constants';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {popTopScreen} from '@screens/navigation';
import {changeOpacity, getKeyboardAppearanceFromTheme, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import {getTimezoneRegion} from '@utils/user';
import TimezoneRow from './timezone_row';
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
container: {
flex: 1,
backgroundColor: theme.centerChannelBg,
},
searchBarInput: {
color: theme.centerChannelColor,
...typography('Body', 100, 'Regular'),
},
searchBar: {
height: 38,
marginVertical: 5,
},
};
});
const EDGES: Edge[] = ['left', 'right'];
const EMPTY_TIMEZONES: string[] = [];
const ITEM_HEIGHT = 45;
const VIEWABILITY_CONFIG = List.VISIBILITY_CONFIG_DEFAULTS;
const keyExtractor = (item: string) => item;
const getItemLayout = (_data: string[], index: number) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
});
type SelectTimezonesProps = {
selectedTimezone: string;
onBack: (tz: string) => void;
}
const SelectTimezones = ({selectedTimezone, onBack}: SelectTimezonesProps) => {
const intl = useIntl();
const serverUrl = useServerUrl();
const theme = useTheme();
const styles = getStyleSheet(theme);
const [timezones, setTimezones] = useState<string[]>(EMPTY_TIMEZONES);
const [initialScrollIndex, setInitialScrollIndex] = useState<number>(0);
const [value, setValue] = useState('');
const filteredTimezones = (timezonePrefix: string) => {
if (timezonePrefix.length === 0) {
return timezones;
}
const lowerCasePrefix = timezonePrefix.toLowerCase();
return timezones.filter((t) => (
getTimezoneRegion(t).toLowerCase().indexOf(lowerCasePrefix) >= 0 ||
t.toLowerCase().indexOf(lowerCasePrefix) >= 0
));
};
const onPressTimezone = useCallback((tzne: string) => {
onBack(tzne);
popTopScreen();
}, [onBack]);
const renderItem = ({item: timezone}: {item: string}) => {
return (
<TimezoneRow
onPressTimezone={onPressTimezone}
selectedTimezone={selectedTimezone}
timezone={timezone}
/>
);
};
useEffect(() => {
// let's get all supported timezones
const getSupportedTimezones = async () => {
const allTzs = await getAllSupportedTimezones(serverUrl);
if (allTzs.length > 0) {
setTimezones(allTzs);
const timezoneIndex = allTzs.findIndex((timezone) => timezone === selectedTimezone);
if (timezoneIndex > 0) {
setInitialScrollIndex(timezoneIndex);
}
}
};
getSupportedTimezones();
}, []);
return (
<SafeAreaView
edges={EDGES}
style={styles.container}
testID='settings.select_timezone.screen'
>
<View style={styles.searchBar}>
<Search
autoCapitalize='none'
containerStyle={styles.searchBarContainer}
inputStyle={styles.searchBarInput}
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
onChangeText={setValue}
placeholder={intl.formatMessage({id: 'search_bar.search', defaultMessage: 'Search'})}
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.5)}
selectionColor={changeOpacity(theme.centerChannelColor, 0.5)}
testID='settings.select_timezone.search_bar'
value={value}
/>
</View>
<FlatList
data={filteredTimezones(value)}
getItemLayout={getItemLayout}
initialScrollIndex={initialScrollIndex}
keyExtractor={keyExtractor}
keyboardDismissMode='on-drag'
keyboardShouldPersistTaps='always'
maxToRenderPerBatch={15}
removeClippedSubviews={true}
renderItem={renderItem}
viewabilityConfig={VIEWABILITY_CONFIG}
/>
</SafeAreaView>
);
};
export default SelectTimezones;

View file

@ -0,0 +1,69 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {TouchableOpacity, View, Text} from 'react-native';
import CompassIcon from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
const ITEM_HEIGHT = 45;
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
itemContainer: {
flexDirection: 'row',
alignItems: 'center',
width: '100%',
paddingHorizontal: 15,
height: ITEM_HEIGHT,
},
item: {
alignItems: 'center',
flex: 1,
flexDirection: 'row',
},
itemText: {
color: theme.centerChannelColor,
...typography('Body', 100, 'Regular'),
},
};
});
type TimezoneRowProps = {
onPressTimezone: (timezone: string) => void;
selectedTimezone: string;
timezone: string;
}
const TimezoneRow = ({onPressTimezone, selectedTimezone, timezone}: TimezoneRowProps) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const onTimezoneSelect = () => {
onPressTimezone(timezone);
};
return (
<TouchableOpacity
style={styles.itemContainer}
key={timezone}
onPress={onTimezoneSelect}
>
<View style={styles.item}>
<Text style={styles.itemText}>
{timezone}
</Text>
</View>
{timezone === selectedTimezone && (
<CompassIcon
name='check'
size={24}
color={theme.linkColor}
/>
)}
</TouchableOpacity>
);
};
export default TimezoneRow;

View file

@ -5,10 +5,11 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {observeCurrentUser} from '@queries/servers/user';
import {WithDatabaseArgs} from '@typings/database/database';
import NotificationAutoResponder from './notification_auto_responder';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
currentUser: observeCurrentUser(database),

View file

@ -6,10 +6,11 @@ import withObservables from '@nozbe/with-observables';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {observeCurrentUser} from '@queries/servers/user';
import {WithDatabaseArgs} from '@typings/database/database';
import Mentions from './notification_mention';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
isCRTEnabled: observeIsCRTEnabled(database),

View file

@ -15,11 +15,12 @@ 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 UserModel from '@typings/database/models/servers/user';
import {changeOpacity, getKeyboardAppearanceFromTheme, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import {getNotificationProps} from '@utils/user';
import type UserModel from '@typings/database/models/servers/user';
const mentionHeaderText = {
id: t('notification_settings.mentions.wordsTrigger'),
defaultMessage: 'Words that trigger mentions',

View file

@ -7,10 +7,11 @@ import withObservables from '@nozbe/with-observables';
import {observeConfigBooleanValue} from '@queries/servers/system';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {observeCurrentUser} from '@queries/servers/user';
import {WithDatabaseArgs} from '@typings/database/database';
import NotificationPush from './notification_push';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
currentUser: observeCurrentUser(database),

View file

@ -6,10 +6,11 @@ import withObservables from '@nozbe/with-observables';
import {observeConfigBooleanValue} from '@queries/servers/system';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {WithDatabaseArgs} from '@typings/database/database';
import NotificationSettings from './notifications';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
isCRTEnabled: observeIsCRTEnabled(database),

View file

@ -138,6 +138,17 @@ export const getTimezone = (timezone: UserTimezone | null) => {
return timezone.manualTimezone;
};
export const getTimezoneRegion = (timezone: string): string => {
if (timezone) {
const split = timezone.split('/');
if (split.length > 1) {
return split.pop()!.replace(/_/g, ' ');
}
}
return timezone;
};
export const getUserCustomStatus = (user?: UserModel | UserProfile): UserCustomStatus | undefined => {
try {
if (typeof user?.props?.customStatus === 'string') {

View file

@ -229,6 +229,7 @@
"date_separator.yesterday": "Yesterday",
"display_settings.clockDisplay": "Clock Display",
"display_settings.theme": "Theme",
"display_settings.timezone": "Timezone",
"download.error": "Unable to download the file. Try again later",
"edit_post.editPost": "Edit the post...",
"edit_post.save": "Save",
@ -691,6 +692,9 @@
"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_display.timezone.automatically": "Set automatically",
"settings_display.timezone.manual": "Change timezone",
"settings_display.timezone.select": "Select Timezone",
"settings.about": "About {appTitle}",
"settings.display": "Display",
"settings.display.militaryClock.save": "Save",