[NEW] Add an option to change message time format

This commit is contained in:
Danish Ahmed Mirza 2022-06-03 00:24:28 +05:30
parent 6220375f7b
commit 8b4cc16548
12 changed files with 94 additions and 10 deletions

View File

@ -52,17 +52,25 @@ interface IMessageBoxReplyPreview {
username: string; username: string;
getCustomEmoji: Function; getCustomEmoji: Function;
useRealName: boolean; useRealName: boolean;
timeFormat: number;
} }
const ReplyPreview = React.memo( const ReplyPreview = React.memo(
({ message, Message_TimeFormat, replying, close, useRealName }: IMessageBoxReplyPreview) => { ({ message, Message_TimeFormat, replying, close, useRealName, timeFormat }: IMessageBoxReplyPreview) => {
const { theme } = useTheme(); const { theme } = useTheme();
const getTimeFormat = () => {
const timeFormats = ['h:mm A', 'H:mm'];
if (timeFormat) {
return timeFormats[timeFormat - 1];
}
return Message_TimeFormat;
};
if (!replying) { if (!replying) {
return null; return null;
} }
const time = moment(message.ts).format(getTimeFormat());
const time = moment(message.ts).format(Message_TimeFormat);
return ( return (
<View style={[styles.container, { backgroundColor: themes[theme].messageboxBackground }]}> <View style={[styles.container, { backgroundColor: themes[theme].messageboxBackground }]}>
<View style={[styles.messageContainer, { backgroundColor: themes[theme].chatComponentBackground }]}> <View style={[styles.messageContainer, { backgroundColor: themes[theme].chatComponentBackground }]}>

View File

@ -1077,6 +1077,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
username={user.username} username={user.username}
replying={replying} replying={replying}
getCustomEmoji={getCustomEmoji} getCustomEmoji={getCustomEmoji}
timeFormat={user.timeFormat}
/> />
) : null; ) : null;

View File

@ -21,6 +21,7 @@ export interface ILoggedUser {
showMessageInMainThread?: boolean; showMessageInMainThread?: boolean;
isFromWebView?: boolean; isFromWebView?: boolean;
enableMessageParserEarlyAdoption: boolean; enableMessageParserEarlyAdoption: boolean;
timeFormat: number;
} }
export interface ILoggedUserResultFromServer export interface ILoggedUserResultFromServer

View File

@ -112,6 +112,7 @@ export interface INotificationPreferences {
pushNotifications: TNotifications; pushNotifications: TNotifications;
emailNotificationMode?: 'mentions' | 'nothing'; emailNotificationMode?: 'mentions' | 'nothing';
language?: string; language?: string;
clockMode?: number;
} }
export interface IUserPreferences { export interface IUserPreferences {

View File

@ -1,6 +1,8 @@
{ {
"1_person_reacted": "1 person reacted", "1_person_reacted": "1 person reacted",
"1_user": "1 user", "1_user": "1 user",
"12_Hour": "12-hour clock",
"24_Hour": "24-hour clock",
"error-action-not-allowed": "{{action}} is not allowed", "error-action-not-allowed": "{{action}} is not allowed",
"error-application-not-found": "Application not found", "error-application-not-found": "Application not found",
"error-archived-duplicate-name": "There's an archived channel with name {{room_name}}", "error-archived-duplicate-name": "There's an archived channel with name {{room_name}}",
@ -327,6 +329,7 @@
"Message": "Message", "Message": "Message",
"Messages": "Messages", "Messages": "Messages",
"Message_Reported": "Message reported", "Message_Reported": "Message reported",
"Message_time_format": "Time format",
"Microphone_Permission_Message": "Rocket.Chat needs access to your microphone so you can send audio message.", "Microphone_Permission_Message": "Rocket.Chat needs access to your microphone so you can send audio message.",
"Microphone_Permission": "Microphone Permission", "Microphone_Permission": "Microphone Permission",
"Mute": "Mute", "Mute": "Mute",

View File

@ -29,4 +29,6 @@ export default class User extends Model {
@field('is_from_webview') isFromWebView; @field('is_from_webview') isFromWebView;
@field('enable_message_parser_early_adoption') enableMessageParserEarlyAdoption; @field('enable_message_parser_early_adoption') enableMessageParserEarlyAdoption;
@field('time_format') timeFormat;
} }

View File

@ -103,6 +103,15 @@ export default schemaMigrations({
columns: [{ name: 'enable_message_parser_early_adoption', type: 'boolean', isOptional: true }] columns: [{ name: 'enable_message_parser_early_adoption', type: 'boolean', isOptional: true }]
}) })
] ]
},
{
toVersion: 13,
steps: [
addColumns({
table: 'users',
columns: [{ name: 'time_format', type: 'number', isOptional: true }]
})
]
} }
] ]
}); });

View File

@ -1,7 +1,7 @@
import { appSchema, tableSchema } from '@nozbe/watermelondb'; import { appSchema, tableSchema } from '@nozbe/watermelondb';
export default appSchema({ export default appSchema({
version: 12, version: 13,
tables: [ tables: [
tableSchema({ tableSchema({
name: 'users', name: 'users',
@ -17,7 +17,8 @@ export default appSchema({
{ name: 'show_message_in_main_thread', type: 'boolean', isOptional: true }, { name: 'show_message_in_main_thread', type: 'boolean', isOptional: true },
{ name: 'avatar_etag', type: 'string', isOptional: true }, { name: 'avatar_etag', type: 'string', isOptional: true },
{ name: 'is_from_webview', type: 'boolean', isOptional: true }, { name: 'is_from_webview', type: 'boolean', isOptional: true },
{ name: 'enable_message_parser_early_adoption', type: 'boolean', isOptional: true } { name: 'enable_message_parser_early_adoption', type: 'boolean', isOptional: true },
{ name: 'time_format', type: 'number', isOptional: true }
] ]
}), }),
tableSchema({ tableSchema({

View File

@ -295,6 +295,9 @@ export default function subscribeRooms() {
if ((['settings.preferences.showMessageInMainThread'] as any) in diff) { if ((['settings.preferences.showMessageInMainThread'] as any) in diff) {
store.dispatch(setUser({ showMessageInMainThread: diff['settings.preferences.showMessageInMainThread'] })); store.dispatch(setUser({ showMessageInMainThread: diff['settings.preferences.showMessageInMainThread'] }));
} }
if ((['settings.preferences.clockMode'] as any) in diff) {
store.dispatch(setUser({ timeFormat: diff['settings.preferences.clockMode'] }));
}
} }
if (/subscriptions/.test(ev)) { if (/subscriptions/.test(ev)) {
if (type === 'removed') { if (type === 'removed') {

View File

@ -285,7 +285,8 @@ async function login(credentials: ICredentials, isFromWebView = false): Promise<
avatarETag: result.me.avatarETag, avatarETag: result.me.avatarETag,
isFromWebView, isFromWebView,
showMessageInMainThread: result.me.settings?.preferences?.showMessageInMainThread ?? true, showMessageInMainThread: result.me.settings?.preferences?.showMessageInMainThread ?? true,
enableMessageParserEarlyAdoption: result.me.settings?.preferences?.enableMessageParserEarlyAdoption ?? true enableMessageParserEarlyAdoption: result.me.settings?.preferences?.enableMessageParserEarlyAdoption ?? true,
timeFormat: result.me.settings?.preferences?.clockMode ?? 0
}; };
return user; return user;
} }

View File

@ -139,7 +139,7 @@ const roomAttrsUpdate = [
] as TRoomUpdate[]; ] as TRoomUpdate[];
interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> { interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> {
user: Pick<ILoggedUser, 'id' | 'username' | 'token' | 'showMessageInMainThread'>; user: Pick<ILoggedUser, 'id' | 'username' | 'token' | 'showMessageInMainThread' | 'timeFormat'>;
appState: string; appState: string;
useRealName?: boolean; useRealName?: boolean;
isAuthenticated: boolean; isAuthenticated: boolean;
@ -1183,10 +1183,19 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
}); });
}; };
getMessageTimeFormat = () => {
const { user, Message_TimeFormat } = this.props;
const timeFormats = ['h:mm A', 'H:mm'];
if (user.timeFormat) {
return timeFormats[user.timeFormat - 1];
}
return Message_TimeFormat;
};
renderItem = (item: TAnyMessageModel, previousItem: TAnyMessageModel, highlightedMessage?: string) => { renderItem = (item: TAnyMessageModel, previousItem: TAnyMessageModel, highlightedMessage?: string) => {
const { room, lastOpen, canAutoTranslate } = this.state; const { room, lastOpen, canAutoTranslate } = this.state;
const { user, Message_GroupingPeriod, Message_TimeFormat, useRealName, baseUrl, Message_Read_Receipt_Enabled, theme } = const { user, Message_GroupingPeriod, useRealName, baseUrl, Message_Read_Receipt_Enabled, theme } = this.props;
this.props; const Message_TimeFormat = this.getMessageTimeFormat();
let dateSeparator = null; let dateSeparator = null;
let showUnreadSeparator = false; let showUnreadSeparator = false;

View File

@ -14,14 +14,33 @@ import { getUserSelector } from '../../selectors/login';
import { ProfileStackParamList } from '../../stacks/types'; import { ProfileStackParamList } from '../../stacks/types';
import { Services } from '../../lib/services'; import { Services } from '../../lib/services';
import { useAppSelector } from '../../lib/hooks'; import { useAppSelector } from '../../lib/hooks';
import { useTheme } from '../../theme';
interface IUserPreferencesViewProps { interface IUserPreferencesViewProps {
navigation: StackNavigationProp<ProfileStackParamList, 'UserPreferencesView'>; navigation: StackNavigationProp<ProfileStackParamList, 'UserPreferencesView'>;
theme: string;
} }
const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Element => { const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Element => {
const { enableMessageParserEarlyAdoption, id } = useAppSelector(state => getUserSelector(state)); const { enableMessageParserEarlyAdoption, timeFormat, id } = useAppSelector(state => getUserSelector(state));
const dispatch = useDispatch(); const dispatch = useDispatch();
const { colors } = useTheme();
interface ITimeFormats {
label: string;
value: number;
}
const timeFormats: ITimeFormats[] = [
{
label: '12_Hour',
value: 1
},
{
label: '24_Hour',
value: 2
}
];
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
@ -47,6 +66,17 @@ const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Ele
<Switch value={value} trackColor={SWITCH_TRACK_COLOR} onValueChange={toggleMessageParser} /> <Switch value={value} trackColor={SWITCH_TRACK_COLOR} onValueChange={toggleMessageParser} />
); );
const renderIcon = () => <List.Icon name='check' color={colors.tintColor} />;
const onChangeTimeFormat = async (item: ITimeFormats) => {
try {
dispatch(setUser({ timeFormat: item.value }));
await Services.saveUserPreferences({ id, clockMode: item.value });
} catch (e) {
log(e);
}
};
return ( return (
<SafeAreaView testID='preferences-view'> <SafeAreaView testID='preferences-view'>
<StatusBar /> <StatusBar />
@ -70,6 +100,21 @@ const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Ele
/> />
<List.Separator /> <List.Separator />
</List.Section> </List.Section>
<List.Section title='Message_time_format'>
<List.Separator />
<List.Item
title={timeFormats[0].label}
onPress={() => onChangeTimeFormat(timeFormats[0])}
right={() => (timeFormat === timeFormats[0].value ? renderIcon() : null)}
/>
<List.Separator />
<List.Item
title={timeFormats[1].label}
onPress={() => onChangeTimeFormat(timeFormats[1])}
right={() => (timeFormat === timeFormats[1].value ? renderIcon() : null)}
/>
<List.Separator />
</List.Section>
</List.Container> </List.Container>
</SafeAreaView> </SafeAreaView>
); );