From 87f1cf2b1efbd7c8cfcfeb5fa3fca90fec8e503c Mon Sep 17 00:00:00 2001 From: harukin-expo-dev-env Date: Wed, 4 Mar 2026 14:55:18 +0000 Subject: [PATCH] =?UTF-8?q?DataSourceAccordionCard=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=81=97=E3=80=81=E9=89=84=E9=81=93=E9=81=8B=E7=94=A8?= =?UTF-8?q?Hub=E3=81=AE=E3=83=87=E3=83=BC=E3=82=BF=E3=82=BD=E3=83=BC?= =?UTF-8?q?=E3=82=B9=E8=A8=AD=E5=AE=9A=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Settings/DataSourceSettings.tsx | 350 +++++++++++++++++---- 1 file changed, 297 insertions(+), 53 deletions(-) diff --git a/components/Settings/DataSourceSettings.tsx b/components/Settings/DataSourceSettings.tsx index 41153fa..c28d36d 100644 --- a/components/Settings/DataSourceSettings.tsx +++ b/components/Settings/DataSourceSettings.tsx @@ -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 = ({ + logo, + accentColor, + title, + tagline, + enabled, + onToggle, + description, + features, + linkLabel, + linkUrl, +}) => { + const [expanded, setExpanded] = useState(false); + + return ( + + {/* ── ヘッダー行(常時表示) ── */} + + {/* 左:ロゴ */} + + + {/* 中央:タイトル+タグライン */} + + {title} + {tagline} + + + {/* 右:スイッチ */} + + + + {/* スイッチ状態テキスト */} + + + + {enabled ? "有効 — 編成データを取得します" : "無効 — データを取得しません"} + + + + {/* ── 展開トリガー ── */} + setExpanded((v) => !v)} + activeOpacity={0.6} + > + + {expanded ? "詳細を閉じる" : "鉄道運用Hub について"} + + + + + {/* ── 展開コンテンツ ── */} + {expanded && ( + + {/* 説明文 */} + {description} + + {/* 機能リスト */} + + {features.map((f) => ( + + + + + {f.label} + {f.text} + + ))} + + + {/* リンク */} + Linking.openURL(linkUrl)} + activeOpacity={0.7} + > + + {linkLabel} + + + )} + + ); +}; + +/* ------------------------------------------------------------------ */ +/* 定数 */ +/* ------------------------------------------------------------------ */ +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 = () => { 鉄道運用Hubまたはアプリ管理者の権限が必要です。 ) : ( - - + 外部データソース - - - - 鉄道運用Hub - - 列車の運用番号(車両編成番号)を表示します。 - {"\n"} - データがある列車では地図上に黄色いマークが表示され、列車情報画面のデータベースアイコンも黄色になります。 - - - - - - - - 情報ソース設定は、外部のコミュニティデータソースとの連携を管理します。 - {"\n\n"} - データの正確性は保証されません。参考情報としてご利用ください。 - - - + + + + + 情報ソース設定は、外部のコミュニティデータソースとの連携を管理します。 + {"\n\n"} + データの正確性は保証されません。参考情報としてご利用ください。 + + + )} ); }; 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,