diff --git a/android/app/build.gradle b/android/app/build.gradle
index b5b350855..9f2340532 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -143,12 +143,12 @@ android {
dimension "environment"
applicationId "me.tinykitten.trainlcd.dev"
versionNameSuffix "-dev"
- versionCode 100000532
+ versionCode 100000533
versionName "10.9.1"
}
prod {
dimension "environment"
- versionCode 100000532
+ versionCode 100000533
versionName "10.9.1"
}
}
diff --git a/app.config.ts b/app.config.ts
index b0afef226..ad558ecbb 100644
--- a/app.config.ts
+++ b/app.config.ts
@@ -52,7 +52,7 @@ export default {
},
},
ios: {
- buildNumber: '2745',
+ buildNumber: '2746',
scheme: IS_DEV ? 'CanaryTrainLCD' : 'ProdTrainLCD',
bundleIdentifier: IS_DEV ? 'me.tinykitten.trainlcd.dev' : 'me.tinykitten.trainlcd',
supportsTablet: true,
@@ -60,7 +60,7 @@ export default {
android: {
package: IS_DEV ? 'me.tinykitten.trainlcd.dev' : 'me.tinykitten.trainlcd',
permissions: [],
- versionCode: 100000532,
+ versionCode: 100000533,
},
owner: 'trainlcd',
experiments: {
diff --git a/ios/TrainLCD.xcodeproj/project.pbxproj b/ios/TrainLCD.xcodeproj/project.pbxproj
index 8ca5a2965..224cd33ab 100644
--- a/ios/TrainLCD.xcodeproj/project.pbxproj
+++ b/ios/TrainLCD.xcodeproj/project.pbxproj
@@ -2407,7 +2407,7 @@
CODE_SIGN_ENTITLEMENTS = ProdTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Prod/Info.plist;
@@ -2446,7 +2446,7 @@
CODE_SIGN_ENTITLEMENTS = ProdTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Prod/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TrainLCD;
@@ -2505,7 +2505,7 @@
CODE_SIGN_ENTITLEMENTS = TrainLCD/trainlcd.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
CXX = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang++.sh";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -2611,7 +2611,7 @@
CODE_SIGN_ENTITLEMENTS = TrainLCD/trainlcd.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
CXX = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang++.sh";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -2690,7 +2690,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Dev/Info.plist;
@@ -2729,7 +2729,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Dev/Info.plist;
@@ -2940,7 +2940,7 @@
CODE_SIGN_ENTITLEMENTS = RideSessionActivity/CanaryRideSessionActivity.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -2991,7 +2991,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -3042,7 +3042,7 @@
CODE_SIGN_ENTITLEMENTS = WatchWidget/ProdWatchWidget.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -3100,7 +3100,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -3151,7 +3151,7 @@
CODE_SIGN_ENTITLEMENTS = WatchWidget/CanaryWatchWidget.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -3208,7 +3208,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -3256,7 +3256,7 @@
CODE_SIGN_ENTITLEMENTS = RideSessionActivity/ProdRideSessionActivity.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -3307,7 +3307,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -3526,7 +3526,7 @@
CODE_SIGN_ENTITLEMENTS = ProdAppClip/ProdAppClip.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -3582,7 +3582,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -3632,7 +3632,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryAppClip/CanaryAppClip.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -3690,7 +3690,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2745;
+ CURRENT_PROJECT_VERSION = 2746;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
diff --git a/src/screens/SelectLineScreen.render.test.tsx b/src/screens/SelectLineScreen.render.test.tsx
index c8c2b2038..c749030a2 100644
--- a/src/screens/SelectLineScreen.render.test.tsx
+++ b/src/screens/SelectLineScreen.render.test.tsx
@@ -282,16 +282,18 @@ describe('SelectLineScreen', () => {
});
describe('ローディング状態', () => {
- it('nearbyStationLoading=true のときスケルトンが表示される', () => {
+ it('nearbyStationLoading=true のとき路線リストのスケルトンが表示される', () => {
setupDefaults({ nearbyStationLoading: true });
- const { getByTestId, queryByTestId } = render();
+ const { getByTestId } = render();
expect(getByTestId('skeleton-placeholder')).toBeTruthy();
- expect(queryByTestId('presets')).toBeNull();
+ // プリセットカードは上部固定表示になり最寄り駅のローディングとは独立したため、
+ // ローディング中でも常に表示される
+ expect(getByTestId('presets')).toBeTruthy();
});
- it('nearbyStationLoading=false のときプリセットが表示される', () => {
+ it('nearbyStationLoading=false のとき路線リストのスケルトンは表示されない', () => {
setupDefaults({ nearbyStationLoading: false });
const { getByTestId, queryByTestId } = render();
diff --git a/src/screens/SelectLineScreen.tsx b/src/screens/SelectLineScreen.tsx
index d6cdebe11..ca79cfa37 100644
--- a/src/screens/SelectLineScreen.tsx
+++ b/src/screens/SelectLineScreen.tsx
@@ -45,10 +45,7 @@ import { SelectLineScreenPresets } from './SelectLineScreenPresets';
const styles = StyleSheet.create({
root: { paddingHorizontal: 24, flex: 1 },
- listContainerStyle: {
- paddingBottom: 24,
- paddingHorizontal: 24,
- },
+ listScroll: { flex: 1 },
heading: {
fontSize: 24,
fontWeight: 'bold',
@@ -69,6 +66,10 @@ const styles = StyleSheet.create({
// https://github.com/facebook/react-native/issues/53987
const REFRESH_TINT_DELAY_MS = 500;
+// 路線リストのスクロール領域下端の基本パディング。実際の下端余白はこれに
+// フッタータブバーの高さ(useFooterHeight)を加算して算出する
+const LIST_CONTENT_PADDING_BOTTOM = 24;
+
const NearbyStationLoader = () => (
@@ -152,12 +153,10 @@ const SelectLineScreen = () => {
// --- 派生値 ---
const footerHeight = useFooterHeight();
- const listPaddingBottom = useMemo(() => {
- const flattened = StyleSheet.flatten(styles.listContainerStyle) as {
- paddingBottom?: number;
- };
- return (flattened?.paddingBottom ?? 24) + footerHeight;
- }, [footerHeight]);
+ const listPaddingBottom = useMemo(
+ () => LIST_CONTENT_PADDING_BOTTOM + footerHeight,
+ [footerHeight]
+ );
const orientation = useDeviceOrientation();
const isPortraitOrientation = useMemo(
@@ -303,36 +302,47 @@ const SelectLineScreen = () => {
// --- JSX ---
return (
<>
-
+ {/*
+ 上下のセーフエリアは絶対配置オーバーレイの NowHeader / FooterTabBar が
+ それぞれ処理するため上下インセットは無効化する。一方、横向き/タブレットの
+ ノッチでコンテンツが欠けないよう、左右インセットだけは SafeAreaView で確保する。
+ */}
+
+ {/*
+ プリセットカードは上部に固定表示し、Pull to Refresh の対象外にする。
+ paddingTop で固定ヘッダー(NowHeader)の直下に配置する。
+ */}
+
+
+
+
+
+
+ {/* プリセットカードより下の路線リストのみ Pull to Refresh の対象にする */}
}
- contentContainerStyle={[
- styles.listContainerStyle,
- nowHeaderHeight ? { paddingTop: nowHeaderHeight } : null,
- { paddingBottom: listPaddingBottom },
- ]}
+ contentContainerStyle={{ paddingBottom: listPaddingBottom }}
>
{nearbyStationLoading && !refreshing ? (
) : (
<>
-
-
-
{stationLines.length > 0 && (