~cytrogen/masto-fe

4df14235c6b27a4c8370af93c76095077d395be5 — tobi 1 year, 4 months ago 9f520d3
[feature] Move `use_blurhash` to app settings, enable by default (#5)

Does what it says on the tin! This serves as a decent model (imo) for how to move something from Mastodon's rather opaque server-side settings to client settings.

Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/5
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Co-committed-by: tobi <tobi.smethurst@protonmail.com>
M app/javascript/flavours/glitch/components/media_gallery.jsx => app/javascript/flavours/glitch/components/media_gallery.jsx +41 -5
@@ 11,7 11,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';

import { Blurhash } from 'flavours/glitch/components/blurhash';
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
import { autoPlayGif, displayMedia } from 'flavours/glitch/initial_state';

import { IconButton } from './icon_button';



@@ 51,6 51,7 @@ class Item extends PureComponent {
    displayWidth: PropTypes.number,
    visible: PropTypes.bool.isRequired,
    autoplay: PropTypes.bool,
    useBlurhash: PropTypes.bool,
  };

  static defaultProps = {


@@ 105,7 106,17 @@ class Item extends PureComponent {
  };

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

    let badges = [], thumbnail;



@@ 243,6 254,7 @@ class MediaGallery extends PureComponent {
    visible: PropTypes.bool,
    autoplay: PropTypes.bool,
    onToggleVisibility: PropTypes.func,
    useBlurhash: PropTypes.bool,
  };

  static defaultProps = {


@@ 326,7 338,7 @@ class MediaGallery extends PureComponent {
  }

  render () {
    const { media, lang, intl, sensitive, letterbox, fullwidth, defaultWidth, autoplay } = this.props;
    const { media, lang, intl, sensitive, letterbox, fullwidth, defaultWidth, autoplay, useBlurhash } = this.props;
    const { visible } = this.state;
    const size     = media.take(4).size;
    const uncached = media.every(attachment => attachment.get('type') === 'unknown');


@@ 346,9 358,33 @@ class MediaGallery extends PureComponent {
    }

    if (this.isStandaloneEligible()) {
      children = <Item standalone autoplay={autoplay} onClick={this.handleClick} attachment={media.get(0)} lang={lang} displayWidth={width} visible={visible} />;
      children = (
        <Item
          standalone
          autoplay={autoplay}
          onClick={this.handleClick}
          attachment={media.get(0)}
          lang={lang}
          displayWidth={width}
          visible={visible}
          useBlurhash={useBlurhash}
        />
      );
    } else {
      children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} autoplay={autoplay} onClick={this.handleClick} attachment={attachment} index={i} lang={lang} size={size} letterbox={letterbox} displayWidth={width} visible={visible || uncached} />);
      children = media.take(4).map((attachment, i) => (
        <Item
          key={attachment.get('id')}
          autoplay={autoplay}
          onClick={this.handleClick}
          attachment={attachment}
          index={i}
          lang={lang}
          size={size}
          letterbox={letterbox}
          displayWidth={width}
          visible={visible || uncached}
          useBlurhash={useBlurhash} />
      ));
    }

    if (uncached) {

M app/javascript/flavours/glitch/components/status.jsx => app/javascript/flavours/glitch/components/status.jsx +4 -0
@@ 667,6 667,7 @@ class Status extends ImmutablePureComponent {
                blurhash={attachment.get('blurhash')}
                visible={this.state.showMedia}
                onToggleVisibility={this.handleToggleMediaVisibility}
                useBlurhash={settings.getIn(['media', 'use_blurhash'])}
              />
            )}
          </Bundle>,


@@ 694,6 695,7 @@ class Status extends ImmutablePureComponent {
              deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
              visible={this.state.showMedia}
              onToggleVisibility={this.handleToggleMediaVisibility}
              useBlurhash={settings.getIn(['media', 'use_blurhash'])}
            />)}
          </Bundle>,
        );


@@ 714,6 716,7 @@ class Status extends ImmutablePureComponent {
                defaultWidth={this.props.cachedMediaWidth}
                visible={this.state.showMedia}
                onToggleVisibility={this.handleToggleMediaVisibility}
                useBlurhash={settings.getIn(['media', 'use_blurhash'])}
              />
            )}
          </Bundle>,


@@ 731,6 734,7 @@ class Status extends ImmutablePureComponent {
          card={status.get('card')}
          compact
          sensitive={status.get('sensitive')}
          useBlurhash={settings.getIn(['media', 'use_blurhash'])}
        />,
      );
      mediaIcons.push('link');

M app/javascript/flavours/glitch/features/account_gallery/components/media_item.jsx => app/javascript/flavours/glitch/features/account_gallery/components/media_item.jsx +3 -4
@@ 7,9 7,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';

import { Blurhash } from 'flavours/glitch/components/blurhash';
import { Icon } from 'flavours/glitch/components/icon';
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';


import { autoPlayGif, displayMedia } from 'flavours/glitch/initial_state';

export default class MediaItem extends ImmutablePureComponent {



@@ 17,6 15,7 @@ export default class MediaItem extends ImmutablePureComponent {
    attachment: ImmutablePropTypes.map.isRequired,
    displayWidth: PropTypes.number.isRequired,
    onOpenMedia: PropTypes.func.isRequired,
    useBlurhash: PropTypes.bool,
  };

  state = {


@@ 58,7 57,7 @@ export default class MediaItem extends ImmutablePureComponent {
  };

  render () {
    const { attachment, displayWidth } = this.props;
    const { attachment, displayWidth, useBlurhash } = this.props;
    const { visible, loaded } = this.state;

    const width  = `${Math.floor((displayWidth - 4) / 3) - 4}px`;

M app/javascript/flavours/glitch/features/account_gallery/index.jsx => app/javascript/flavours/glitch/features/account_gallery/index.jsx +10 -2
@@ 32,6 32,7 @@ const mapStateToProps = (state, { params: { acct, id } }) => {

  return {
    accountId,
    settings: state.get('local_settings'),
    isAccount: !!state.getIn(['accounts', accountId]),
    attachments: getAccountGallery(state, accountId),
    isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading']),


@@ 69,6 70,7 @@ class AccountGallery extends ImmutablePureComponent {
      acct: PropTypes.string,
      id: PropTypes.string,
    }).isRequired,
    settings: ImmutablePropTypes.map.isRequired,
    accountId: PropTypes.string,
    dispatch: PropTypes.func.isRequired,
    attachments: ImmutablePropTypes.list.isRequired,


@@ 175,7 177,7 @@ class AccountGallery extends ImmutablePureComponent {
  };

  render () {
    const { attachments, isLoading, hasMore, isAccount, multiColumn, suspended } = this.props;
    const { attachments, isLoading, hasMore, isAccount, settings, multiColumn, suspended } = this.props;
    const { width } = this.state;

    if (!isAccount) {


@@ 215,7 217,13 @@ class AccountGallery extends ImmutablePureComponent {
                {attachments.map((attachment, index) => attachment === null ? (
                  <LoadMoreMedia key={'more:' + attachments.getIn(index + 1, 'id')} maxId={index > 0 ? attachments.getIn(index - 1, 'id') : null} onLoadMore={this.handleLoadMore} />
                ) : (
                  <MediaItem key={attachment.get('id')} attachment={attachment} displayWidth={width} onOpenMedia={this.handleOpenMedia} />
                  <MediaItem
                    key={attachment.get('id')}
                    attachment={attachment}
                    displayWidth={width}
                    onOpenMedia={this.handleOpenMedia}
                    useBlurhash={settings.getIn(['media', 'use_blurhash'])}
                  />
                ))}

                {loadOlder}

M app/javascript/flavours/glitch/features/audio/index.jsx => app/javascript/flavours/glitch/features/audio/index.jsx +3 -2
@@ 12,7 12,7 @@ import { throttle, debounce } from 'lodash';
import { Blurhash } from 'flavours/glitch/components/blurhash';
import { Icon } from 'flavours/glitch/components/icon';
import { formatTime, getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video';
import { displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
import { displayMedia } from 'flavours/glitch/initial_state';

import Visualizer from './visualizer';



@@ 56,6 56,7 @@ class Audio extends PureComponent {
    volume: PropTypes.number,
    muted: PropTypes.bool,
    deployPictureInPicture: PropTypes.func,
    useBlurhash: PropTypes.bool,
  };

  state = {


@@ 472,7 473,7 @@ class Audio extends PureComponent {
  };

  render () {
    const { src, intl, alt, lang, editable, autoPlay, sensitive, blurhash } = this.props;
    const { src, intl, alt, lang, editable, autoPlay, sensitive, blurhash, useBlurhash } = this.props;
    const { paused, volume, currentTime, duration, buffer, dragging, revealed } = this.state;
    const progress = Math.min((currentTime / duration) * 100, 100);
    const muted = this.state.muted || volume === 0;

M app/javascript/flavours/glitch/features/local_settings/page/index.jsx => app/javascript/flavours/glitch/features/local_settings/page/index.jsx +8 -0
@@ 468,6 468,14 @@ class LocalSettingsPage extends PureComponent {
        <h1><FormattedMessage id='settings.media' defaultMessage='Media' /></h1>
        <LocalSettingsPageItem
          settings={settings}
          item={['media', 'use_blurhash']}
          id='mastodon-settings--media-use-blurhash'
          onChange={onChange}
        >
          <FormattedMessage id='setting_use_blurhash' defaultMessage='Show colorful gradients for hidden media' />
        </LocalSettingsPageItem>
        <LocalSettingsPageItem
          settings={settings}
          item={['media', 'letterbox']}
          id='mastodon-settings--media-letterbox'
          onChange={onChange}

M app/javascript/flavours/glitch/features/status/components/card.jsx => app/javascript/flavours/glitch/features/status/components/card.jsx +2 -2
@@ 10,7 10,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';

import { Blurhash } from 'flavours/glitch/components/blurhash';
import { Icon } from 'flavours/glitch/components/icon';
import { useBlurhash } from 'flavours/glitch/initial_state';
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';

const getHostname = url => {


@@ 49,6 48,7 @@ export default class Card extends PureComponent {
    onOpenMedia: PropTypes.func.isRequired,
    compact: PropTypes.bool,
    sensitive: PropTypes.bool,
    useBlurhash: PropTypes.bool,
  };

  static defaultProps = {


@@ 138,7 138,7 @@ export default class Card extends PureComponent {
  }

  render () {
    const { card, compact } = this.props;
    const { card, compact, useBlurhash } = this.props;
    const { embedded, revealed } = this.state;

    if (card === null) {

M app/javascript/flavours/glitch/features/status/components/detailed_status.jsx => app/javascript/flavours/glitch/features/status/components/detailed_status.jsx +10 -1
@@ 185,6 185,7 @@ class DetailedStatus extends ImmutablePureComponent {
            blurhash={attachment.get('blurhash')}
            height={150}
            onToggleVisibility={this.props.onToggleMediaVisibility}
            useBlurhash={settings.getIn(['media', 'use_blurhash'])}
          />,
        );
        mediaIcons.push('music');


@@ 209,6 210,7 @@ class DetailedStatus extends ImmutablePureComponent {
            autoplay
            visible={this.props.showMedia}
            onToggleVisibility={this.props.onToggleMediaVisibility}
            useBlurhash={settings.getIn(['media', 'use_blurhash'])}
          />,
        );
        mediaIcons.push('video-camera');


@@ 225,12 227,19 @@ class DetailedStatus extends ImmutablePureComponent {
            onOpenMedia={this.props.onOpenMedia}
            visible={this.props.showMedia}
            onToggleVisibility={this.props.onToggleMediaVisibility}
            useBlurhash={settings.getIn(['media', 'use_blurhash'])}
          />,
        );
        mediaIcons.push('picture-o');
      }
    } else if (status.get('card')) {
      media.push(<Card sensitive={status.get('sensitive')} onOpenMedia={this.props.onOpenMedia} card={status.get('card')} />);
      media.push(
        <Card
          sensitive={status.get('sensitive')}
          onOpenMedia={this.props.onOpenMedia}
          card={status.get('card')}
          useBlurhash={settings.getIn(['media', 'use_blurhash'])} />
      );
      mediaIcons.push('link');
    }


M app/javascript/flavours/glitch/features/video/index.jsx => app/javascript/flavours/glitch/features/video/index.jsx +31 -3
@@ 11,7 11,7 @@ import { throttle } from 'lodash';

import { Blurhash } from 'flavours/glitch/components/blurhash';
import { Icon } from 'flavours/glitch/components/icon';
import { displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
import { displayMedia } from 'flavours/glitch/initial_state';

import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';



@@ 129,6 129,7 @@ class Video extends PureComponent {
    muted: PropTypes.bool,
    componentIndex: PropTypes.number,
    autoFocus: PropTypes.bool,
    useBlurhash: PropTypes.bool,
  };

  static defaultProps = {


@@ 509,8 510,35 @@ class Video extends PureComponent {
  }

  render () {
    const { preview, src, inline, onOpenVideo, onCloseVideo, intl, alt, lang, letterbox, fullwidth, detailed, sensitive, editable, blurhash, autoFocus } = this.props;
    const { currentTime, duration, volume, buffer, dragging, paused, fullscreen, hovered, revealed } = this.state;
    const {
      preview,
      src,
      inline,
      onOpenVideo,
      onCloseVideo,
      intl,
      alt,
      lang,
      letterbox,
      fullwidth,
      detailed,
      sensitive,
      editable,
      blurhash,
      autoFocus,
      useBlurhash
    } = this.props;
    const {
      currentTime,
      duration,
      volume,
      buffer,
      dragging,
      paused,
      fullscreen,
      hovered,
      revealed
    } = this.state;
    const progress = Math.min((currentTime / duration) * 100, 100);
    const muted = this.state.muted || volume === 0;


M app/javascript/flavours/glitch/initial_state.js => app/javascript/flavours/glitch/initial_state.js +0 -2
@@ 79,7 79,6 @@
 * @property {boolean} show_trends
 * @property {boolean} trends_as_landing_page
 * @property {boolean} unfollow_modal
 * @property {boolean} use_blurhash
 * @property {boolean=} use_pending_items
 * @property {string} version
 * @property {string} sso_redirect


@@ 158,7 157,6 @@ export const timelinePreview = getMeta('timeline_preview');
export const title = getMeta('title');
export const trendsAsLanding = getMeta('trends_as_landing_page');
export const unfollowModal = getMeta('unfollow_modal');
export const useBlurhash = getMeta('use_blurhash');
export const usePendingItems = getMeta('use_pending_items');
export const version = getMeta('version');
export const languages = initialState?.languages;

M app/javascript/flavours/glitch/reducers/local_settings.js => app/javascript/flavours/glitch/reducers/local_settings.js +1 -0
@@ 45,6 45,7 @@ const initialState = ImmutableMap({
    show_action_bar : true,
  }),
  media     : ImmutableMap({
    use_blurhash     : true,
    letterbox        : false,
    fullwidth        : true,
    reveal_behind_cw : false,