Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Arithmetic.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 14 additions & 7 deletions Arithmetic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -135,6 +135,7 @@
8AF3AB9E2E05AE3600F67CDE /* ViewModels */,
8AF3ABA32E05AE3600F67CDE /* Views */,
1A2B3C4D5E6F7897 /* Products */,
8AEB5CF92F0B8C63004CB384 /* Recovered References */,
);
sourceTree = "<group>";
};
Expand All @@ -159,6 +160,14 @@
path = CoreData;
sourceTree = "<group>";
};
8AEB5CF92F0B8C63004CB384 /* Recovered References */ = {
isa = PBXGroup;
children = (
8A0000000000000000000004 /* GoogleService-Info.plist */,
);
name = "Recovered References";
sourceTree = "<group>";
};
8AF3AB8F2E05AE3600F67CDE /* Extensions */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -245,9 +254,8 @@
1A2B3C4D5E6F789A /* Sources */,
1A2B3C4D5E6F7894 /* Frameworks */,
1A2B3C4D5E6F789B /* Resources */,

8A0000000000000000000001 /* Crashlytics */,
8A0000000000000000000002 /* Check Localizations */,
8A0000000000000000000001 /* Crashlytics */,
8A0000000000000000000002 /* Check Localizations */,
);
buildRules = (
);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions ChangeLogs.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
4 changes: 2 additions & 2 deletions Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.0.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>2</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSApplicationCrashOnExceptions</key>
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -52,7 +52,8 @@
| PDF题库生成 | 系统信息监控 | 设置选项 |
| 欢迎引导流程 | 数学公式大全 | QR码扫描工具 |
| 网络状态检测 | 单位换算 | 电池监控 |
| Firebase崩溃监控 (Firebase Crash Monitoring) | 运行时长计算 | |
| Firebase崩溃监控 (Firebase Crash Monitoring) | 运行时长计算 | 关于页面 (About Page) |
| Git信息嵌入 (Git Info Embedding) | | |

</div>

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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/ # 测试文件
Expand Down
11 changes: 11 additions & 0 deletions Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -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.";


11 changes: 11 additions & 0 deletions Resources/zh-Hans.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -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" = "本应用旨在帮助小学生以有趣和引人入胜的方式练习算术技能。";


40 changes: 20 additions & 20 deletions Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
117 changes: 117 additions & 0 deletions Views/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -26,6 +27,11 @@ struct SettingsView: View {
.environmentObject(localizationManager)
}

private var aboutAppDestination: some View {
AboutAppView()
.environmentObject(localizationManager)
}

var body: some View {
NavigationView {
Form {
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}
}

Expand Down
Loading
Loading