Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions src/app/(app)/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Icon } from '@/components/icon';
import { SafeAreaView } from '@/components/safe-area-view';
import { UpdateDialog } from '@/components/update-dialog';
import { SITE_DOMAINS, SITE_DOMAIN_KEY, type SiteDomain } from '@/lib/hanime1/endpoints';
import { type ThemeMode, useThemeConfig } from '@/lib/hooks';
import { type ThemeMode, usePlaybackSettings, useThemeConfig } from '@/lib/hooks';
import { useSecuritySettings } from '@/lib/hooks/use-security-settings';
import { useUpdateCheck } from '@/lib/hooks/use-update-check';
import { LANGUAGE_LABELS, type Language } from '@/lib/i18n/resources';
Expand All @@ -16,7 +16,15 @@ import { Env } from '@env';
// bundles (binding missing at runtime), destructuring after import works.
import * as ApplicationNS from 'expo-application';
import { ActivityAction, startActivityAsync } from 'expo-intent-launcher';
import { ActivityIndicator, Platform, Pressable, ScrollView, Text, View } from 'react-native';
import {
ActivityIndicator,
Platform,
Pressable,
ScrollView,
Switch,
Text,
View,
} from 'react-native';
import { showMessage } from 'react-native-flash-message';
import { useMMKVString } from 'react-native-mmkv';

Expand Down Expand Up @@ -106,6 +114,7 @@ export { ScreenErrorBoundary as ErrorBoundary };
export default function SettingsScreen() {
const t = useTranslate();
const [theme, setTheme] = useThemeConfig();
const { autoplay, setAutoplay } = usePlaybackSettings();
const [domain, setDomain] = useMMKVString(SITE_DOMAIN_KEY);
const [lang, setLang] = useSelectedLanguage();
const clearHistory = useHistoryStore((s) => s.clearHistory);
Expand Down Expand Up @@ -140,6 +149,15 @@ export default function SettingsScreen() {
))}
</Row>

<SectionTitle>{t('settings.playback')}</SectionTitle>
<Row label={t('settings.autoplay')} description={t('settings.autoplayDesc')}>
<Switch
value={autoplay}
onValueChange={setAutoplay}
trackColor={{ true: '#f43f5e', false: '#a1a1aa' }}
/>
</Row>

<SectionTitle>{t('settings.domain')}</SectionTitle>
<Row label={t('settings.domain')} description={t('settings.domainDescription')}>
{SITE_DOMAINS.map((d) => (
Expand Down
18 changes: 17 additions & 1 deletion src/app/watch/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { SafeAreaView } from '@/components/safe-area-view';
import { toOfflineDetail } from '@/lib/download/offline-detail';
import { buildUrl, endpoints } from '@/lib/hanime1/scraper';
import { haptic, hapticSuccess } from '@/lib/haptics';
import { useVideoDownload } from '@/lib/hooks';
import { usePlaybackSettings, useVideoDownload } from '@/lib/hooks';
import { useTranslate } from '@/lib/i18n/utils';
import {
useDownloadedStore,
Expand Down Expand Up @@ -79,6 +79,22 @@ export default function WatchScreen() {
});
const { isPlaying } = useEvent(player, 'playingChange', { isPlaying: player.playing });

const { autoplay } = usePlaybackSettings();

// Start playback automatically when the screen is entered or the source
// changes (new video via the stack, or a resolution switch) unless the
// user opted out in Settings. Coming back from a deeper screen (author /
// tag) stays paused — the focus cleanup below paused it on leave.
// biome-ignore lint/correctness/useExhaustiveDependencies: videoSource is an intentional trigger — replay when the source lands or switches.
useEffect(() => {
if (!autoplay) return;
try {
player.play();
} catch {
// Player not attached to a source yet — replays when videoSource lands.
}
}, [autoplay, player, videoSource]);

// Pause when this screen loses focus (opening the author page, a tag page or
// another video keeps this screen mounted in the stack — without this, its
// audio keeps playing under the new screen). On unmount expo-video may
Expand Down
1 change: 1 addition & 0 deletions src/lib/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {
PORTRAIT_MIN_TILE_WIDTH,
useColumns,
} from './use-columns';
export { usePlaybackSettings } from './use-playback-settings';
export { useSearchHistory } from './use-search-history';
export { useUpdateCheck, type UpdateCheckState } from './use-update-check';
export { useVideoActions, type ActionableItem } from './use-video-actions';
Expand Down
16 changes: 16 additions & 0 deletions src/lib/hooks/use-playback-settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useMMKVBoolean } from 'react-native-mmkv';

const AUTOPLAY_KEY = 'settings.autoplay';

/**
* Toggle for "Autoplay on entering the watch screen" — on by default.
* `undefined` (never set) reads as enabled; an explicit `false` opts out.
*/
export const usePlaybackSettings = () => {
const [autoplay, setAutoplay] = useMMKVBoolean(AUTOPLAY_KEY);

return {
autoplay: autoplay ?? true,
setAutoplay,
};
};
3 changes: 3 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
"themeSystem": "System",
"themeLight": "Light",
"themeDark": "Dark",
"playback": "Playback",
"autoplay": "Autoplay",
"autoplayDesc": "Start playing automatically when you open a video",
"domain": "Source domain",
"domainDescription": "Switch mirror if the default is blocked or slow",
"openLinks": "Open site links",
Expand Down
3 changes: 3 additions & 0 deletions src/translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
"themeSystem": "システム",
"themeLight": "ライト",
"themeDark": "ダーク",
"playback": "再生",
"autoplay": "自動再生",
"autoplayDesc": "再生画面を開いたときに自動で再生する",
"domain": "ソースドメイン",
"domainDescription": "デフォルトがブロックまたは遅い場合はミラーを切り替えてください",
"openLinks": "サイトリンクを開く",
Expand Down
3 changes: 3 additions & 0 deletions src/translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
"themeSystem": "시스템",
"themeLight": "라이트",
"themeDark": "다크",
"playback": "재생",
"autoplay": "자동 재생",
"autoplayDesc": "재생 화면을 열면 자동으로 재생",
"domain": "소스 도메인",
"domainDescription": "기본 도메인이 차단되거나 느리면 미러를 전환하세요",
"openLinks": "사이트 링크 열기",
Expand Down
3 changes: 3 additions & 0 deletions src/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
"themeSystem": "跟随系统",
"themeLight": "浅色",
"themeDark": "深色",
"playback": "播放",
"autoplay": "自动播放",
"autoplayDesc": "进入播放页时自动开始播放",
"domain": "数据源域名",
"domainDescription": "若默认域名被封锁或缓慢,可切换镜像",
"openLinks": "打开站点链接",
Expand Down
3 changes: 3 additions & 0 deletions src/translations/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
"themeSystem": "跟隨系統",
"themeLight": "淺色",
"themeDark": "深色",
"playback": "播放",
"autoplay": "自動播放",
"autoplayDesc": "進入播放頁時自動開始播放",
"domain": "資料來源網域",
"domainDescription": "若預設網域被封鎖或緩慢,可切換鏡像",
"openLinks": "開啟站點連結",
Expand Down