Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6746cb9
feat: 新增 xuexiaotong 模块与 reminder 模块
InChange-Jiang Aug 26, 2026
90a0389
feat: 优化 xuexiaotong 登录界面与构建配置
InChange-Jiang Aug 26, 2026
47e4146
fix: 根据 PR 审批意见修复 10 个问题
InChange-Jiang Aug 27, 2026
3f1bd27
feat(recharge): unify secure card payment flows
Aug 27, 2026
130439a
feat(ui): unify themes and harden app flows
Aug 31, 2026
c10f698
feat: RadiantUI 分支同步本地开发改动(学习通日历与权限图标、设置页 8 项 iconpark 图标、日程/课表界面等)
InChange-Jiang Sep 2, 2026
edec99f
feat(payments): add native recharge and electricity controllers
Sep 2, 2026
317f2e6
feat: 学习通 tab 新增首次引导气泡(曜光分支)
InChange-Jiang Sep 4, 2026
ff19119
style: GlassCard 玻璃卡阴影减重(曜光分支)
InChange-Jiang Sep 4, 2026
aabeaed
chore(merge): integrate PR #11 into #13
Sep 4, 2026
800a05a
feat(merge): integrate PR #14 with RadiantUI theme
Sep 4, 2026
6e70235
chore(merge): checkpoint PR 13 and 14 integration
Sep 4, 2026
dbee7f1
fix(cache): isolate home layouts by theme family
Sep 4, 2026
d23e142
fix(theme): migrate legacy UI style preference
Sep 4, 2026
a6530f0
fix(xuexiaotong): isolate and clean up reminders
Sep 4, 2026
05507e7
fix(navigation): restore radiant tools and home layouts
Sep 4, 2026
f679b9b
fix(weather): unify settings sheet container
Sep 4, 2026
88cf564
fix(payment): preserve secure flows in radiant pages
Sep 4, 2026
5f4ba0d
feat(radiant): adapt business pages
Sep 4, 2026
389b183
fix(radiant): add missing page imports
Sep 4, 2026
f04a842
fix(weather): restore radiant header and themed settings
Sep 4, 2026
270238f
fix(settings): restore Radiant card shadows and icons
Sep 4, 2026
1c8716d
fix(schedule): use semantic settings colors
Sep 4, 2026
7611df1
fix(home): restore radiant navigation and motion
Sep 4, 2026
d62d304
fix(login): restore home redirect after sign-in
Sep 4, 2026
8e7ab09
fix(free-classroom): restore radiant card surfaces
Sep 4, 2026
151fce8
fix(settings): render Radiant shadows in glass layer
Sep 4, 2026
45e96f4
fix(home): restore PR14 layers and boundaries
Sep 4, 2026
7cb7541
fix(navigation): register widgets action route
Sep 4, 2026
9a012f8
fix(ci): isolate release build with larger heap
Sep 4, 2026
760e000
fix(ci): isolate kotlin compilation memory
Sep 4, 2026
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
39 changes: 27 additions & 12 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,31 @@ on:

jobs:
build:
name: Build Debug
name: Test, lint and build
runs-on: ubuntu-latest

steps:
- name: Checkout selected branch
if: github.event_name == 'workflow_dispatch'
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ inputs.branch }}
submodules: recursive

- name: Checkout
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4.9.1
with:
distribution: temurin
java-version: "17"

- name: Set up Android SDK
uses: android-actions/setup-android@v3
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3

- name: Install SDK components
run: |
Expand All @@ -56,31 +56,46 @@ jobs:
echo "$ANDROID_HOME/ndk/28.2.13676358/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c
with:
toolchain: 1.94.0
targets: aarch64-linux-android
components: clippy

- name: Install cargo-ndk
run: cargo install cargo-ndk
run: cargo install cargo-ndk --version 4.1.2 --locked

- name: Set Gradle permission
run: chmod +x ./gradlew

- name: Cache Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4

- name: Cache Cargo
uses: Swatinem/rust-cache@v2
uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2
with:
workspaces: |
sdk
GuiXu-Rust

- name: Build debug APK
run: ./gradlew :app:assembleDebug --stacktrace
- name: Test Rust SDK
run: |
cargo test --manifest-path sdk/Cargo.toml
# The pinned SDK still contains a known unsupported look-ahead regex.
# Keep every other Clippy check active until that SDK fix is merged.
cargo clippy --manifest-path sdk/Cargo.toml --all-targets -- --allow clippy::invalid_regex

- name: Test and build debug Android
run: ./gradlew --no-daemon -Dorg.gradle.jvmargs="-Xmx4096m -Dfile.encoding=UTF-8" -Pkotlin.compiler.execution.strategy=in-process :app:testDebugUnitTest :app:assembleDebug --stacktrace

- name: Lint release Android
run: ./gradlew --no-daemon -Dorg.gradle.jvmargs="-Xmx4096m -Dfile.encoding=UTF-8" -Pkotlin.compiler.execution.strategy=in-process :app:lintRelease --stacktrace

- name: Build release Android
run: ./gradlew --no-daemon -Dorg.gradle.jvmargs="-Xmx4096m -Dfile.encoding=UTF-8" -Pkotlin.compiler.execution.strategy=in-process :app:assembleRelease --stacktrace

- name: Upload debug APK
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: AHUTong-debug-apk
path: app/build/outputs/apk/debug/*.apk
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
/local.properties
.DS_Store
/build
app/build/
*.apk
*.aab
*.keystore
/captures
.externalNativeBuild
.cxx
Expand Down
26 changes: 10 additions & 16 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
id("org.jetbrains.kotlin.plugin.serialization")
id("com.google.devtools.ksp")
id("com.google.dagger.hilt.android")
}
Expand All @@ -16,26 +17,18 @@ android {
}
}

packaging {
jniLibs {
excludes += "**/libahutong_rs.so"
}
}

lint {
//即使报错也不会停止打包
abortOnError = false
//打包release版本的时候是否进行检测
checkReleaseBuilds = false
lint {
abortOnError = true
checkReleaseBuilds = true
}
//关闭PNG合法性检查
// aaptOptions.useNewCruncher = false
defaultConfig {
applicationId = "com.ahu.ahutong"
minSdk = 26
targetSdk = 36
versionCode = 322
versionName = "3.2.2"
versionCode = 330
versionName = "3.3.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters += listOf("arm64-v8a")
Expand All @@ -44,8 +37,8 @@ android {

buildTypes {
release {
isShrinkResources = true // 移除无用的resource文件
isMinifyEnabled = true //是否对代码进行混淆,true表示混淆
isShrinkResources = true
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
Expand Down Expand Up @@ -135,7 +128,8 @@ dependencies {
implementation(libs.androidx.ui)
implementation(libs.androidx.foundation)
implementation(libs.androidx.material.icons.extended)
implementation(libs.material3)
implementation(libs.material3)
implementation(libs.miuix.android)
implementation(libs.androidx.runtime.livedata)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
Expand Down
51 changes: 31 additions & 20 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keep class com.ahu.ahutong.data.model.** { *; }
# These models are deserialized both from the native bridge and from local Gson caches. Field-only
# rules do not prevent vertical class merging, which is unsafe for reflection-based construction.
-keep class com.ahu.ahutong.data.model.** { *; }
-keep class com.ahu.ahutong.ui.screen.main.ElectricityDepositKt { *; }
-keep class com.ahu.ahutong.ui.screen.main.home.ElectricityPaymentKt { *; }
-keep class com.ahu.ahutong.data.dao.AHUCache { *; }
-keep class com.ahu.ahutong.ui.component.** { *; }
-keep class com.ahu.ahutong.ui.state.** { *; }

-keepclassmembers class kotlinx.coroutines.** {
volatile <fields>;
Expand All @@ -74,7 +74,26 @@
private *;
}

-keep class com.ahu.ahutong.data.crawler.model.** { *; }
# Crawler DTOs are Retrofit/Gson wire contracts. Keeping only their fields still allows R8 to
# merge the owning classes, which can turn a valid login response into a ClassCastException in
# minified builds. Keep the complete contracts so Review/Release authentication behaves like Debug.
-keep class com.ahu.ahutong.data.crawler.model.** { *; }

# Payment view models contain a small number of file-local wire DTOs. Keep only the DTO naming
# families rather than the ViewModels themselves, so R8 can still optimize the screen logic while
# Gson retains concrete constructors and field contracts in Review/Release builds.
-keep class com.ahu.ahutong.ui.state.*Response { *; }
-keep class com.ahu.ahutong.ui.state.*Map { *; }
-keep class com.ahu.ahutong.ui.state.*Data { *; }
-keep class com.ahu.ahutong.ui.state.*DataItem { *; }
-keep class com.ahu.ahutong.ui.state.*Details { *; }
-keep class com.ahu.ahutong.ui.state.*Payload { *; }
-keep class com.ahu.ahutong.ui.state.*FeeItem { *; }

# Native campus-card WebView bridge messages are also Gson contracts.
-keep class com.ahu.ahutong.ui.screen.main.CmbRechargeBridgePayload { *; }
-keep class com.ahu.ahutong.ui.screen.main.CmbRechargeBridgePaymentMethod { *; }
-keep class com.ahu.ahutong.ui.screen.main.CmbPaymentUiPayload { *; }


-renamesourcefileattribute AHUTong
Expand Down Expand Up @@ -160,22 +179,14 @@
-keep class com.ahu.ahutong.personalization.bootstrap.BootstrapTrainingCredentialResponse { *; }
-keep class com.ahu.ahutong.personalization.bootstrap.BootstrapTrainingDeletionRequest { *; }

# Data source interface + implementations (prevent R8 from stripping abstract methods)
-keep interface com.ahu.ahutong.data.base.BaseDataSource { *; }
-keep class com.ahu.ahutong.data.crawler.CrawlerDataSource { *; }
-keep class com.ahu.ahutong.data.crawler.SdkDataSource { *; }
-keep class com.ahu.ahutong.data.mock.MockDataSource { *; }

# Weather API + models (prevent R8 from stripping Gson/Retrofit classes)
-keep class com.ahu.ahutong.data.weather.** { *; }
-keep interface com.ahu.ahutong.data.weather.WeatherApi { *; }

# Repository / GitHub models
-keep class com.ahu.ahutong.data.repository.** { *; }

# AHURepository
-keep class com.ahu.ahutong.data.AHURepository { *; }
# Weather responses are constructed and populated reflectively by Gson. Field-only rules with
# allowoptimization let R8 remove fields that are only read through reflection, which leaves the
# release weather widget with an incomplete response model.
-keep class com.ahu.ahutong.data.weather.** { *; }
-keep interface com.ahu.ahutong.data.weather.WeatherApi { *; }

# Repository / GitHub models
-keepclassmembers,allowoptimization class com.ahu.ahutong.data.repository.** { <fields>; }

# Evaluation
-keep class com.ahu.ahutong.data.EvaluationRepository { *; }
-keep interface com.ahu.ahutong.data.crawler.api.jwxt.EvaluationApi { *; }
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
Expand All @@ -69,6 +70,10 @@ import com.ahu.ahutong.personalization.prefetch.PrefetchCoordinator
import com.ahu.ahutong.personalization.prefetch.PrefetchDiagnostic
import com.ahu.ahutong.personalization.prefetch.PrefetchState
import com.ahu.ahutong.personalization.ui.SuggestionPolicy
import com.ahu.ahutong.ui.components.LocalLiquidGlassContentBackdrop
import com.ahu.ahutong.ui.components.appLiquidGlassSceneBackground
import com.ahu.ahutong.ui.components.appLiquidGlassSurface
import com.ahu.ahutong.ui.theme.LiquidGlassSurfaceLevel
import java.time.LocalDate
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -130,6 +135,7 @@ class DebugDiagnosticsContribution @Inject constructor(
val screenWidthPx = with(density) { configuration.screenWidthDp.dp.toPx() }
val screenHeightPx = with(density) { configuration.screenHeightDp.dp.toPx() }
val ballPx = with(density) { 52.dp.toPx() }
val contentBackdrop = LocalLiquidGlassContentBackdrop.current
val horizontalInsetPx = with(density) { 12.dp.toPx() }
val minX = -(screenWidthPx - ballPx - horizontalInsetPx * 2).coerceAtLeast(0f)
val maxY = (screenHeightPx / 2f - ballPx).coerceAtLeast(0f)
Expand All @@ -143,7 +149,12 @@ class DebugDiagnosticsContribution @Inject constructor(
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.padding(end = 12.dp)
.size(52.dp)
.clip(CircleShape)
.appLiquidGlassSurface(
shape = CircleShape,
fallbackColor = MaterialTheme.colorScheme.tertiaryContainer,
level = LiquidGlassSurfaceLevel.Floating,
backdrop = contentBackdrop
)
.pointerInput(minX, maxY) {
detectDragGestures(
onDragEnd = {
Expand All @@ -161,7 +172,7 @@ class DebugDiagnosticsContribution @Inject constructor(
onLongClick = preferences::togglePaused
),
shape = CircleShape,
color = MaterialTheme.colorScheme.tertiaryContainer,
color = Color.Transparent,
shadowElevation = 8.dp
) {
Box(contentAlignment = Alignment.Center) {
Expand Down Expand Up @@ -198,7 +209,9 @@ private fun DiagnosticsScreen(
onDispose { activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) }
}
LazyColumn(
modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background),
modifier = Modifier
.fillMaxSize()
.appLiquidGlassSceneBackground(MaterialTheme.colorScheme.background),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Expand Down Expand Up @@ -844,11 +857,18 @@ private fun DiagnosticsSection(
title: String? = null,
content: @Composable ColumnScope.() -> Unit
) {
val shape = MaterialTheme.shapes.large
Surface(
modifier = Modifier.fillMaxWidth(),
shape = MaterialTheme.shapes.large,
color = MaterialTheme.colorScheme.surfaceContainer,
tonalElevation = 1.dp
modifier = Modifier
.fillMaxWidth()
.appLiquidGlassSurface(
shape = shape,
fallbackColor = MaterialTheme.colorScheme.surfaceContainer,
level = LiquidGlassSurfaceLevel.Panel
),
shape = shape,
color = Color.Transparent,
tonalElevation = 0.dp
) {
Column(
modifier = Modifier.fillMaxWidth().padding(16.dp),
Expand Down
Loading
Loading