DataSourceAccordionCardコンポーネントを追加し、鉄道運用Hubのデータソース設定を改善
This commit is contained in:
@@ -1,12 +1,151 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { View, Text, ScrollView, StyleSheet } from "react-native";
|
||||
import { View, Text, ScrollView, StyleSheet, Image, TouchableOpacity, Linking } from "react-native";
|
||||
import { Switch } from "react-native-elements";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { SheetHeaderItem } from "@/components/atom/SheetHeaderItem";
|
||||
import { AS } from "../../storageControl";
|
||||
import { STORAGE_KEYS } from "@/constants";
|
||||
import { useTrainMenu } from "@/stateBox/useTrainMenu";
|
||||
|
||||
const HUB_LOGO_PNG = require("@/assets/icons/hub_logo.png");
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* DataSourceAccordionCard */
|
||||
/* ------------------------------------------------------------------ */
|
||||
type Feature = { icon: string; label: string; text: string };
|
||||
|
||||
type DataSourceAccordionCardProps = {
|
||||
/** ロゴ画像 (require) */
|
||||
logo: any;
|
||||
/** アクセントカラー */
|
||||
accentColor: string;
|
||||
/** データソース名 */
|
||||
title: string;
|
||||
/** 1行サブタイトル */
|
||||
tagline: string;
|
||||
/** スイッチの値 */
|
||||
enabled: boolean;
|
||||
/** スイッチ変更ハンドラ */
|
||||
onToggle: (v: boolean) => void;
|
||||
/** 説明文 */
|
||||
description: string;
|
||||
/** 機能リスト */
|
||||
features: Feature[];
|
||||
/** フッターリンクラベル */
|
||||
linkLabel: string;
|
||||
/** フッターリンク URL */
|
||||
linkUrl: string;
|
||||
};
|
||||
|
||||
const DataSourceAccordionCard: React.FC<DataSourceAccordionCardProps> = ({
|
||||
logo,
|
||||
accentColor,
|
||||
title,
|
||||
tagline,
|
||||
enabled,
|
||||
onToggle,
|
||||
description,
|
||||
features,
|
||||
linkLabel,
|
||||
linkUrl,
|
||||
}) => {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
return (
|
||||
<View style={[styles.accordionCard, enabled && styles.accordionCardEnabled]}>
|
||||
{/* ── ヘッダー行(常時表示) ── */}
|
||||
<View style={styles.accordionHeader}>
|
||||
{/* 左:ロゴ */}
|
||||
<Image source={logo} style={styles.accordionLogo} />
|
||||
|
||||
{/* 中央:タイトル+タグライン */}
|
||||
<View style={styles.accordionTitles}>
|
||||
<Text style={styles.accordionTitle}>{title}</Text>
|
||||
<Text style={styles.accordionTagline}>{tagline}</Text>
|
||||
</View>
|
||||
|
||||
{/* 右:スイッチ */}
|
||||
<Switch
|
||||
value={enabled}
|
||||
onValueChange={onToggle}
|
||||
color={accentColor}
|
||||
style={styles.accordionSwitch}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* スイッチ状態テキスト */}
|
||||
<View style={styles.accordionStatusRow}>
|
||||
<View style={[styles.statusDot, { backgroundColor: enabled ? accentColor : "#ccc" }]} />
|
||||
<Text style={[styles.statusText, { color: enabled ? accentColor : "#aaa" }]}>
|
||||
{enabled ? "有効 — 編成データを取得します" : "無効 — データを取得しません"}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* ── 展開トリガー ── */}
|
||||
<TouchableOpacity
|
||||
style={styles.accordionToggleRow}
|
||||
onPress={() => setExpanded((v) => !v)}
|
||||
activeOpacity={0.6}
|
||||
>
|
||||
<Text style={styles.accordionToggleLabel}>
|
||||
{expanded ? "詳細を閉じる" : "鉄道運用Hub について"}
|
||||
</Text>
|
||||
<MaterialCommunityIcons
|
||||
name={expanded ? "chevron-up" : "chevron-down"}
|
||||
size={16}
|
||||
color="#888"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* ── 展開コンテンツ ── */}
|
||||
{expanded && (
|
||||
<View style={styles.accordionBody}>
|
||||
{/* 説明文 */}
|
||||
<Text style={styles.bodyDesc}>{description}</Text>
|
||||
|
||||
{/* 機能リスト */}
|
||||
<View style={styles.bodyFeatures}>
|
||||
{features.map((f) => (
|
||||
<View key={f.icon} style={styles.featureRow}>
|
||||
<View style={styles.featureIcon}>
|
||||
<MaterialCommunityIcons name={f.icon as any} size={14} color="#444" />
|
||||
</View>
|
||||
<Text style={styles.featureLabel}>{f.label}</Text>
|
||||
<Text style={styles.featureText}>{f.text}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* リンク */}
|
||||
<TouchableOpacity
|
||||
style={styles.bodyLink}
|
||||
onPress={() => Linking.openURL(linkUrl)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<MaterialCommunityIcons name="open-in-new" size={13} color="#555" />
|
||||
<Text style={styles.bodyLinkText}>{linkLabel}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 定数 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
const UNYOHUB_FEATURES: Feature[] = [
|
||||
{ icon: "map-marker-radius-outline", label: "走行位置", text: "どの編成がどの駅間を走っているかリアルタイムで確認" },
|
||||
{ icon: "timetable", label: "時刻表", text: "充当編成情報付きの駅時刻表を閲覧" },
|
||||
{ icon: "clipboard-list-outline", label: "運用データ", text: "一日の全運用を一覧表示・過去日付への遡り閲覧" },
|
||||
{ icon: "train-car", label: "編成表", text: "車両メーカー・竣工日・運用履歴を閲覧" },
|
||||
{ icon: "table-search", label: "運用表", text: "列車番号・両数・出庫場所などで運用を検索" },
|
||||
];
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* DataSourceSettings */
|
||||
/* ------------------------------------------------------------------ */
|
||||
export const DataSourceSettings = () => {
|
||||
const navigation = useNavigation();
|
||||
const { updatePermission, dataSourcePermission } = useTrainMenu();
|
||||
@@ -40,41 +179,39 @@ export const DataSourceSettings = () => {
|
||||
<Text style={styles.noPermissionSubText}>鉄道運用Hubまたはアプリ管理者の権限が必要です。</Text>
|
||||
</View>
|
||||
) : (
|
||||
<ScrollView style={styles.content}>
|
||||
<View style={styles.section}>
|
||||
<ScrollView style={styles.content} contentContainerStyle={styles.contentInner}>
|
||||
<Text style={styles.sectionTitle}>外部データソース</Text>
|
||||
|
||||
<View style={styles.settingItem}>
|
||||
<View style={styles.settingTextContainer}>
|
||||
<Text style={styles.settingTitle}>鉄道運用Hub</Text>
|
||||
<Text style={styles.settingDescription}>
|
||||
列車の運用番号(車両編成番号)を表示します。
|
||||
{"\n"}
|
||||
データがある列車では地図上に黄色いマークが表示され、列車情報画面のデータベースアイコンも黄色になります。
|
||||
</Text>
|
||||
</View>
|
||||
<Switch
|
||||
value={useUnyohub}
|
||||
onValueChange={handleToggleUnyohub}
|
||||
color="#0099CC"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.infoSection}>
|
||||
<Text style={styles.infoText}>
|
||||
情報ソース設定は、外部のコミュニティデータソースとの連携を管理します。
|
||||
{"\n\n"}
|
||||
データの正確性は保証されません。参考情報としてご利用ください。
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<DataSourceAccordionCard
|
||||
logo={HUB_LOGO_PNG}
|
||||
accentColor="#0099CC"
|
||||
title="鉄道運用Hub"
|
||||
tagline="コミュニティによる列車運用情報サービス"
|
||||
enabled={useUnyohub}
|
||||
onToggle={handleToggleUnyohub}
|
||||
description={
|
||||
"鉄道ファン有志の目撃情報をもとに、どの編成がどの列車に充当されているかをリアルタイムで共有・確認できる無料 Web サービスです。JR 四国をはじめ全国多数の路線系統に対応しています。\n\nデータがある列車では地図上に黄色いマークが表示され、列車情報画面の編成表示も更新されます。"
|
||||
}
|
||||
features={UNYOHUB_FEATURES}
|
||||
linkLabel="unyohub.2pd.jp を開く(JR四国)"
|
||||
linkUrl="https://unyohub.2pd.jp/railroad_shikoku/"
|
||||
/>
|
||||
|
||||
<View style={styles.infoSection}>
|
||||
<Text style={styles.infoText}>
|
||||
情報ソース設定は、外部のコミュニティデータソースとの連携を管理します。
|
||||
{"\n\n"}
|
||||
データの正確性は保証されません。参考情報としてご利用ください。
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
/* ── 権限なし ── */
|
||||
noPermissionContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8f8fc",
|
||||
@@ -94,6 +231,7 @@ const styles = StyleSheet.create({
|
||||
color: "#666",
|
||||
textAlign: "center",
|
||||
},
|
||||
/* ── レイアウト ── */
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#0099CC",
|
||||
@@ -102,46 +240,152 @@ const styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
backgroundColor: "#f8f8fc",
|
||||
},
|
||||
section: {
|
||||
backgroundColor: "white",
|
||||
marginTop: 20,
|
||||
marginHorizontal: 10,
|
||||
borderRadius: 10,
|
||||
padding: 15,
|
||||
contentInner: {
|
||||
paddingHorizontal: 14,
|
||||
paddingBottom: 40,
|
||||
gap: 12,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "bold",
|
||||
color: "#333",
|
||||
marginBottom: 15,
|
||||
fontSize: 13,
|
||||
fontWeight: "600",
|
||||
color: "#888",
|
||||
letterSpacing: 0.5,
|
||||
marginTop: 20,
|
||||
marginLeft: 4,
|
||||
},
|
||||
settingItem: {
|
||||
/* ── アコーディオンカード ── */
|
||||
accordionCard: {
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 14,
|
||||
borderWidth: 1,
|
||||
borderColor: "#e4e4e4",
|
||||
overflow: "hidden",
|
||||
},
|
||||
accordionCardEnabled: {
|
||||
borderColor: "#0099CC44",
|
||||
},
|
||||
accordionHeader: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 14,
|
||||
paddingTop: 14,
|
||||
paddingBottom: 6,
|
||||
gap: 10,
|
||||
},
|
||||
settingTextContainer: {
|
||||
accordionLogo: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 8,
|
||||
flexShrink: 0,
|
||||
},
|
||||
accordionTitles: {
|
||||
flex: 1,
|
||||
marginRight: 10,
|
||||
gap: 2,
|
||||
},
|
||||
settingTitle: {
|
||||
fontSize: 16,
|
||||
accordionTitle: {
|
||||
fontSize: 15,
|
||||
fontWeight: "bold",
|
||||
color: "#111",
|
||||
},
|
||||
accordionTagline: {
|
||||
fontSize: 11,
|
||||
color: "#888",
|
||||
},
|
||||
accordionSwitch: {
|
||||
flexShrink: 0,
|
||||
},
|
||||
accordionStatusRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
paddingHorizontal: 14,
|
||||
paddingBottom: 10,
|
||||
},
|
||||
statusDot: {
|
||||
width: 7,
|
||||
height: 7,
|
||||
borderRadius: 4,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 12,
|
||||
fontWeight: "500",
|
||||
},
|
||||
/* ── 展開トリガー ── */
|
||||
accordionToggleRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 10,
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: "#ebebeb",
|
||||
},
|
||||
accordionToggleLabel: {
|
||||
fontSize: 12,
|
||||
color: "#666",
|
||||
fontWeight: "500",
|
||||
},
|
||||
/* ── 展開コンテンツ ── */
|
||||
accordionBody: {
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: "#ebebeb",
|
||||
padding: 14,
|
||||
gap: 10,
|
||||
backgroundColor: "#fafafa",
|
||||
},
|
||||
bodyDesc: {
|
||||
fontSize: 12,
|
||||
color: "#444",
|
||||
lineHeight: 19,
|
||||
},
|
||||
bodyFeatures: {
|
||||
gap: 7,
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: "#e4e4e4",
|
||||
paddingTop: 8,
|
||||
},
|
||||
featureRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "flex-start",
|
||||
gap: 6,
|
||||
},
|
||||
featureIcon: {
|
||||
width: 22,
|
||||
alignItems: "center",
|
||||
paddingTop: 1,
|
||||
flexShrink: 0,
|
||||
},
|
||||
featureLabel: {
|
||||
fontSize: 12,
|
||||
fontWeight: "bold",
|
||||
color: "#333",
|
||||
marginBottom: 5,
|
||||
width: 62,
|
||||
flexShrink: 0,
|
||||
},
|
||||
settingDescription: {
|
||||
fontSize: 13,
|
||||
color: "#666",
|
||||
lineHeight: 18,
|
||||
featureText: {
|
||||
fontSize: 12,
|
||||
color: "#555",
|
||||
flex: 1,
|
||||
lineHeight: 17,
|
||||
},
|
||||
bodyLink: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 5,
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: "#e4e4e4",
|
||||
paddingTop: 8,
|
||||
marginTop: 2,
|
||||
},
|
||||
bodyLinkText: {
|
||||
fontSize: 12,
|
||||
color: "#555",
|
||||
},
|
||||
/* ── 注意書き ── */
|
||||
infoSection: {
|
||||
backgroundColor: "#fff3cd",
|
||||
marginTop: 20,
|
||||
marginHorizontal: 10,
|
||||
borderRadius: 10,
|
||||
padding: 15,
|
||||
marginBottom: 30,
|
||||
padding: 14,
|
||||
},
|
||||
infoText: {
|
||||
fontSize: 13,
|
||||
|
||||
Reference in New Issue
Block a user