Merge commit '520974e05211e988b0447f7f29e88798b1794bcf' into glitch-soc/merge-upstream

Conflicts:
- `app/serializers/rest/status_serializer.rb`:
  Not a real conflict, just glitch-soc code textually adjacent to code added
  upstream.
This commit is contained in:
Claire committed 2025-06-05 18:02:40 +02:00
commit 2085b0b53a
48 files changed
+446 -177

No files matched your search

@@ -8,6 +8,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import Textarea from 'react-textarea-autosize';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
const messages = defineMessages({
placeholder: { id: 'account_note.placeholder', defaultMessage: 'Click to add a note' },
});
@@ -153,17 +155,23 @@ class AccountNote extends ImmutablePureComponent {
<FormattedMessage id='account.account_note_header' defaultMessage='Personal note' /> <InlineAlert show={saved} />
</label>
<Textarea
id={`account-note-${accountId}`}
className='account__header__account-note__content'
disabled={this.props.value === null || value === null}
placeholder={intl.formatMessage(messages.placeholder)}
value={value || ''}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
onBlur={this.handleBlur}
ref={this.setTextareaRef}
/>
{this.props.value === undefined ? (
<div className='account__header__account-note__loading-indicator-wrapper'>
<LoadingIndicator />
</div>
) : (
<Textarea
id={`account-note-${accountId}`}
className='account__header__account-note__content'
disabled={value === null}
placeholder={intl.formatMessage(messages.placeholder)}
value={value || ''}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
onBlur={this.handleBlur}
ref={this.setTextareaRef}
/>
)}
</div>
);
}
@@ -17,6 +17,7 @@ import { Blurhash } from 'mastodon/components/blurhash';
import { Icon } from 'mastodon/components/icon';
import { SpoilerButton } from 'mastodon/components/spoiler_button';
import { formatTime, getPointerPosition } from 'mastodon/features/video';
import { useAudioContext } from 'mastodon/hooks/useAudioContext';
import { useAudioVisualizer } from 'mastodon/hooks/useAudioVisualizer';
import {
displayMedia,
@@ -119,12 +120,17 @@ export const Audio: React.FC<{
const seekRef = useRef<HTMLDivElement>(null);
const volumeRef = useRef<HTMLDivElement>(null);
const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>();
const [resumeAudio, suspendAudio, frequencyBands] = useAudioVisualizer(
audioRef,
3,
);
const accessibilityId = useId();
const { audioContextRef, sourceRef, gainNodeRef, playAudio, pauseAudio } =
useAudioContext({ audioElementRef: audioRef });
const frequencyBands = useAudioVisualizer({
audioContextRef,
sourceRef,
numBands: 3,
});
const [style, spring] = useSpring(() => ({
progress: '0%',
buffer: '0%',
@@ -152,6 +158,9 @@ export const Audio: React.FC<{
restoreVolume(audioRef.current);
setVolume(audioRef.current.volume);
setMuted(audioRef.current.muted);
if (gainNodeRef.current) {
gainNodeRef.current.gain.value = audioRef.current.volume;
}
void spring.start({
volume: `${audioRef.current.volume * 100}%`,
immediate: reduceMotion,
@@ -159,15 +168,14 @@ export const Audio: React.FC<{
}
},
[
spring,
setVolume,
setMuted,
deployPictureInPicture,
src,
poster,
backgroundColor,
accentColor,
foregroundColor,
deployPictureInPicture,
accentColor,
gainNodeRef,
spring,
],
);
@@ -178,7 +186,11 @@ export const Audio: React.FC<{
audioRef.current.volume = volume;
audioRef.current.muted = muted;
}, [volume, muted]);
if (gainNodeRef.current) {
gainNodeRef.current.gain.value = muted ? 0 : volume;
}
}, [volume, muted, gainNodeRef]);
useEffect(() => {
if (typeof visible !== 'undefined') {
@@ -192,11 +204,10 @@ export const Audio: React.FC<{
}, [visible, sensitive]);
useEffect(() => {
if (!revealed && audioRef.current) {
audioRef.current.pause();
suspendAudio();
if (!revealed) {
pauseAudio();
}
}, [suspendAudio, revealed]);
}, [pauseAudio, revealed]);
useEffect(() => {
let nextFrame: ReturnType<typeof requestAnimationFrame>;
@@ -228,13 +239,11 @@ export const Audio: React.FC<{
}
if (audioRef.current.paused) {
resumeAudio();
void audioRef.current.play();
playAudio();
} else {
audioRef.current.pause();
suspendAudio();
pauseAudio();
}
}, [resumeAudio, suspendAudio]);
}, [playAudio, pauseAudio]);
const handlePlay = useCallback(() => {
setPaused(false);
@@ -349,8 +358,7 @@ export const Audio: React.FC<{
document.removeEventListener('mouseup', handleSeekMouseUp, true);
setDragging(false);
resumeAudio();
void audioRef.current?.play();
playAudio();
};
const handleSeekMouseMove = (e: MouseEvent) => {
@@ -377,7 +385,7 @@ export const Audio: React.FC<{
e.preventDefault();
e.stopPropagation();
},
[setDragging, spring, resumeAudio],
[playAudio, spring],
);
const handleMouseEnter = useCallback(() => {
@@ -446,10 +454,9 @@ export const Audio: React.FC<{
const handleCanPlayThrough = useCallback(() => {
if (startPlaying) {
resumeAudio();
void audioRef.current?.play();
playAudio();
}
}, [startPlaying, resumeAudio]);
}, [startPlaying, playAudio]);
const seekBy = (time: number) => {
if (!audioRef.current) {
@@ -492,7 +499,7 @@ export const Audio: React.FC<{
return;
}
const newVolume = audioRef.current.volume + step;
const newVolume = Math.max(0, audioRef.current.volume + step);
if (!isNaN(newVolume)) {
audioRef.current.volume = newVolume;
@@ -40,6 +40,19 @@ export const ColumnSettings: React.FC = () => {
}
/>
<SettingToggle
prefix='home_timeline'
settings={settings}
settingPath={['shows', 'quote']}
onChange={onChange}
label={
<FormattedMessage
id='home.column_settings.show_quotes'
defaultMessage='Show quotes'
/>
}
/>
<SettingToggle
prefix='home_timeline'
settings={settings}
@@ -17,19 +17,22 @@ const makeGetStatusIds = (pending = false) => createSelector([
if (id === null || id === 'inline-follow-suggestions') return true;
const statusForId = statuses.get(id);
let showStatus = true;
if (statusForId.get('account') === me) return true;
if (columnSettings.getIn(['shows', 'reblog']) === false) {
showStatus = showStatus && statusForId.get('reblog') === null;
if (columnSettings.getIn(['shows', 'reblog']) === false && statusForId.get('reblog') !== null) {
return false;
}
if (columnSettings.getIn(['shows', 'reply']) === false) {
showStatus = showStatus && (statusForId.get('in_reply_to_id') === null || statusForId.get('in_reply_to_account_id') === me);
if (columnSettings.getIn(['shows', 'reply']) === false && statusForId.get('in_reply_to_id') !== null && statusForId.get('in_reply_to_account_id') !== me) {
return false;
}
return showStatus;
if (columnSettings.getIn(['shows', 'quote']) === false && statusForId.get('quote') !== null) {
return false;
}
return true;
});
});