diff --git a/Arithmetic.gif b/Arithmetic.gif index f8a368b..d51f8ab 100644 Binary files a/Arithmetic.gif and b/Arithmetic.gif differ diff --git a/Arithmetic.xcodeproj/project.pbxproj b/Arithmetic.xcodeproj/project.pbxproj index e5e89e7..8867f47 100644 --- a/Arithmetic.xcodeproj/project.pbxproj +++ b/Arithmetic.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 8A0000000000000000000003 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8A0000000000000000000004 /* GoogleService-Info.plist */; }; 8A0C5AE12EC8D88E0020200A /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0C5AE02EC8D88E0020200A /* SettingsView.swift */; }; 8A0C5AED2EC9C92D0020200A /* MathBankView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0C5AEC2EC9C92D0020200A /* MathBankView.swift */; }; 8A0C5AEF2EC9C9510020200A /* MathBankPDFGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0C5AEE2EC9C9510020200A /* MathBankPDFGenerator.swift */; }; @@ -52,7 +53,6 @@ 8AF3ABB42E05AE3600F67CDE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8AF3AB972E05AE3600F67CDE /* Localizable.strings */; }; 8AF3EA7D2E75A6B700E0F439 /* TTSHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AF3EA7C2E75A6B700E0F439 /* TTSHelper.swift */; }; 8AFF11782EEE7AC300CA7987 /* QrCodeToolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AFF11772EEE7AC300CA7987 /* QrCodeToolView.swift */; }; - 8A0000000000000000000003 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8A0000000000000000000004 /* GoogleService-Info.plist */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -135,6 +135,7 @@ 8AF3AB9E2E05AE3600F67CDE /* ViewModels */, 8AF3ABA32E05AE3600F67CDE /* Views */, 1A2B3C4D5E6F7897 /* Products */, + 8AEB5CF92F0B8C63004CB384 /* Recovered References */, ); sourceTree = ""; }; @@ -159,6 +160,14 @@ path = CoreData; sourceTree = ""; }; + 8AEB5CF92F0B8C63004CB384 /* Recovered References */ = { + isa = PBXGroup; + children = ( + 8A0000000000000000000004 /* GoogleService-Info.plist */, + ); + name = "Recovered References"; + sourceTree = ""; + }; 8AF3AB8F2E05AE3600F67CDE /* Extensions */ = { isa = PBXGroup; children = ( @@ -245,9 +254,8 @@ 1A2B3C4D5E6F789A /* Sources */, 1A2B3C4D5E6F7894 /* Frameworks */, 1A2B3C4D5E6F789B /* Resources */, - - 8A0000000000000000000001 /* Crashlytics */, - 8A0000000000000000000002 /* Check Localizations */, + 8A0000000000000000000001 /* Crashlytics */, + 8A0000000000000000000002 /* Check Localizations */, ); buildRules = ( ); @@ -328,9 +336,6 @@ shellPath = /bin/sh; shellScript = "sh \"${SRCROOT}/../firebase-ios-sdk/Crashlytics/run\""; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ 8A0000000000000000000002 /* Check Localizations */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -531,6 +536,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6NQ9M8HGC4; @@ -553,6 +559,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6NQ9M8HGC4; diff --git a/ChangeLogs.md b/ChangeLogs.md index befa4d9..decbc74 100644 --- a/ChangeLogs.md +++ b/ChangeLogs.md @@ -1,5 +1,14 @@ # Change Log +### 🌟 2026-01-05 (About App & UI Improvements) +- **新增“关于应用”页面 (Added "About App" Page)**: + - 在设置页面新增“关于 Arithmetic”按钮,点击后可查看应用版本、构建号、Git提交哈希和提交信息。 + - 界面优化,采用更清晰的表单布局,并添加了致谢列表。 + - **Git信息嵌入**:通过Xcode构建脚本将最新的Git提交信息(哈希和消息)嵌入到应用中,解决了Git信息显示“N/A”的问题。 + - **国际化支持**:所有“关于应用”页面的文本都已进行完整的中英文本地化。 +- **主界面按钮位置调整 (Main Screen Button Reordering)**: + - 将主页面的“设置”按钮移动到“其他选项”按钮下方,优化了界面布局。 + ## 🔄 最近更新 (Recent Updates) ### 🌟 2026-01-03 (Crash Test and Localization Improvements) diff --git a/Info.plist b/Info.plist index 1e6b7a6..243235a 100644 --- a/Info.plist +++ b/Info.plist @@ -27,9 +27,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.0.1 CFBundleVersion - 1 + 2 LSRequiresIPhoneOS NSApplicationCrashOnExceptions diff --git a/README.md b/README.md index 289dfef..087190c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # 🧮 小学生算术学习应用 ## Elementary Arithmetic Learning App -*Updated: January 4, 2026* +*Version: 1.0.1* | *Updated: January 5, 2026* [![Demo](https://github.com/tobecrazy/Arithmetic/blob/main/Arithmetic.gif)](https://github.com/tobecrazy/Arithmetic) @@ -52,7 +52,8 @@ | PDF题库生成 | 系统信息监控 | 设置选项 | | 欢迎引导流程 | 数学公式大全 | QR码扫描工具 | | 网络状态检测 | 单位换算 | 电池监控 | -| Firebase崩溃监控 (Firebase Crash Monitoring) | 运行时长计算 | | +| Firebase崩溃监控 (Firebase Crash Monitoring) | 运行时长计算 | 关于页面 (About Page) | +| Git信息嵌入 (Git Info Embedding) | | | @@ -305,6 +306,11 @@ - **错误分析 (Error Analysis)** - 帮助开发者快速识别和修复问题,提高应用稳定性 (Helps developers quickly identify and fix issues, improving app stability) - **测试功能 (Testing Feature)** - 在设置页面提供崩溃测试功能,便于验证错误监控系统 (Provides crash testing functionality in settings for verifying error monitoring system) +### ℹ️ 关于应用页面 (About App Page) +- **版本信息 (Version Information)** - 在设置中新增“关于应用”页面,显示应用版本、构建号。 (Adds an "About App" page in Settings to display app version and build number.) +- **自动Git信息 (Automatic Git Info)** - 通过构建脚本自动嵌入最新的Git提交哈希和信息。 (Automatically embeds the latest Git commit hash and message via a build script.) +- **国际化 (Internationalized)** - 页面内容完全支持中英文。 (The page content is fully localized in Chinese and English.) + ### 🌐 多语言支持 (Language Settings) - **双语界面 (Bilingual Interface)** - 支持中文和英文界面 (Supports both Chinese and English interfaces) - **实时切换 (Real-time Switching)** - 可随时切换语言 (Language can be switched at any time) @@ -744,7 +750,7 @@ Arithmetic/ │ ├── QrCodeToolView.swift # QR码工具视图 │ └── CachedAsyncImageView.swift # 图片缓存视图 ├── 📁 scripts/ # 构建和工具脚本 -│ ├── check_localizations.sh # 本地化检查脚本 +│ ├── check_localizations.sh # 本地化检查并嵌入Git信息 (Checks localization and embeds Git info) │ ├── upload_dsyms.sh # dSYM上传脚本 │ └── upload-symbols # dSYM上传工具 └── 📁 Tests/ # 测试文件 diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 237c450..7ba11b7 100644 --- a/Resources/en.lproj/Localizable.strings +++ b/Resources/en.lproj/Localizable.strings @@ -482,3 +482,14 @@ "crash.test.title" = "Crash Test"; "crash.test.button" = "Generate App Crash"; +"about.arithmetic.title" = "About Arithmetic"; + +/* About App View */ +"about.app.section.git_details" = "Git Commit Details"; +"about.app.section.about_app" = "About the App"; +"about.app.section.acknowledgements" = "Acknowledgements"; +"about.app.label.hash" = "Hash"; +"about.app.label.message" = "Message"; +"about.app.description" = "This app is designed to help elementary school students practice their arithmetic skills in a fun and engaging way."; + + diff --git a/Resources/zh-Hans.lproj/Localizable.strings b/Resources/zh-Hans.lproj/Localizable.strings index 4dbbe7b..8c112ec 100644 --- a/Resources/zh-Hans.lproj/Localizable.strings +++ b/Resources/zh-Hans.lproj/Localizable.strings @@ -475,3 +475,14 @@ "crash.test.title" = "崩溃测试"; "crash.test.button" = "生成应用崩溃"; +"about.arithmetic.title" = "关于 Arithmetic"; + +/* About App View */ +"about.app.section.git_details" = "Git 提交详情"; +"about.app.section.about_app" = "关于应用"; +"about.app.section.acknowledgements" = "鸣谢"; +"about.app.label.hash" = "哈希值"; +"about.app.label.message" = "提交信息"; +"about.app.description" = "本应用旨在帮助小学生以有趣和引人入胜的方式练习算术技能。"; + + diff --git a/Views/ContentView.swift b/Views/ContentView.swift index b393458..2d542dd 100644 --- a/Views/ContentView.swift +++ b/Views/ContentView.swift @@ -366,24 +366,24 @@ struct ContentView: View { .animation(.easeInOut(duration: 0.6).delay(0.8), value: isAnimating) enhancedActionButton( - title: "button.settings".localized, - subtitle: "settings.title".localized, - iconName: "gear", - gradient: ContentView.purpleGradient + title: "button.other_options".localized, + subtitle: "explore.more.features".localized, + iconName: "ellipsis.circle.fill", + gradient: .greenGradient ) { - showSettingsView = true + showOtherOptionsView = true } .opacity(isAnimating ? 1 : 0) .offset(x: isAnimating ? 0 : 50) .animation(.easeInOut(duration: 0.6).delay(0.9), value: isAnimating) enhancedActionButton( - title: "button.other_options".localized, - subtitle: "explore.more.features".localized, - iconName: "ellipsis.circle.fill", - gradient: .greenGradient + title: "button.settings".localized, + subtitle: "settings.title".localized, + iconName: "gear", + gradient: ContentView.purpleGradient ) { - showOtherOptionsView = true + showSettingsView = true } .opacity(isAnimating ? 1 : 0) .offset(x: isAnimating ? 0 : 50) @@ -503,24 +503,24 @@ struct ContentView: View { .animation(.easeInOut(duration: 0.6).delay(0.8), value: isAnimating) enhancedActionButton( - title: "button.settings".localized, - subtitle: "settings.title".localized, - iconName: "gear", - gradient: ContentView.purpleGradient + title: "button.other_options".localized, + subtitle: "explore.more.features".localized, + iconName: "ellipsis.circle.fill", + gradient: .greenGradient ) { - showSettingsView = true + showOtherOptionsView = true } .opacity(isAnimating ? 1 : 0) .offset(y: isAnimating ? 0 : 30) .animation(.easeInOut(duration: 0.6).delay(0.9), value: isAnimating) enhancedActionButton( - title: "button.other_options".localized, - subtitle: "explore.more.features".localized, - iconName: "ellipsis.circle.fill", - gradient: .greenGradient + title: "button.settings".localized, + subtitle: "settings.title".localized, + iconName: "gear", + gradient: ContentView.purpleGradient ) { - showOtherOptionsView = true + showSettingsView = true } .opacity(isAnimating ? 1 : 0) .offset(y: isAnimating ? 0 : 30) diff --git a/Views/SettingsView.swift b/Views/SettingsView.swift index fd02e00..f61877d 100644 --- a/Views/SettingsView.swift +++ b/Views/SettingsView.swift @@ -10,6 +10,7 @@ struct SettingsView: View { @State private var navigateToAboutMe = false @State private var navigateToSystemInfo = false @State private var navigateToQrCodeTool = false + @State private var navigateToAboutApp = false private var aboutMeDestination: some View { AboutMeView() @@ -26,6 +27,11 @@ struct SettingsView: View { .environmentObject(localizationManager) } + private var aboutAppDestination: some View { + AboutAppView() + .environmentObject(localizationManager) + } + var body: some View { NavigationView { Form { @@ -78,6 +84,15 @@ struct SettingsView: View { } } .buttonStyle(PlainButtonStyle()) + + Button(action: { navigateToAboutApp = true }) { + HStack { + Image(systemName: "info.circle.fill") + .foregroundColor(.green) + Text("about.arithmetic.title".localized) + } + } + .buttonStyle(PlainButtonStyle()) } } .navigationTitle("settings.title".localized) @@ -99,7 +114,109 @@ struct SettingsView: View { qrCodeToolDestination } } + .sheet(isPresented: $navigateToAboutApp) { + NavigationView { + aboutAppDestination + } + } + } + } +} + +struct AboutAppView: View { + @Environment(\.presentationMode) var presentationMode + + var appVersion: String { + Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "N/A" + } + + var buildNumber: String { + Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "N/A" + } + + var gitCommitHash: String { + gitInfo.hash + } + + var gitCommitMessage: String { + gitInfo.message + } + + private var gitInfo: (hash: String, message: String) { + if let appVersionURL = Bundle.main.url(forResource: "appversion", withExtension: "txt"), + let content = try? String(contentsOf: appVersionURL, encoding: .utf8) { + let components = content.components(separatedBy: "_||_") + if components.count == 2 { + let hash = components[0].trimmingCharacters(in: .whitespacesAndNewlines) + let message = components[1].trimmingCharacters(in: .whitespacesAndNewlines) + return (hash, message) + } + } + return ("N/A", "N/A") + } + + var body: some View { + NavigationView { + Form { + Section { + HStack { + Spacer() + VStack(spacing: 10) { + Image("logo") + .resizable() + .frame(width: 80, height: 80) + .cornerRadius(16) + .shadow(radius: 3) + Text("Arithmetic") + .font(.title) + .fontWeight(.bold) + Text("Version \(appVersion) (\(buildNumber))") + .font(.caption) + .foregroundColor(.secondary) + } + Spacer() + } + .padding(.vertical) + } + + Section(header: Text("about.app.section.git_details".localized)) { + InfoRow(label: "about.app.label.hash".localized, value: gitCommitHash) + InfoRow(label: "about.app.label.message".localized, value: gitCommitMessage) + } + + Section(header: Text("about.app.section.about_app".localized)) { + Text("about.app.description".localized) + .font(.body) + .padding(.vertical, 5) + } + + Section(header: Text("about.app.section.acknowledgements".localized)) { + Link("Firebase", destination: URL(string: "https://firebase.google.com")!) + Link("SwiftUI", destination: URL(string: "https://developer.apple.com/xcode/swiftui/")!) + } + } + .navigationTitle("about.arithmetic.title".localized) + .navigationBarItems(trailing: Button("Done") { + presentationMode.wrappedValue.dismiss() + }) + } + } +} + +struct InfoRow: View { + let label: String + let value: String + + var body: some View { + VStack(alignment: .leading, spacing: 4) { + Text(label) + .font(.caption) + .foregroundColor(.secondary) + Text(value) + .font(.body) + .lineLimit(3) } + .padding(.vertical, 4) } } diff --git a/scripts/check_localizations.sh b/scripts/check_localizations.sh index ce07070..7b69aab 100644 --- a/scripts/check_localizations.sh +++ b/scripts/check_localizations.sh @@ -63,5 +63,24 @@ else echo "Total en keys: ${#EN_KEYS[@]}, zh-Hans keys: ${#ZH_KEYS[@]}" >&2 fi +# --- Embed Git Info --- +echo "---" +echo "Embedding Git info into app bundle..." + +# Set the path for the output file +APPVERSION_FILE_PATH="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/appversion.txt" + +# Get the latest git commit hash (short version) +COMMIT_HASH=$(git rev-parse --short HEAD) + +# Get the latest git commit message +COMMIT_MESSAGE=$(git log -1 --pretty=%B) + +# Write the commit hash and message to the file, separated by a delimiter +echo "${COMMIT_HASH}_||_${COMMIT_MESSAGE}" > "${APPVERSION_FILE_PATH}" + +echo "✅ Git info set in appversion.txt" +echo "---" + rm -f "$en_tmp" "$zh_tmp" "$en_tmp_keys" "$zh_tmp_keys" exit $status