mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-03-21 18:04:10 -05:00
Add relative time strings
This commit is contained in:
parent
a661f91efb
commit
b9b9f6a8d7
|
|
@ -48,7 +48,7 @@ export default function FriendWindow(props: FriendProps) {
|
|||
if (!user || !friend || discord_presence_source_state !== RequestState.LOADED) {
|
||||
return <Root title={friend?.name} titleUser={user ?? undefined}
|
||||
autoresize={!!user && discord_presence_source_state === RequestState.LOADED}
|
||||
i18nNamespace="friend_window"
|
||||
i18nNamespace={['friend_window', 'time_since']}
|
||||
>
|
||||
<View style={styles.loading}>
|
||||
<ActivityIndicator size="large" color={'#' + (accent_colour ?? DEFAULT_ACCENT_COLOUR)} />
|
||||
|
|
@ -62,7 +62,7 @@ export default function FriendWindow(props: FriendProps) {
|
|||
const can_see_user_presence = user.nsoAccount.user.permissions.presence === PresencePermissions.FRIENDS ||
|
||||
(user.nsoAccount.user.permissions.presence === PresencePermissions.FAVORITE_FRIENDS && friend.isFavoriteFriend);
|
||||
|
||||
return <Root title={friend.name} titleUser={user} autoresize i18nNamespace="friend_window">
|
||||
return <Root title={friend.name} titleUser={user} autoresize i18nNamespace={['friend_window', 'time_since']}>
|
||||
<Friend
|
||||
friend={friend} canSeeUserPresence={can_see_user_presence}
|
||||
showDiscordPresenceSetup={discord_presence_active || !!friend.presence.updatedAt || false}
|
||||
|
|
@ -160,7 +160,7 @@ function FriendPresence(props: {
|
|||
const { t, i18n } = useTranslation('friend_window');
|
||||
|
||||
const logout = props.presence.logoutAt ? new Date(props.presence.logoutAt * 1000) : null;
|
||||
const since_logout = useTimeSince(logout ?? new Date(0));
|
||||
const since_logout = useTimeSince(logout ?? new Date(0), false, i18n.getFixedT(null, 'time_since'));
|
||||
const game = 'name' in props.presence.game ? props.presence.game : null;
|
||||
|
||||
if ((props.presence.state === PresenceState.ONLINE || props.presence.state === PresenceState.PLAYING) && game) {
|
||||
|
|
@ -194,7 +194,12 @@ function FriendPresenceGame(props: {
|
|||
<Text style={[styles.gameName, theme.text]}>{props.game.name}</Text>
|
||||
{props.game.sysDescription ? <Text style={[styles.gameActivity, theme.text]}>{props.game.sysDescription}</Text> : null}
|
||||
<Text style={[styles.gameTotalPlayTime, theme.text]}>
|
||||
{t('game_played_for', {duration: hrduration(props.game.totalPlayTime)})}
|
||||
{props.game.totalPlayTime >= 60 ?
|
||||
props.game.totalPlayTime % 60 ?
|
||||
t('game_played_for_hm', {hours: Math.floor(props.game.totalPlayTime / 60),
|
||||
minutes: props.game.totalPlayTime % 60}) :
|
||||
t('game_played_for_h', {hours: props.game.totalPlayTime / 60}) :
|
||||
t('game_played_for_m', {minutes: props.game.totalPlayTime})}
|
||||
</Text>
|
||||
<Text style={[styles.gameFirstPlayed, theme.text]}>
|
||||
{first_played ? t('game_first_played', {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ function FriendPresence(props: {
|
|||
const { t, i18n } = useTranslation('main_window', { keyPrefix: 'friends_section' });
|
||||
|
||||
const logout = props.presence.logoutAt ? new Date(props.presence.logoutAt * 1000) : null;
|
||||
const since_logout = useTimeSince(logout ?? new Date(0), true);
|
||||
const since_logout = useTimeSince(logout ?? new Date(0), true, i18n.getFixedT(null, 'time_since'));
|
||||
|
||||
if (props.presence.state === PresenceState.ONLINE || props.presence.state === PresenceState.PLAYING) {
|
||||
return <Text style={[styles.presenceText, theme.text, styles.presenceTextOnline]}>{t('presence_playing')}</Text>;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export default function App(props: AppProps) {
|
|||
titleUser={selectedUser}
|
||||
vibrancy={props.vibrancy}
|
||||
style={[styles.app, !props.vibrancy ? theme.appNoVibrancy : null]}
|
||||
i18nNamespace="main_window"
|
||||
i18nNamespace={['main_window', 'time_since']}
|
||||
>
|
||||
<Sidebar users={users} selectedUser={selectedUserId} onSelectUser={setSelectedUserId}
|
||||
insetTitleBarControls={props.insetTitleBarControls}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { EventEmitter } from 'node:events';
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { ColorSchemeName, I18nManager, LayoutChangeEvent, Platform, StyleProp, StyleSheet, useColorScheme, View, ViewStyle } from 'react-native';
|
||||
import { i18n } from 'i18next';
|
||||
import { ColorSchemeName, LayoutChangeEvent, Platform, StyleProp, StyleSheet, useColorScheme, View, ViewStyle } from 'react-native';
|
||||
import { i18n, TFunction } from 'i18next';
|
||||
import { I18nextProvider, initReactI18next } from 'react-i18next';
|
||||
import type { User as DiscordUser } from 'discord-rpc';
|
||||
import { ErrorResponse } from '../../api/util.js';
|
||||
|
|
@ -305,10 +305,10 @@ export function useActiveDiscordUser() {
|
|||
return user;
|
||||
}
|
||||
|
||||
export function useTimeSince(time: Date, short = false) {
|
||||
export function useTimeSince(time: Date, short = false, t?: TFunction) {
|
||||
const [now, setNow] = useState(Date.now());
|
||||
|
||||
const [since, update_in] = getTimeSince(time, now, short ? short_time_since_intervals : time_since_intervals);
|
||||
const [since, update_in] = getTimeSince(time, now, short ? short_time_since_intervals : time_since_intervals, t);
|
||||
const update_at = Date.now() + update_in;
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -323,24 +323,28 @@ interface TimeSinceInterval {
|
|||
interval: number;
|
||||
max: number;
|
||||
string: (count: number) => string;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
const time_since_intervals: TimeSinceInterval[] = [
|
||||
{interval: 1000, max: 10, string: () => 'just now'},
|
||||
{interval: 1000, max: 60, string: c => c + ' second' + (c === 1 ? '' : 's') + ' ago'},
|
||||
{interval: 60 * 1000, max: 60, string: c => c + ' minute' + (c === 1 ? '' : 's') + ' ago'},
|
||||
{interval: 60 * 60 * 1000, max: 24, string: c => c + ' hour' + (c === 1 ? '' : 's') + ' ago'},
|
||||
{interval: 24 * 60 * 60 * 1000, max: Infinity, string: c => c + ' day' + (c === 1 ? '' : 's') + ' ago'},
|
||||
{interval: 1000, max: 10, string: () => 'just now', key: 'default.now'},
|
||||
{interval: 1000, max: 60, string: c => c + ' second' + (c === 1 ? '' : 's') + ' ago', key: 'default.seconds'},
|
||||
{interval: 60 * 1000, max: 60, string: c => c + ' minute' + (c === 1 ? '' : 's') + ' ago', key: 'default.minutes'},
|
||||
{interval: 60 * 60 * 1000, max: 24, string: c => c + ' hour' + (c === 1 ? '' : 's') + ' ago', key: 'default.hours'},
|
||||
{interval: 24 * 60 * 60 * 1000, max: Infinity, string: c => c + ' day' + (c === 1 ? '' : 's') + ' ago', key: 'default.days'},
|
||||
];
|
||||
const short_time_since_intervals: TimeSinceInterval[] = [
|
||||
{interval: 1000, max: 10, string: () => 'Just now'},
|
||||
{interval: 1000, max: 60, string: c => c + ' sec' + (c === 1 ? '' : 's')},
|
||||
{interval: 60 * 1000, max: 60, string: c => c + ' min' + (c === 1 ? '' : 's')},
|
||||
{interval: 60 * 60 * 1000, max: 24, string: c => c + ' hr' + (c === 1 ? '' : 's')},
|
||||
{interval: 24 * 60 * 60 * 1000, max: Infinity, string: c => c + ' day' + (c === 1 ? '' : 's')},
|
||||
{interval: 1000, max: 10, string: () => 'Just now', key: 'default.now'},
|
||||
{interval: 1000, max: 60, string: c => c + ' sec' + (c === 1 ? '' : 's'), key: 'short.seconds'},
|
||||
{interval: 60 * 1000, max: 60, string: c => c + ' min' + (c === 1 ? '' : 's'), key: 'short.minutes'},
|
||||
{interval: 60 * 60 * 1000, max: 24, string: c => c + ' hr' + (c === 1 ? '' : 's'), key: 'short.hours'},
|
||||
{interval: 24 * 60 * 60 * 1000, max: Infinity, string: c => c + ' day' + (c === 1 ? '' : 's'), key: 'short.days'},
|
||||
];
|
||||
|
||||
function getTimeSince(time: Date | number, now = Date.now(), intervals = time_since_intervals): [string, number] {
|
||||
function getTimeSince(
|
||||
time: Date | number, now = Date.now(),
|
||||
intervals = time_since_intervals, t?: TFunction,
|
||||
): [string, number] {
|
||||
if (time instanceof Date) time = time.getTime();
|
||||
|
||||
const elapsed = Math.max(0, now - time);
|
||||
|
|
@ -349,7 +353,10 @@ function getTimeSince(time: Date | number, now = Date.now(), intervals = time_si
|
|||
for (const i of intervals) {
|
||||
if (elapsed < i.max * i.interval || last === i) {
|
||||
const count = Math.floor(elapsed / i.interval);
|
||||
return [i.string.call(null, count), i.interval - (elapsed - (count * i.interval))];
|
||||
return [
|
||||
(t && i.key ? t(i.key, {count, defaultValue: ''}) : '') || i.string.call(null, count),
|
||||
i.interval - (elapsed - (count * i.interval)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,15 @@ export const menus = {
|
|||
friend: {
|
||||
presence_online: 'Online',
|
||||
game_first_played: 'First played: {{date, datetime}}',
|
||||
game_play_time: 'Play time: {{time, datetime}}',
|
||||
|
||||
game_play_time_h: 'Play time: $t(friend.hours, {"count": {{hours}}})',
|
||||
game_play_time_hm: 'Play time: $t(friend.hours, {"count": {{hours}}}), $t(friend.minutes, {"count": {{minutes}}})',
|
||||
game_play_time_m: 'Play time: $t(friend.minutes, {"count": {{minutes}}})',
|
||||
hours_one: '{{count}} hour',
|
||||
hours_other: '{{count}} hours',
|
||||
minutes_one: '{{count}} minute',
|
||||
minutes_other: '{{count}} minutes',
|
||||
|
||||
presence_inactive: 'Offline (console online)',
|
||||
presence_offline: 'Offline',
|
||||
presence_updated: 'Updated: {{date, datetime}}',
|
||||
|
|
@ -91,6 +99,32 @@ export const handle_uri = {
|
|||
cancel: 'Cancel',
|
||||
};
|
||||
|
||||
export const time_since = {
|
||||
default: {
|
||||
now: 'just now',
|
||||
seconds_one: '{{count}} second ago',
|
||||
seconds_other: '{{count}} seconds ago',
|
||||
minutes_one: '{{count}} minute ago',
|
||||
minutes_other: '{{count}} minutes ago',
|
||||
hours_one: '{{count}} hour ago',
|
||||
hours_other: '{{count}} hours ago',
|
||||
days_one: '{{count}} day ago',
|
||||
days_other: '{{count}} days ago',
|
||||
},
|
||||
|
||||
short: {
|
||||
now: 'Just now',
|
||||
seconds_one: '{{count}} sec',
|
||||
seconds_other: '{{count}} secs',
|
||||
minutes_one: '{{count}} min',
|
||||
minutes_other: '{{count}} mins',
|
||||
hours_one: '{{count}} hr',
|
||||
hours_other: '{{count}} hrs',
|
||||
days_one: '{{count}} day',
|
||||
days_other: '{{count}} days',
|
||||
},
|
||||
};
|
||||
|
||||
export const main_window = {
|
||||
sidebar: {
|
||||
discord_active: 'Discord Rich Presence active',
|
||||
|
|
@ -244,7 +278,14 @@ export const friend_window = {
|
|||
presence_offline: 'Offline',
|
||||
presence_last_seen: 'Last seen {{since_logout}}',
|
||||
|
||||
game_played_for: 'Played for {{duration}}',
|
||||
game_played_for_h: 'Played for $t(hours, {"count": {{hours}}})',
|
||||
game_played_for_hm: 'Played for $t(hours, {"count": {{hours}}}), $t(minutes, {"count": {{minutes}}})',
|
||||
game_played_for_m: 'Played for $t(minutes, {"count": {{minutes}}})',
|
||||
hours_one: '{{count}} hour',
|
||||
hours_other: '{{count}} hours',
|
||||
minutes_one: '{{count}} minute',
|
||||
minutes_other: '{{count}} minutes',
|
||||
|
||||
game_first_played: 'First played {{date, datetime}}',
|
||||
game_first_played_now: 'First played now',
|
||||
game_title_id: 'Title ID',
|
||||
|
|
|
|||
|
|
@ -316,9 +316,12 @@ function buildFriendMenu(app: App, user: NintendoAccountUser, nso: CurrentUser,
|
|||
date: new Date(friend.presence.game.firstPlayedAt * 1000),
|
||||
formatParams: { date: { dateStyle: 'short', timeStyle: 'medium' } },
|
||||
})!, enabled: false}),
|
||||
new MenuItem({label: t('game_play_time', {
|
||||
time: hrduration(friend.presence.game.totalPlayTime),
|
||||
})!, enabled: false}),
|
||||
new MenuItem({label: friend.presence.game.totalPlayTime >= 60 ?
|
||||
friend.presence.game.totalPlayTime % 60 ?
|
||||
t('game_play_time_hm', {hours: Math.floor(friend.presence.game.totalPlayTime / 60),
|
||||
minutes: friend.presence.game.totalPlayTime % 60})! :
|
||||
t('game_play_time_h', {hours: friend.presence.game.totalPlayTime / 60})! :
|
||||
t('game_play_time_m', {minutes: friend.presence.game.totalPlayTime})!, enabled: false}),
|
||||
] : []),
|
||||
new MenuItem({label: t('presence_updated', {
|
||||
date: new Date(friend.presence.updatedAt * 1000),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user