Skip to content

Commit 4d34621

Browse files
TinyKittenclaude
andcommitted
長押しメニューにランダムテーマ切り替え機能を追加
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7103dab commit 4d34621

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

assets/translations/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,5 +285,7 @@
285285
"presetNamePlaceholder": "Preset name",
286286
"save": "Save",
287287
"selectStartStationTitle": "Select starting station",
288-
"departure": "Dep."
288+
"departure": "Dep.",
289+
"randomTheme": "Random Theme",
290+
"randomThemeChanged": "Theme changed to \"%{themeName}\""
289291
}

assets/translations/ja.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,7 @@
286286
"presetNamePlaceholder": "プリセット名",
287287
"save": "保存",
288288
"selectStartStationTitle": "始発駅を選択",
289-
"departure": "始発"
289+
"departure": "始発",
290+
"randomTheme": "ランダムテーマ",
291+
"randomThemeChanged": "テーマを「%{themeName}」に変更しました"
290292
}

src/components/Permitted.tsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,29 @@ import {
3131
useFeedback,
3232
useWarningInfo,
3333
} from '../hooks';
34-
import type { AppTheme } from '../models/Theme';
34+
import { APP_THEME, type AppTheme } from '../models/Theme';
3535
import navigationState from '../store/atoms/navigation';
3636
import speechState from '../store/atoms/speech';
3737
import stationState from '../store/atoms/station';
3838
import { themeAtom } from '../store/atoms/theme';
3939
import { isJapanese, translate } from '../translation';
40+
import { showToast } from '../utils/toast';
4041
import NewReportModal from './NewReportModal';
4142
import WarningPanel from './WarningPanel';
4243

44+
const THEME_LABEL_KEYS: Record<AppTheme, string> = {
45+
[APP_THEME.TOKYO_METRO]: 'tokyoMetroLike',
46+
[APP_THEME.YAMANOTE]: 'yamanoteLineLike',
47+
[APP_THEME.JR_WEST]: 'jrWestLike',
48+
[APP_THEME.TY]: 'tyLike',
49+
[APP_THEME.SAIKYO]: 'saikyoLineLike',
50+
[APP_THEME.TOEI]: 'toeiLike',
51+
[APP_THEME.LED]: 'ledLike',
52+
[APP_THEME.JO]: 'joLike',
53+
[APP_THEME.JL]: 'jlLike',
54+
[APP_THEME.JR_KYUSHU]: 'jrKyushuLike',
55+
};
56+
4357
type Props = {
4458
children: React.ReactNode;
4559
};
@@ -51,7 +65,7 @@ const PermittedLayout: React.FC<Props> = ({ children }: Props) => {
5165
const setNavigation = useSetAtom(navigationState);
5266
const setSpeech = useSetAtom(speechState);
5367
const setTuning = useSetAtom(tuningState);
54-
const setTheme = useSetAtom(themeAtom);
68+
const [currentTheme, setTheme] = useAtom(themeAtom);
5569
const [reportModalShow, setReportModalShow] = useAtom(reportModalVisibleAtom);
5670
const [sendingReport, setSendingReport] = useState(false);
5771
const [screenShotBase64, setScreenShotBase64] = useState('');
@@ -130,6 +144,33 @@ const PermittedLayout: React.FC<Props> = ({ children }: Props) => {
130144
}
131145
}, [isAppLatest, setReportModalShow]);
132146

147+
const handleRandomTheme = useCallback(async () => {
148+
const allThemes = Object.values(APP_THEME);
149+
const otherThemes = allThemes.filter((t) => t !== currentTheme);
150+
const randomTheme =
151+
otherThemes[Math.floor(Math.random() * otherThemes.length)];
152+
153+
if (!randomTheme) {
154+
return;
155+
}
156+
157+
setTheme(randomTheme);
158+
try {
159+
await AsyncStorage.setItem(
160+
ASYNC_STORAGE_KEYS.PREVIOUS_THEME,
161+
randomTheme
162+
);
163+
} catch (error) {
164+
console.error(error);
165+
}
166+
167+
const themeName = translate(THEME_LABEL_KEYS[randomTheme]);
168+
showToast({
169+
type: 'success',
170+
text1: translate('randomThemeChanged', { themeName }),
171+
});
172+
}, [currentTheme, setTheme]);
173+
133174
const handleShare = useCallback(async () => {
134175
const captureError = (err: unknown) => {
135176
console.error(err);
@@ -216,6 +257,10 @@ const PermittedLayout: React.FC<Props> = ({ children }: Props) => {
216257
label: translate('share'),
217258
handler: handleShare,
218259
},
260+
{
261+
label: translate('randomTheme'),
262+
handler: handleRandomTheme,
263+
},
219264
{
220265
label: translate('report'),
221266
handler: handleReport,
@@ -226,6 +271,10 @@ const PermittedLayout: React.FC<Props> = ({ children }: Props) => {
226271
label: translate('share'),
227272
handler: handleShare,
228273
},
274+
{
275+
label: translate('randomTheme'),
276+
handler: handleRandomTheme,
277+
},
229278
{
230279
label: translate('report'),
231280
handler: handleReport,
@@ -286,6 +335,7 @@ const PermittedLayout: React.FC<Props> = ({ children }: Props) => {
286335
},
287336
[
288337
devOverlayEnabled,
338+
handleRandomTheme,
289339
handleReport,
290340
handleShare,
291341
navigation,

0 commit comments

Comments
 (0)