Skip to content

Commit

Permalink
タイムライン上に表示される添付メディアのサムネイル画像をクロップ表示する設定項目を追加
Browse files Browse the repository at this point in the history
  • Loading branch information
MitarashiDango committed Oct 21, 2024
1 parent c639974 commit 763ec73
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 19 deletions.
44 changes: 28 additions & 16 deletions app/javascript/mastodon/components/media_gallery.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { AltTextBadge } from 'mastodon/components/alt_text_badge';
import { Blurhash } from 'mastodon/components/blurhash';
import { formatTime } from 'mastodon/features/video';

import { autoPlayGif, displayMedia, useBlurhash } from '../initial_state';
import { autoPlayGif, cropAttachmentThumbnailsOnTimeline, displayMedia, useBlurhash } from '../initial_state';

class Item extends PureComponent {

Expand Down Expand Up @@ -57,7 +57,7 @@ class Item extends PureComponent {
return this.props.autoplay || autoPlayGif;
}

hoverToPlay () {
hoverToPlay() {
const { attachment } = this.props;
return !this.getAutoPlay() && ['gifv', 'video'].includes(attachment.get('type'));
}
Expand All @@ -81,12 +81,12 @@ class Item extends PureComponent {
this.setState({ loaded: true });
};

render () {
render() {
const { attachment, lang, index, size, standalone, displayWidth, visible } = this.props;

let badges = [], thumbnail;

let width = 50;
let width = 50;
let height = 100;

if (size === 1) {
Expand Down Expand Up @@ -116,21 +116,21 @@ class Item extends PureComponent {
</div>
);
} else if (attachment.get('type') === 'image') {
const previewUrl = attachment.get('preview_url');
const previewUrl = attachment.get('preview_url');
const previewWidth = attachment.getIn(['meta', 'small', 'width']);

const originalUrl = attachment.get('url');
const originalUrl = attachment.get('url');
const originalWidth = attachment.getIn(['meta', 'original', 'width']);

const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number';

const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null;
const sizes = hasSize && (displayWidth > 0) ? `${displayWidth * (width / 100)}px` : null;
const sizes = hasSize && (displayWidth > 0) ? `${displayWidth * (width / 100)}px` : null;

const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
const x = ((focusX / 2) + .5) * 100;
const y = ((focusY / -2) + .5) * 100;
const x = ((focusX / 2) + .5) * 100;
const y = ((focusY / -2) + .5) * 100;

thumbnail = (
<a
Expand Down Expand Up @@ -221,22 +221,23 @@ class MediaGallery extends PureComponent {
visible: PropTypes.bool,
autoplay: PropTypes.bool,
onToggleVisibility: PropTypes.func,
standalone: PropTypes.bool,
};

state = {
visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
width: this.props.defaultWidth,
};

componentDidMount () {
componentDidMount() {
window.addEventListener('resize', this.handleResize, { passive: true });
}

componentWillUnmount () {
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}

UNSAFE_componentWillReceiveProps (nextProps) {
UNSAFE_componentWillReceiveProps(nextProps) {
if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
} else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
Expand Down Expand Up @@ -272,7 +273,7 @@ class MediaGallery extends PureComponent {
}
};

_setDimensions () {
_setDimensions() {
const width = this.node.offsetWidth;

// offsetWidth triggers a layout, so only calculate when we need to
Expand All @@ -286,11 +287,20 @@ class MediaGallery extends PureComponent {
}

isFullSizeEligible() {
const { media } = this.props;
const { media, standalone } = this.props;
if (cropAttachmentThumbnailsOnTimeline) {
return media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']) && standalone;
}

return media.size === 1 && media.getIn([0, 'meta', 'small', 'aspect']);
}

render () {
isCropThumbnail() {
const { media, standalone } = this.props;
return media.size === 1 && cropAttachmentThumbnailsOnTimeline && standalone !== true;
}

render() {
const { media, lang, sensitive, defaultWidth, autoplay } = this.props;
const { visible } = this.state;
const width = this.state.width || defaultWidth;
Expand All @@ -301,11 +311,13 @@ class MediaGallery extends PureComponent {

if (this.isFullSizeEligible()) {
style.aspectRatio = `${this.props.media.getIn([0, 'meta', 'small', 'aspect'])}`;
} else if (this.isCropThumbnail()) {
style.aspectRatio = '16 / 9';
} else {
style.aspectRatio = '3 / 2';
}

const size = media.size;
const size = media.size;
const uncached = media.every(attachment => attachment.get('type') === 'unknown');

if (this.isFullSizeEligible()) {
Expand Down
6 changes: 3 additions & 3 deletions app/javascript/mastodon/components/status.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Card from '../features/status/components/card';
import Bundle from '../features/ui/components/bundle';
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
import { SensitiveMediaContext } from '../features/ui/util/sensitive_media_context';
import { displayMedia } from '../initial_state';
import { cropAttachmentThumbnailsOnTimeline, displayMedia } from '../initial_state';

import AttachmentList from './attachment_list';
import { Avatar } from './avatar';
Expand Down Expand Up @@ -209,7 +209,7 @@ class Status extends ImmutablePureComponent {
const attachments = this._properStatus().get('media_attachments');

if (attachments.getIn([0, 'type']) === 'video') {
return `${attachments.getIn([0, 'meta', 'original', 'width'])} / ${attachments.getIn([0, 'meta', 'original', 'height'])}`;
return cropAttachmentThumbnailsOnTimeline ? '16 / 9' : `${attachments.getIn([0, 'meta', 'original', 'width'])} / ${attachments.getIn([0, 'meta', 'original', 'height'])}`;
} else if (attachments.getIn([0, 'type']) === 'audio') {
return '16 / 9';
} else {
Expand Down Expand Up @@ -513,7 +513,7 @@ class Status extends ImmutablePureComponent {
<Component
preview={attachment.get('preview_url')}
frameRate={attachment.getIn(['meta', 'original', 'frame_rate'])}
aspectRatio={`${attachment.getIn(['meta', 'original', 'width'])} / ${attachment.getIn(['meta', 'original', 'height'])}`}
aspectRatio={cropAttachmentThumbnailsOnTimeline ? '16 / 9' : `${attachment.getIn(['meta', 'original', 'width'])} / ${attachment.getIn(['meta', 'original', 'height'])}`}
blurhash={attachment.get('blurhash')}
src={attachment.get('url')}
alt={description}
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/mastodon/initial_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* @property {boolean} activity_api_enabled
* @property {string} admin
* @property {boolean=} boost_modal
* @property {boolean=} crop_attachment_thumbnails_on_timeline
* @property {boolean=} delete_modal
* @property {boolean=} disable_swiping
* @property {boolean=} disable_hover_cards
Expand Down Expand Up @@ -88,6 +89,7 @@ export const activityApiEnabled = getMeta('activity_api_enabled');
export const advancedLayout = getMeta('advanced_layout');
export const autoPlayGif = getMeta('auto_play_gif');
export const boostModal = getMeta('boost_modal');
export const cropAttachmentThumbnailsOnTimeline = getMeta('crop_attachment_thumbnails_on_timeline');
export const deleteModal = getMeta('delete_modal');
export const disableSwiping = getMeta('disable_swiping');
export const disableHoverCards = getMeta('disable_hover_cards');
Expand Down
4 changes: 4 additions & 0 deletions app/models/concerns/user/has_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,8 @@ def setting_reverse_nav
def setting_hide_translate_button
settings['web.hide_translate_button']
end

def setting_crop_attachment_thumbnails_on_timeline
settings['web.crop_attachment_thumbnails_on_timeline']
end
end
1 change: 1 addition & 0 deletions app/models/user_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class KeyError < Error; end
setting :mod_webui_styles, default: 'default', in: %w(default compact legacy)
setting :mod_reverse_nav, default: false
setting :hide_translate_button, default: false
setting :crop_attachment_thumbnails_on_timeline, default: false
end

namespace :notification_emails do
Expand Down
1 change: 1 addition & 0 deletions app/serializers/initial_state_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def current_account_settings
webui_styles: object_account_user.setting_webui_styles,
wider_column: object_account_user.setting_wider_column,
hide_translate_button: object_account_user.setting_hide_translate_button,
crop_attachment_thumbnails_on_timeline: object_account_user.setting_crop_attachment_thumbnails_on_timeline,
}
end

Expand Down
3 changes: 3 additions & 0 deletions app/views/settings/preferences/appearance/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@

.fields-group
= ff.input :'web.hide_translate_button', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_hide_translate_button')

.fields-group
= ff.input :'web.crop_attachment_thumbnails_on_timeline', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.crop_attachment_thumbnails_on_timeline'), hint: I18n.t('simple_form.hints.defaults.crop_attachment_thumbnails_on_timeline')

%h4= t 'appearance.advanced_web_interface'

Expand Down
2 changes: 2 additions & 0 deletions config/locales/simple_form.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ en:
avatar: WEBP, PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
bot: Signal to others that the account mainly performs automated actions and might not be monitored
context: One or multiple contexts where the filter should apply
crop_attachment_thumbnails_on_timeline: Crop attachment thumbnails on timeline to 16:9
current_password: For security purposes please enter the password of the current account
current_username: To confirm, please enter the username of the current account
digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence
Expand Down Expand Up @@ -194,6 +195,7 @@ en:
confirm_new_password: Confirm new password
confirm_password: Confirm password
context: Filter contexts
crop_attachment_thumbnails_on_timeline: Crop attachment thumbnails
current_password: Current password
data: Data
display_name: Display name
Expand Down
2 changes: 2 additions & 0 deletions config/locales/simple_form.ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ ja:
avatar: "%{size}までのWEBP、PNG、GIF、JPGが利用可能です。%{dimensions}pxまで縮小されます"
bot: このアカウントは主に自動で動作し、人が見ていない可能性があります
context: フィルターを適用する対象 (複数選択可)
crop_attachment_thumbnails_on_timeline: タイムライン上に表示されるメディアのサムネイル画像を16:9で切り抜き表示します
current_password: 現在のアカウントのパスワードを入力してください
current_username: 確認のため、現在のアカウントのユーザー名を入力してください
digest: 長期間使用していない場合と不在時に返信を受けた場合のみ送信されます
Expand Down Expand Up @@ -194,6 +195,7 @@ ja:
confirm_new_password: 新しいパスワード(確認用)
confirm_password: パスワード(確認用)
context: 除外対象
crop_attachment_thumbnails_on_timeline: メディアのサムネイル画像を切り抜き表示する
current_password: 現在のパスワード
data: データ
display_name: 表示名
Expand Down

0 comments on commit 763ec73

Please sign in to comment.