[NEW] Add an option to change message time format
This commit is contained in:
parent
6220375f7b
commit
8b4cc16548
|
@ -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 }]}>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }]
|
||||||
|
})
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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') {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue