Skip to content

Commit edc89e7

Browse files
author
Lalit Sharma
committed
feat: add About screen in Settings to display app version/build metadata, fix version reporting, and update navigation
1 parent 1c865b7 commit edc89e7

6 files changed

Lines changed: 162 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.50] — 2026-02-27
9+
10+
### Added
11+
- Added a new `About` screen in Settings that displays app version/build metadata in the UI (`App Version`, `Build`, `Configured Version`, and `Runtime Version`).
12+
13+
### Fixed
14+
- Fixed Android app version reporting mismatch by sourcing native `versionName` from `apps/mobile/package.json` in app Gradle config instead of using a hardcoded value.
15+
16+
### Changed
17+
- Added Settings navigation/linking support for the new `About` route (`settings/about`).
18+
- Bumped `apps/mobile` version to `1.1.50`.
19+
820
## [1.1.49] — 2026-02-27
921

1022
### Fixed

apps/mobile/android/app/build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
apply plugin: "com.android.application"
22
apply plugin: "org.jetbrains.kotlin.android"
33
apply plugin: "com.facebook.react"
4+
import groovy.json.JsonSlurper
45

56
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
7+
def mobilePackageJson = new JsonSlurper().parse(file("../../package.json"))
8+
def mobileVersionName = (mobilePackageJson.version ?: "1.0.0").toString()
69

710
/**
811
* This is the configuration block to customize your React Native Android app.
@@ -120,7 +123,7 @@ android {
120123
minSdkVersion rootProject.ext.minSdkVersion
121124
targetSdkVersion rootProject.ext.targetSdkVersion
122125
versionCode 3
123-
versionName "1.0.0"
126+
versionName mobileVersionName
124127

125128
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
126129
manifestPlaceholders += [GOOGLE_MAPS_ANDROID_API_KEY: googleMapsAndroidApiKey]

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eclipse-timer/mobile",
3-
"version": "1.1.49",
3+
"version": "1.1.50",
44
"private": true,
55
"main": "index.js",
66
"scripts": {

apps/mobile/src/navigation/RootNavigator.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { useLandingEclipses } from "../hooks/useLandingEclipses";
4343
import { useLandingScroll } from "../hooks/useLandingScroll";
4444
import { useNotificationScheduler } from "../hooks/useNotificationScheduler";
4545
import { useTimerState } from "../hooks/useTimerState";
46+
import AboutScreen from "../screens/AboutScreen";
4647
import EclipsePreviewScreen, { type PreviewPayload } from "../screens/EclipsePreviewScreen";
4748
import HelpScreen from "../screens/HelpScreen";
4849
import LandingScreen from "../screens/LandingScreen";
@@ -79,6 +80,7 @@ type RootStackParamList = {
7980
Preview: { payload: PreviewPayload };
8081
PhotographyGuide: { payload: PhotographyGuidePayload };
8182
Settings: undefined;
83+
About: undefined;
8284
Help: undefined;
8385
ThemeSettings: undefined;
8486
NotificationSettings: undefined;
@@ -93,6 +95,7 @@ const linking: LinkingOptions<RootStackParamList> = {
9395
Timer: "timer",
9496
PhotographyGuide: "photography-guide",
9597
Settings: "settings",
98+
About: "settings/about",
9699
Help: "settings/help",
97100
ThemeSettings: "settings/theme",
98101
NotificationSettings: "notifications",
@@ -192,6 +195,7 @@ function toMenuRouteName(route: keyof RootStackParamList): MenuRouteName | null
192195
if (route === "Timer" || route === "PhotographyGuide") return "Timer";
193196
if (
194197
route === "Settings" ||
198+
route === "About" ||
195199
route === "Help" ||
196200
route === "ThemeSettings" ||
197201
route === "NotificationSettings" ||
@@ -553,6 +557,7 @@ function SettingsRoute({ navigation, onOpenMenu }: SettingsRouteProps) {
553557
return (
554558
<SettingsScreen
555559
onOpenMenu={onOpenMenu}
560+
onOpenAbout={() => navigation.navigate("About")}
556561
onOpenHelp={() => navigation.navigate("Help")}
557562
onOpenThemeSettings={() => navigation.navigate("ThemeSettings")}
558563
onOpenNotificationSettings={() => navigation.navigate("NotificationSettings")}
@@ -565,6 +570,10 @@ function HelpRoute({ onOpenMenu }: RouteWithMenuProps) {
565570
return <HelpScreen onOpenMenu={onOpenMenu} />;
566571
}
567572

573+
function AboutRoute({ onOpenMenu }: RouteWithMenuProps) {
574+
return <AboutScreen onOpenMenu={onOpenMenu} />;
575+
}
576+
568577
function ThemeSettingsRoute({ onOpenMenu }: ThemeSettingsRouteProps) {
569578
const { state, actions } = useAppState();
570579

@@ -1010,6 +1019,7 @@ export default function RootNavigator() {
10101019
<Stack.Screen name="Settings">
10111020
{(props) => <SettingsRoute {...props} onOpenMenu={openMenu} />}
10121021
</Stack.Screen>
1022+
<Stack.Screen name="About">{() => <AboutRoute onOpenMenu={openMenu} />}</Stack.Screen>
10131023
<Stack.Screen name="Help">{() => <HelpRoute onOpenMenu={openMenu} />}</Stack.Screen>
10141024
<Stack.Screen name="ThemeSettings">
10151025
{(props) => <ThemeSettingsRoute {...props} onOpenMenu={openMenu} />}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import Constants from "expo-constants";
2+
import { useMemo } from "react";
3+
import { StyleSheet, Text, View } from "react-native";
4+
import { SafeAreaView } from "react-native-safe-area-context";
5+
6+
import BurgerButton from "../components/BurgerButton";
7+
import { useAppTheme } from "../theme/useAppTheme";
8+
9+
type AboutScreenProps = {
10+
onOpenMenu: () => void;
11+
};
12+
13+
type VersionRowProps = {
14+
label: string;
15+
value: string;
16+
};
17+
18+
function VersionRow({ label, value }: VersionRowProps) {
19+
const { colors } = useAppTheme();
20+
const styles = useMemo(() => createStyles(colors), [colors]);
21+
22+
return (
23+
<View style={styles.row}>
24+
<Text style={styles.rowLabel}>{label}</Text>
25+
<Text style={styles.rowValue}>{value}</Text>
26+
</View>
27+
);
28+
}
29+
30+
function coerceVersionValue(value: unknown): string {
31+
if (typeof value === "string" && value.trim().length > 0) return value;
32+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
33+
return "Unavailable";
34+
}
35+
36+
export default function AboutScreen({ onOpenMenu }: AboutScreenProps) {
37+
const { colors } = useAppTheme();
38+
const styles = useMemo(() => createStyles(colors), [colors]);
39+
40+
const appVersion = coerceVersionValue(Constants.nativeAppVersion);
41+
const buildVersion = coerceVersionValue(Constants.nativeBuildVersion);
42+
const configuredVersion = coerceVersionValue(Constants.expoConfig?.version);
43+
const runtimeVersion = coerceVersionValue(Constants.expoConfig?.runtimeVersion);
44+
45+
return (
46+
<SafeAreaView style={styles.safe} edges={["top", "left", "right", "bottom"]}>
47+
<View style={styles.headerRow}>
48+
<BurgerButton onPress={onOpenMenu} />
49+
<View style={styles.headerMeta}>
50+
<Text style={styles.title} accessibilityRole="header">
51+
About
52+
</Text>
53+
<Text style={styles.subtitle}>Build and version information for this app.</Text>
54+
</View>
55+
</View>
56+
57+
<View style={styles.content}>
58+
<View style={styles.card}>
59+
<VersionRow label="App Version" value={appVersion} />
60+
<VersionRow label="Build" value={buildVersion} />
61+
<VersionRow label="Configured Version" value={configuredVersion} />
62+
<VersionRow label="Runtime Version" value={runtimeVersion} />
63+
</View>
64+
</View>
65+
</SafeAreaView>
66+
);
67+
}
68+
69+
function createStyles(colors: ReturnType<typeof useAppTheme>["colors"]) {
70+
return StyleSheet.create({
71+
safe: {
72+
flex: 1,
73+
backgroundColor: colors.background,
74+
},
75+
headerRow: {
76+
paddingHorizontal: 12,
77+
paddingTop: 8,
78+
flexDirection: "row",
79+
alignItems: "center",
80+
gap: 10,
81+
},
82+
headerMeta: {
83+
flex: 1,
84+
gap: 2,
85+
},
86+
title: {
87+
color: colors.textPrimary,
88+
fontSize: 21,
89+
fontWeight: "800",
90+
},
91+
subtitle: {
92+
color: colors.textMuted,
93+
fontSize: 12,
94+
lineHeight: 17,
95+
},
96+
content: {
97+
paddingHorizontal: 12,
98+
paddingTop: 14,
99+
gap: 12,
100+
},
101+
card: {
102+
borderRadius: 12,
103+
borderWidth: 1,
104+
borderColor: colors.border,
105+
backgroundColor: colors.surface,
106+
paddingVertical: 12,
107+
paddingHorizontal: 12,
108+
gap: 10,
109+
},
110+
row: {
111+
flexDirection: "row",
112+
alignItems: "center",
113+
justifyContent: "space-between",
114+
gap: 10,
115+
},
116+
rowLabel: {
117+
flex: 1,
118+
color: colors.textMuted,
119+
fontSize: 12,
120+
fontWeight: "600",
121+
},
122+
rowValue: {
123+
color: colors.textPrimary,
124+
fontSize: 13,
125+
fontWeight: "700",
126+
},
127+
});
128+
}

apps/mobile/src/screens/SettingsScreen.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type SettingsScreenProps = {
1111
onOpenLocationSettings: () => void;
1212
onOpenThemeSettings: () => void;
1313
onOpenHelp: () => void;
14+
onOpenAbout: () => void;
1415
};
1516

1617
type SettingsActionCardProps = {
@@ -43,6 +44,7 @@ export default function SettingsScreen({
4344
onOpenLocationSettings,
4445
onOpenThemeSettings,
4546
onOpenHelp,
47+
onOpenAbout,
4648
}: SettingsScreenProps) {
4749
const { colors } = useAppTheme();
4850
const styles = useMemo(() => createStyles(colors), [colors]);
@@ -80,6 +82,11 @@ export default function SettingsScreen({
8082
subtitle="Read quick answers, troubleshooting tips, and full docs."
8183
onPress={onOpenHelp}
8284
/>
85+
<SettingsActionCard
86+
title="About"
87+
subtitle="View app version and build details."
88+
onPress={onOpenAbout}
89+
/>
8390
</View>
8491
</SafeAreaView>
8592
);

0 commit comments

Comments
 (0)