Compare commits

...

2 Commits

Author SHA1 Message Date
Danish Ahmed Mirza 7df61a8621 Change time format of RoomItems 2022-06-03 03:15:41 +05:30
Danish Ahmed Mirza 8b4cc16548 [NEW] Add an option to change message time format 2022-06-03 01:19:12 +05:30
17 changed files with 100 additions and 22 deletions

View File

@ -46,23 +46,22 @@ const styles = StyleSheet.create({
interface IMessageBoxReplyPreview {
replying: boolean;
message: IMessage;
Message_TimeFormat: string;
close(): void;
baseUrl: string;
username: string;
getCustomEmoji: Function;
useRealName: boolean;
timeFormat: string;
}
const ReplyPreview = React.memo(
({ message, Message_TimeFormat, replying, close, useRealName }: IMessageBoxReplyPreview) => {
({ message, replying, close, useRealName, timeFormat }: IMessageBoxReplyPreview) => {
const { theme } = useTheme();
if (!replying) {
return null;
}
const time = moment(message.ts).format(Message_TimeFormat);
const time = moment(message.ts).format(timeFormat);
return (
<View style={[styles.container, { backgroundColor: themes[theme].messageboxBackground }]}>
<View style={[styles.messageContainer, { backgroundColor: themes[theme].chatComponentBackground }]}>
@ -83,7 +82,6 @@ const ReplyPreview = React.memo(
);
const mapStateToProps = (state: IApplicationState) => ({
Message_TimeFormat: state.settings.Message_TimeFormat as string,
baseUrl: state.server.server,
useRealName: state.settings.UI_Use_Real_Name as boolean
});

View File

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

View File

@ -120,13 +120,14 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
swipeEnabled,
autoJoin,
showAvatar,
displayMode
displayMode,
timeFormat
} = this.props;
const name = getRoomTitle(item);
const testID = `rooms-list-view-item-${name}`;
const avatar = getRoomAvatar(item);
const isRead = getIsRead(item);
const date = item.roomUpdatedAt && formatDate(item.roomUpdatedAt);
const date = item.roomUpdatedAt && formatDate(item.roomUpdatedAt, timeFormat);
const alert = item.alert || item.tunread?.length;
let accessibilityLabel = name;

View File

@ -92,6 +92,7 @@ export interface IRoomItemContainerProps {
autoJoin: boolean;
showAvatar: boolean;
displayMode: string;
timeFormat: string;
}
export interface IRoomItemProps {

View File

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

View File

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

View File

@ -1,6 +1,8 @@
{
"1_person_reacted": "1 person reacted",
"1_user": "1 user",
"12_Hour": "12-hour clock",
"24_Hour": "24-hour clock",
"error-action-not-allowed": "{{action}} is not allowed",
"error-application-not-found": "Application not found",
"error-archived-duplicate-name": "There's an archived channel with name {{room_name}}",
@ -327,6 +329,7 @@
"Message": "Message",
"Messages": "Messages",
"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": "Microphone Permission",
"Mute": "Mute",

View File

@ -29,4 +29,6 @@ export default class User extends Model {
@field('is_from_webview') isFromWebView;
@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 }]
})
]
},
{
toVersion: 13,
steps: [
addColumns({
table: 'users',
columns: [{ name: 'time_format', type: 'string', isOptional: true }]
})
]
}
]
});

View File

@ -1,7 +1,7 @@
import { appSchema, tableSchema } from '@nozbe/watermelondb';
export default appSchema({
version: 12,
version: 13,
tables: [
tableSchema({
name: 'users',
@ -17,7 +17,8 @@ export default appSchema({
{ name: 'show_message_in_main_thread', type: 'boolean', isOptional: true },
{ name: 'avatar_etag', type: 'string', 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: 'string', isOptional: true }
]
}),
tableSchema({

View File

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

View File

@ -285,7 +285,8 @@ async function login(credentials: ICredentials, isFromWebView = false): Promise<
avatarETag: result.me.avatarETag,
isFromWebView,
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 === 2 ? 'H:mm' : 'h:mm A'
};
return user;
}

View File

@ -23,10 +23,10 @@ export const capitalize = (s: string): string => {
return s.charAt(0).toUpperCase() + s.slice(1);
};
export const formatDate = (date: string | Date): string =>
export const formatDate = (date: string | Date, timeFormat: string | undefined): string =>
moment(date).calendar(null, {
lastDay: `[${I18n.t('Yesterday')}]`,
sameDay: 'LT',
sameDay: timeFormat || 'LT',
lastWeek: 'dddd',
sameElse: 'L'
});

View File

@ -139,12 +139,11 @@ const roomAttrsUpdate = [
] as TRoomUpdate[];
interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> {
user: Pick<ILoggedUser, 'id' | 'username' | 'token' | 'showMessageInMainThread'>;
user: Pick<ILoggedUser, 'id' | 'username' | 'token' | 'showMessageInMainThread' | 'timeFormat'>;
appState: string;
useRealName?: boolean;
isAuthenticated: boolean;
Message_GroupingPeriod?: number;
Message_TimeFormat?: string;
Message_Read_Receipt_Enabled?: boolean;
Hide_System_Messages?: string[];
baseUrl: string;
@ -1185,8 +1184,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
renderItem = (item: TAnyMessageModel, previousItem: TAnyMessageModel, highlightedMessage?: string) => {
const { room, lastOpen, canAutoTranslate } = this.state;
const { user, Message_GroupingPeriod, Message_TimeFormat, useRealName, baseUrl, Message_Read_Receipt_Enabled, theme } =
this.props;
const { user, Message_GroupingPeriod, useRealName, baseUrl, Message_Read_Receipt_Enabled, theme } = this.props;
let dateSeparator = null;
let showUnreadSeparator = false;
@ -1237,7 +1235,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
isSystemMessage={room.sysMes as boolean}
baseUrl={baseUrl}
Message_GroupingPeriod={Message_GroupingPeriod}
timeFormat={Message_TimeFormat}
timeFormat={user.timeFormat}
useRealName={useRealName}
isReadReceiptEnabled={Message_Read_Receipt_Enabled}
autoTranslateRoom={canAutoTranslate && 'id' in room && room.autoTranslate}
@ -1446,7 +1444,6 @@ const mapStateToProps = (state: IApplicationState) => ({
useRealName: state.settings.UI_Use_Real_Name as boolean,
isAuthenticated: state.login.isAuthenticated,
Message_GroupingPeriod: state.settings.Message_GroupingPeriod as number,
Message_TimeFormat: state.settings.Message_TimeFormat as string,
customEmojis: state.customEmojis,
baseUrl: state.server.server,
serverVersion: state.server.version,

View File

@ -936,7 +936,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
const { item: currentItem } = this.state;
const {
user: { username },
user: { username, timeFormat },
StoreLastMessage,
useRealName,
theme,
@ -972,6 +972,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
swipeEnabled={swipeEnabled}
showAvatar={showAvatar}
displayMode={displayMode}
timeFormat={timeFormat}
/>
);
};

View File

@ -17,7 +17,7 @@ import RoomHeader from '../containers/RoomHeader';
import SafeAreaView from '../containers/SafeAreaView';
import SearchHeader from '../containers/SearchHeader';
import StatusBar from '../containers/StatusBar';
import { IApplicationState, IBaseScreen, TSubscriptionModel } from '../definitions';
import { IApplicationState, IBaseScreen, TSubscriptionModel, IUser } from '../definitions';
import { ERoomType } from '../definitions/ERoomType';
import { withDimensions } from '../dimensions';
import I18n from '../i18n';
@ -88,6 +88,7 @@ interface ITeamChannelsViewProps extends IBaseScreen<ChatsStackParamList, 'TeamC
showActionSheet: (options: TActionSheetOptions) => void;
showAvatar: boolean;
displayMode: DisplayMode;
user: IUser;
}
class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChannelsViewState> {
private teamId: string;
@ -496,7 +497,15 @@ class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChan
};
renderItem = ({ item }: { item: IItem }) => {
const { StoreLastMessage, useRealName, theme, width, showAvatar, displayMode } = this.props;
const {
user: { timeFormat },
StoreLastMessage,
useRealName,
theme,
width,
showAvatar,
displayMode
} = this.props;
return (
<RoomItem
item={item}
@ -513,6 +522,7 @@ class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChan
autoJoin={item.teamDefault}
showAvatar={showAvatar}
displayMode={displayMode}
timeFormat={timeFormat}
/>
);
};

View File

@ -14,14 +14,36 @@ import { getUserSelector } from '../../selectors/login';
import { ProfileStackParamList } from '../../stacks/types';
import { Services } from '../../lib/services';
import { useAppSelector } from '../../lib/hooks';
import { useTheme } from '../../theme';
interface IUserPreferencesViewProps {
navigation: StackNavigationProp<ProfileStackParamList, 'UserPreferencesView'>;
theme: string;
}
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 { colors } = useTheme();
interface ITimeFormats {
label: string;
value: number;
format: string;
}
const timeFormats: ITimeFormats[] = [
{
label: '12_Hour',
value: 1,
format: 'h:mm A'
},
{
label: '24_Hour',
value: 2,
format: 'H:mm'
}
];
useEffect(() => {
navigation.setOptions({
@ -47,6 +69,17 @@ const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Ele
<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.format }));
await Services.saveUserPreferences({ id, clockMode: item.value });
} catch (e) {
log(e);
}
};
return (
<SafeAreaView testID='preferences-view'>
<StatusBar />
@ -70,6 +103,21 @@ const UserPreferencesView = ({ navigation }: IUserPreferencesViewProps): JSX.Ele
/>
<List.Separator />
</List.Section>
<List.Section title='Message_time_format'>
<List.Separator />
<List.Item
title={timeFormats[0].label}
onPress={() => onChangeTimeFormat(timeFormats[0])}
right={() => (timeFormat === timeFormats[0].format ? renderIcon() : null)}
/>
<List.Separator />
<List.Item
title={timeFormats[1].label}
onPress={() => onChangeTimeFormat(timeFormats[1])}
right={() => (timeFormat === timeFormats[1].format ? renderIcon() : null)}
/>
<List.Separator />
</List.Section>
</List.Container>
</SafeAreaView>
);