From d73a197f616abf0aae5c8452619caf048ec234fc Mon Sep 17 00:00:00 2001 From: noellabo Date: Thu, 29 Dec 2022 14:01:26 +0900 Subject: [PATCH] Add absolute time setting --- .../settings/preferences_controller.rb | 1 + .../mastodon/components/absolute_timestamp.js | 68 +++++++++++++++++++ app/javascript/mastodon/components/status.js | 5 +- .../components/conversation.js | 6 +- .../features/ui/components/boost_modal.js | 6 +- .../features/ui/components/reaction_modal.js | 5 +- app/javascript/mastodon/initial_state.js | 1 + app/lib/user_settings_decorator.rb | 1 + app/models/user.rb | 1 + app/serializers/initial_state_serializer.rb | 1 + .../settings/preferences/other/show.html.haml | 4 +- config/locales/simple_form.en.yml | 2 + config/locales/simple_form.ja.yml | 2 + config/settings.yml | 1 + 14 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 app/javascript/mastodon/components/absolute_timestamp.js diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index c524efdd7..5b961bfd0 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -112,6 +112,7 @@ class Settings::PreferencesController < Settings::BaseController :setting_disable_clear_all_notifications, :setting_disable_account_delete, :setting_prohibited_words, + :setting_disable_relative_time, setting_prohibited_visibilities: [], notification_emails: %i(follow follow_request reblog favourite emoji_reaction status_reference mention digest report pending_account trending_tag), interactions: %i(must_be_follower must_be_following must_be_following_dm must_be_dm_to_send_email must_be_following_reference) diff --git a/app/javascript/mastodon/components/absolute_timestamp.js b/app/javascript/mastodon/components/absolute_timestamp.js new file mode 100644 index 000000000..c0a345a5e --- /dev/null +++ b/app/javascript/mastodon/components/absolute_timestamp.js @@ -0,0 +1,68 @@ +import React from 'react'; +import { injectIntl } from 'react-intl'; +import PropTypes from 'prop-types'; + +const dateFormatOptions = { + hour12: false, + year: 'numeric', + month: 'short', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', +}; + +const shortDateFormatOptions = { + month: 'short', + day: 'numeric', +}; + +const shortTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', +}; + +const DAY = 1000 * 60 * 60 * 24; + +export const timeString = (intl, date, year) => { + const delta = intl.now() - date.getTime(); + + let absoluteTime; + + if (Math.abs(delta) < DAY) { + absoluteTime = intl.formatDate(date, shortTimeFormatOptions); + } else if (date.getFullYear() === year) { + absoluteTime = intl.formatDate(date, shortDateFormatOptions); + } else { + absoluteTime = intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' }); + } + + return absoluteTime; +}; + +export default @injectIntl +class AbsoluteTimestamp extends React.Component { + + static propTypes = { + intl: PropTypes.object.isRequired, + timestamp: PropTypes.string.isRequired, + year: PropTypes.number.isRequired, + }; + + static defaultProps = { + year: (new Date()).getFullYear(), + }; + + render () { + const { timestamp, intl, year } = this.props; + + const date = new Date(timestamp); + const absoluteTime = timeString(intl, date, year); + + return ( + + ); + } + +} diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index a40c50bb8..746526309 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import Avatar from './avatar'; import AvatarOverlay from './avatar_overlay'; import AvatarComposite from './avatar_composite'; +import AbsoluteTimestamp from './absolute_timestamp'; import RelativeTimestamp from './relative_timestamp'; import DisplayName from './display_name'; import StatusContent from './status_content'; @@ -19,7 +20,7 @@ import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; import EmojiReactionsBar from 'mastodon/components/emoji_reactions_bar'; import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder'; -import { displayMedia, enableReaction, compactReaction, show_reply_tree_button, enableStatusReference } from 'mastodon/initial_state'; +import { displayMedia, enableReaction, compactReaction, show_reply_tree_button, enableStatusReference, disableRelativeTime } from 'mastodon/initial_state'; import { List as ImmutableList } from 'immutable'; // We use the component (and not the container) since we do not want @@ -755,7 +756,7 @@ class Status extends ImmutablePureComponent { {status.get('expires_at') && } {threadMark} - + {disableRelativeTime ? : } {visibilityLink} diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.js b/app/javascript/mastodon/features/direct_timeline/components/conversation.js index 0a9f5b879..4a574a9aa 100644 --- a/app/javascript/mastodon/features/direct_timeline/components/conversation.js +++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.js @@ -9,9 +9,10 @@ import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; import AvatarComposite from 'mastodon/components/avatar_composite'; import Permalink from 'mastodon/components/permalink'; import IconButton from 'mastodon/components/icon_button'; +import AbsoluteTimestamp from 'mastodon/components/absolute_timestamp'; import RelativeTimestamp from 'mastodon/components/relative_timestamp'; import { HotKeys } from 'react-hotkeys'; -import { autoPlayGif } from 'mastodon/initial_state'; +import { autoPlayGif, disableRelativeTime } from 'mastodon/initial_state'; import classNames from 'classnames'; const messages = defineMessages({ @@ -153,7 +154,8 @@ class Conversation extends ImmutablePureComponent {
- {unread && } + {unread && } + {disableRelativeTime ? : }
diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.js b/app/javascript/mastodon/features/ui/components/boost_modal.js index 89f114fee..3bbf6178a 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.js +++ b/app/javascript/mastodon/features/ui/components/boost_modal.js @@ -6,6 +6,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Button from '../../../components/button'; import StatusContent from '../../../components/status_content'; import Avatar from '../../../components/avatar'; +import AbsoluteTimestamp from '../../../components/absolute_timestamp'; import RelativeTimestamp from '../../../components/relative_timestamp'; import DisplayName from '../../../components/display_name'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -14,6 +15,7 @@ import AttachmentList from 'mastodon/components/attachment_list'; import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown'; import classNames from 'classnames'; import { changeBoostPrivacy } from 'mastodon/actions/boosts'; +import { disableRelativeTime } from 'mastodon/initial_state'; const messages = defineMessages({ cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, @@ -109,7 +111,9 @@ class BoostModal extends ImmutablePureComponent {
diff --git a/app/javascript/mastodon/features/ui/components/reaction_modal.js b/app/javascript/mastodon/features/ui/components/reaction_modal.js index 0dc1a0d88..7b3d8629a 100644 --- a/app/javascript/mastodon/features/ui/components/reaction_modal.js +++ b/app/javascript/mastodon/features/ui/components/reaction_modal.js @@ -4,6 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import StatusContent from '../../../components/status_content'; import Avatar from '../../../components/avatar'; +import AbsoluteTimestamp from '../../../components/absolute_timestamp'; import RelativeTimestamp from '../../../components/relative_timestamp'; import DisplayName from '../../../components/display_name'; @@ -12,7 +13,7 @@ import { supportsPassiveEvents } from 'detect-passive-events'; import { EmojiPicker as EmojiPickerAsync } from '../util/async-components'; import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji'; import { assetHost } from 'mastodon/utils/config'; -import { pickerEmojiSize } from 'mastodon/initial_state'; +import { pickerEmojiSize, disableRelativeTime } from 'mastodon/initial_state'; const messages = defineMessages({ emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }, @@ -233,7 +234,7 @@ export default class ReactionModal extends ImmutablePureComponent {
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 525033cf2..e7b0aaad2 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -65,6 +65,7 @@ export const disableBlock = getMeta('disable_block'); export const disableDomainBlock = getMeta('disable_domain_block'); export const disableClearAllNotifications = getMeta('disable_clear_all_notifications'); export const disableAccountDelete = getMeta('disable_account_delete'); +export const disableRelativeTime = getMeta('disable_relative_time'); export const maxChars = initialState?.max_toot_chars ?? 500; diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb index 5451ede05..b45eb8b92 100644 --- a/app/lib/user_settings_decorator.rb +++ b/app/lib/user_settings_decorator.rb @@ -89,6 +89,7 @@ class UserSettingsDecorator disable_domain_block disable_clear_all_notifications disable_account_delete + disable_relative_time ).freeze STRING_KEYS = %w( diff --git a/app/models/user.rb b/app/models/user.rb index 531bfb990..eeedd05ab 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -145,6 +145,7 @@ class User < ApplicationRecord :show_reload_button, :default_column_width, :disable_post, :disable_reactions, :disable_follow, :disable_unfollow, :disable_block, :disable_domain_block, :disable_clear_all_notifications, :disable_account_delete, :prohibited_visibilities, :prohibited_words, + :disable_relative_time, to: :settings, prefix: :setting, allow_nil: false diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index 953afae90..002560fa2 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -86,6 +86,7 @@ class InitialStateSerializer < ActiveModel::Serializer store[:disable_domain_block] = object.current_account.user.setting_disable_domain_block store[:disable_clear_all_notifications] = object.current_account.user.setting_disable_clear_all_notifications store[:disable_account_delete] = object.current_account.user.setting_disable_account_delete + store[:disable_relative_time] = object.current_account.user.setting_disable_relative_time else store[:auto_play_gif] = Setting.auto_play_gif store[:display_media] = Setting.display_media diff --git a/app/views/settings/preferences/other/show.html.haml b/app/views/settings/preferences/other/show.html.haml index 24b103bfe..055adc701 100644 --- a/app/views/settings/preferences/other/show.html.haml +++ b/app/views/settings/preferences/other/show.html.haml @@ -116,8 +116,8 @@ .fields-group = f.input :setting_show_reload_button, as: :boolean, wrapper: :with_label, fedibird_features: true - -# .fields-group - -# = f.input :setting_show_target, as: :boolean, wrapper: :with_label + .fields-group + = f.input :setting_disable_relative_time, as: :boolean, wrapper: :with_label, fedibird_features: true %h4= t 'preferences.public_timelines' diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index e618188e3..ecf93f178 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -78,6 +78,7 @@ en: setting_disable_joke_appearance: Disable April Fools' Day and other joke functions setting_disable_post: Restricts you from accidentally posting setting_disable_reactions: Restrict reactions for favorites, boosts ,emoji reactions and polls + setting_disable_relative_time: setting_disable_unfollow: Restricts you from accidentally unfollowing setting_display_media_default: Hide media marked as sensitive setting_display_media_hide_all: Always hide media @@ -261,6 +262,7 @@ en: setting_disable_joke_appearance: Disable joke feature to change appearance setting_disable_post: Disable post setting_disable_reactions: Disable reactions + setting_disable_relative_time: Disable relative time on posts setting_disable_swiping: Disable swiping motions setting_disable_unfollow: Disable unfollow setting_display_media: Media display diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index e3ae354ac..cf819b97d 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -74,6 +74,7 @@ ja: setting_disable_joke_appearance: エイプリルフール等のジョーク機能を無効にします setting_disable_post: 誤って投稿することを防ぎます setting_disable_reactions: 誤ってお気に入り・ブースト・絵文字リアクション・投票することを防ぎます + setting_disable_relative_time: 投稿日時を相対表示する機能を無効にし、日時をそのまま表示します setting_disable_unfollow: 誤ってフォロー解除することを防ぎます setting_display_media_default: 閲覧注意としてマークされたメディアは隠す setting_display_media_hide_all: メディアを常に隠す @@ -257,6 +258,7 @@ ja: setting_disable_joke_appearance: ジョーク機能による見た目の変更を無効にする setting_disable_post: 投稿を無効にする setting_disable_reactions: リアクションを無効にする + setting_disable_relative_time: 投稿の相対日時を無効にする setting_disable_swiping: スワイプでの切り替えを無効にする setting_disable_unfollow: フォロー解除を無効にする setting_display_media: メディアの表示 diff --git a/config/settings.yml b/config/settings.yml index 1a8515b0d..ecfdb90e9 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -128,6 +128,7 @@ defaults: &defaults disable_account_delete: false prohibited_visibilities: [] prohibited_words: '' + disable_relative_time: false development: <<: *defaults