Gitea's own notification feed doesn't fire for plain pushes (only issue/PR activity), so this app now periodically checks each favorited repository's most recent push time itself and posts a local notification when it advances past what was last seen. - FavoritePushDetector: pure comparison logic, never notifies on a repository's first sighting (only a real advance counts), avoiding a notification storm the first time this feature ever runs. - GetLatestPushEpochMillisUseCase: extracts the same 'newest branch commit time' heuristic RepositoryListViewModel already uses for the repository list's own last-push row, as a shared, reusable use case. - SharedPreferencesLastSeenPushStore: one long per favorited repo, not Room (docs/architecture.md reserves Room for offline caching). - FavoritePushCheckWorker: 15-minute WorkManager periodic job, network-constrained, no-ops cleanly with no session or no favorites. - POST_NOTIFICATIONS requested at runtime on API 33+; a denial degrades safely, the worker still runs and updates its baseline. No deep link from the notification to the specific repository yet -- tapping it opens the app normally. End-to-end delivery (a real push landing, 15 minutes elapsing) is unit-tested and the scheduling/ permission wiring is live-confirmed (prompt appeared, was granted, no crash), but an actual notification firing hasn't been observed within this same live-testing session. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
87 lines
2.5 KiB
Plaintext
87 lines
2.5 KiB
Plaintext
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
|
|
plugins {
|
|
alias(libs.plugins.android.application)
|
|
alias(libs.plugins.kotlin.android)
|
|
alias(libs.plugins.kotlin.compose)
|
|
}
|
|
|
|
android {
|
|
namespace = "com.ubisam.ubgitea"
|
|
compileSdk = 36
|
|
|
|
defaultConfig {
|
|
applicationId = "com.ubisam.ubgitea"
|
|
minSdk = 28
|
|
targetSdk = 36
|
|
versionCode = 1
|
|
versionName = "0.1.0"
|
|
|
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
isMinifyEnabled = false
|
|
proguardFiles(
|
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
"proguard-rules.pro",
|
|
)
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
targetCompatibility = JavaVersion.VERSION_17
|
|
}
|
|
|
|
buildFeatures {
|
|
compose = true
|
|
buildConfig = true
|
|
}
|
|
|
|
packaging {
|
|
resources.excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
}
|
|
|
|
// Debug-build-only diagnostic logging (e.g. HttpTransport.requireSuccess, RepositoryListViewModel
|
|
// .toggleFavorite) calls android.util.Log directly. Plain JVM unit tests run against an unmocked
|
|
// android.jar where every framework call throws by default; this makes them return harmless
|
|
// defaults (0/null/false) instead, so a debug-only Log.w doesn't fail tests that legitimately
|
|
// exercise the code path around it.
|
|
testOptions {
|
|
unitTests {
|
|
isReturnDefaultValues = true
|
|
}
|
|
}
|
|
}
|
|
|
|
kotlin {
|
|
compilerOptions {
|
|
jvmTarget.set(JvmTarget.JVM_17)
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation(libs.androidx.core.ktx)
|
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
|
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
|
implementation(libs.androidx.lifecycle.viewmodel.ktx)
|
|
implementation(libs.androidx.activity.compose)
|
|
implementation(libs.androidx.browser)
|
|
implementation(platform(libs.androidx.compose.bom))
|
|
implementation(libs.androidx.compose.ui)
|
|
implementation(libs.androidx.compose.ui.tooling.preview)
|
|
implementation(libs.androidx.compose.material3)
|
|
implementation(libs.kotlinx.coroutines.android)
|
|
implementation(libs.okhttp)
|
|
implementation(libs.gson)
|
|
implementation(libs.androidx.work.runtime.ktx)
|
|
debugImplementation(libs.androidx.compose.ui.tooling)
|
|
|
|
testImplementation(libs.junit)
|
|
testImplementation(libs.kotlinx.coroutines.test)
|
|
testImplementation(libs.okhttp.mockwebserver)
|
|
testImplementation(libs.androidx.work.testing)
|
|
}
|