SettingTopPageとSoundSettingsのリファクタリング、不要なコードの削除とオーディオプレイヤー機能の追加
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import React from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
ScrollView,
|
||||
Linking,
|
||||
Image,
|
||||
Platform,
|
||||
} from "react-native";
|
||||
import * as Updates from "expo-updates";
|
||||
import { useWindowDimensions } from "react-native";
|
||||
@@ -16,16 +15,9 @@ import TouchableScale from "react-native-touchable-scale";
|
||||
import { SwitchArea } from "../atom/SwitchArea";
|
||||
import { useNotification } from "../../stateBox/useNotifications";
|
||||
import { SheetHeaderItem } from "@/components/atom/SheetHeaderItem";
|
||||
import { Asset } from "expo-asset";
|
||||
import {
|
||||
useAudioPlayer,
|
||||
setAudioModeAsync,
|
||||
} from "expo-audio";
|
||||
import type { AudioSource } from "expo-audio";
|
||||
import { useThemeColors, type ColorThemePref } from "@/lib/theme/useThemeColors";
|
||||
|
||||
const versionCode = "6.2.1.1"; // Update this version code as needed
|
||||
const settingsPreviewSound = require("../../assets/sound/rikka-test.mp3");
|
||||
const versionCode = "7.0"; // Update this version code as needed
|
||||
|
||||
export const SettingTopPage = ({
|
||||
testNFC,
|
||||
@@ -38,60 +30,6 @@ export const SettingTopPage = ({
|
||||
const { colors, fixed, colorTheme, setColorTheme } = useThemeColors();
|
||||
const navigation = useNavigation<any>();
|
||||
|
||||
// expo-asset でローカルパスを取得し、expo-audio に渡す
|
||||
const [resolvedSource, setResolvedSource] = useState<AudioSource>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
const resolve = async () => {
|
||||
try {
|
||||
const asset = Asset.fromModule(settingsPreviewSound);
|
||||
await asset.downloadAsync();
|
||||
const localUri = asset.localUri;
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (localUri) {
|
||||
// Android の expo-audio は file:// URI を正しく処理できないため prefix を除去
|
||||
// iOS は file:// プレフィックスが必要なのでそのまま使用
|
||||
const source =
|
||||
Platform.OS === "android"
|
||||
? { uri: localUri.replace(/^file:\/\//, "") }
|
||||
: { uri: localUri };
|
||||
setResolvedSource(source);
|
||||
}
|
||||
} catch (error) {
|
||||
if (!mounted) return;
|
||||
console.warn("Failed to resolve audio asset", error);
|
||||
}
|
||||
};
|
||||
|
||||
resolve();
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const previewPlayer = useAudioPlayer(resolvedSource);
|
||||
|
||||
const onPressHeaderImage = useCallback(async () => {
|
||||
try {
|
||||
// カーナビ風: 他のアプリの音楽を止めず音量を下げて上書き再生 (duckOthers)
|
||||
// iOS: playsInSilentMode: true でサイレントモード時も再生
|
||||
await setAudioModeAsync({
|
||||
playsInSilentMode: true,
|
||||
shouldPlayInBackground: false,
|
||||
interruptionMode: "duckOthers",
|
||||
});
|
||||
if (previewPlayer.playing) previewPlayer.pause();
|
||||
previewPlayer.volume = 1;
|
||||
await previewPlayer.seekTo(0);
|
||||
previewPlayer.play();
|
||||
} catch (error) {
|
||||
console.warn("Failed to play preview sound", error);
|
||||
}
|
||||
}, [previewPlayer]);
|
||||
|
||||
return (
|
||||
<View style={{ height: "100%", backgroundColor: fixed.primary }}>
|
||||
<SheetHeaderItem title="アプリの設定画面" LeftItem={{
|
||||
@@ -101,17 +39,15 @@ export const SettingTopPage = ({
|
||||
<ScrollView style={{ flex: 1, backgroundColor: colors.backgroundSecondary }}>
|
||||
<View style={{ height: 300, padding: 10 }}>
|
||||
<View style={{ flex: 1 }} />
|
||||
<TouchableOpacity activeOpacity={0.9} onPress={onPressHeaderImage}>
|
||||
<Image
|
||||
source={require("../../assets/Header.png")}
|
||||
style={{
|
||||
aspectRatio: 8.08,
|
||||
height: undefined,
|
||||
width: width - 20,
|
||||
borderRadius: 5,
|
||||
}}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<Image
|
||||
source={require("../../assets/Header.png")}
|
||||
style={{
|
||||
aspectRatio: 8.08,
|
||||
height: undefined,
|
||||
width: width - 20,
|
||||
borderRadius: 5,
|
||||
}}
|
||||
/>
|
||||
<View style={{ flexDirection: "row", paddingTop: 10 }}>
|
||||
<View style={{ flex: 1 }} />
|
||||
<Text style={{ color: colors.text }}>内部バージョン: {versionCode}</Text>
|
||||
|
||||
@@ -1,17 +1,58 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { View, Text, ScrollView } from "react-native";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { View, Text, ScrollView, Platform } from "react-native";
|
||||
import { Switch } from "@rneui/themed";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { SheetHeaderItem } from "@/components/atom/SheetHeaderItem";
|
||||
import { AS } from "../../storageControl";
|
||||
import { STORAGE_KEYS } from "@/constants";
|
||||
import { useThemeColors } from "@/lib/theme";
|
||||
import { Asset } from "expo-asset";
|
||||
import { useAudioPlayer, setAudioModeAsync } from "expo-audio";
|
||||
import type { AudioSource } from "expo-audio";
|
||||
|
||||
const previewSound = require("../../assets/sound/rikka-test.mp3");
|
||||
|
||||
export const SoundSettings = () => {
|
||||
const { goBack } = useNavigation();
|
||||
const { colors, fixed } = useThemeColors();
|
||||
const [delayAnnouncement, setDelayAnnouncement] = useState(false);
|
||||
|
||||
// expo-asset でローカルパスを取得し、expo-audio に渡す
|
||||
const [resolvedSource, setResolvedSource] = useState<AudioSource>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
const resolve = async () => {
|
||||
try {
|
||||
const asset = Asset.fromModule(previewSound);
|
||||
await asset.downloadAsync();
|
||||
const localUri = asset.localUri;
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (localUri) {
|
||||
// Android の expo-audio は file:// URI を正しく処理できないため prefix を除去
|
||||
// iOS は file:// プレフィックスが必要なのでそのまま使用
|
||||
const source =
|
||||
Platform.OS === "android"
|
||||
? { uri: localUri.replace(/^file:\/\//, "") }
|
||||
: { uri: localUri };
|
||||
setResolvedSource(source);
|
||||
}
|
||||
} catch (error) {
|
||||
if (!mounted) return;
|
||||
console.warn("Failed to resolve audio asset", error);
|
||||
}
|
||||
};
|
||||
|
||||
resolve();
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const previewPlayer = useAudioPlayer(resolvedSource);
|
||||
|
||||
useEffect(() => {
|
||||
AS.getItem(STORAGE_KEYS.SOUND_DELAY_ANNOUNCEMENT)
|
||||
.then((v) => setDelayAnnouncement(v === true || v === "true"))
|
||||
@@ -20,9 +61,28 @@ export const SoundSettings = () => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const playPreview = useCallback(async () => {
|
||||
try {
|
||||
await setAudioModeAsync({
|
||||
playsInSilentMode: true,
|
||||
shouldPlayInBackground: false,
|
||||
interruptionMode: "duckOthers",
|
||||
});
|
||||
if (previewPlayer.playing) previewPlayer.pause();
|
||||
previewPlayer.volume = 1;
|
||||
await previewPlayer.seekTo(0);
|
||||
previewPlayer.play();
|
||||
} catch (error) {
|
||||
console.warn("Failed to play preview sound", error);
|
||||
}
|
||||
}, [previewPlayer]);
|
||||
|
||||
const handleToggle = (value: boolean) => {
|
||||
setDelayAnnouncement(value);
|
||||
AS.setItem(STORAGE_KEYS.SOUND_DELAY_ANNOUNCEMENT, value.toString());
|
||||
if (value) {
|
||||
playPreview();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user