@@ -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' ;
3535import navigationState from '../store/atoms/navigation' ;
3636import speechState from '../store/atoms/speech' ;
3737import stationState from '../store/atoms/station' ;
3838import { themeAtom } from '../store/atoms/theme' ;
3939import { isJapanese , translate } from '../translation' ;
40+ import { showToast } from '../utils/toast' ;
4041import NewReportModal from './NewReportModal' ;
4142import 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+
4357type 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