mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 21:38:44 +08:00
feat(core): improve mobile perf (#15317)
#### PR Dependency Tree * **PR #15317** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Virtualized mobile navigation with shell navigation and interactive swipe menus; coordinated mobile back handling with interactive phases/state restoration. * Added shared auth request proxy and message-port based token handling across mobile and worker flows. * **Bug Fixes** * Hydrated remote worker error stacks for calls and observable errors. * Improved SQLite FTS/indexer and nbstore optional text handling; refined docs-search ref parsing and notification loading/retry. * **Refactor / UX** * Modal focus-preservation and pointer behavior updates; improved mobile menu controls and back gesture plugins. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -20,35 +20,42 @@ def nativeAbi = nativeTarget == 'x86_64' ? 'x86_64' : 'arm64-v8a'
|
||||
apply from: 'capacitor.build.gradle'
|
||||
|
||||
android {
|
||||
namespace "app.affine.pro"
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
namespace = "app.affine.pro"
|
||||
compileSdk = rootProject.ext.compileSdkVersion
|
||||
ndkVersion = new File(sdkDirectory, "ndk").listFiles().sort().last().name
|
||||
defaultConfig {
|
||||
applicationId "app.affine.pro"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName System.getenv('VERSION_NAME') ?: 'v1.0.0-local'
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
applicationId = "app.affine.pro"
|
||||
minSdkVersion = rootProject.ext.minSdkVersion
|
||||
targetSdkVersion = rootProject.ext.targetSdkVersion
|
||||
versionCode = 1
|
||||
versionName = System.getenv('VERSION_NAME') ?: 'v1.0.0-local'
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
manifestPlaceholders = [usesCleartextTraffic: "false"]
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
||||
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
}
|
||||
ndk {
|
||||
abiFilters nativeAbi
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
buildConfig true
|
||||
viewBinding true
|
||||
compose = true
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
profile {
|
||||
initWith release
|
||||
profileable true
|
||||
signingConfig signingConfigs.debug
|
||||
matchingFallbacks = ['release']
|
||||
}
|
||||
debug {
|
||||
minifyEnabled false
|
||||
@@ -112,6 +119,7 @@ dependencies {
|
||||
implementation libs.androidx.datastore.preferences
|
||||
implementation libs.androidx.navigation.fragment
|
||||
implementation libs.androidx.navigation.ui.ktx
|
||||
implementation libs.androidx.webkit
|
||||
|
||||
implementation libs.apollo.runtime
|
||||
implementation (libs.jna) {
|
||||
@@ -159,8 +167,8 @@ cargo {
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
apiVersion = KotlinVersion.KOTLIN_2_1
|
||||
languageVersion = KotlinVersion.KOTLIN_2_1
|
||||
apiVersion = KotlinVersion.KOTLIN_2_2
|
||||
languageVersion = KotlinVersion.KOTLIN_2_2
|
||||
jvmTarget = JvmTarget.JVM_21
|
||||
}
|
||||
}
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package app.affine.pro
|
||||
|
||||
import androidx.activity.BackEventCompat
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MobileBackDispatcherTest {
|
||||
@Test
|
||||
fun disabledAppCallbackPassesTheSameBackToTheNextCallback() {
|
||||
ActivityScenario.launch(MainActivity::class.java).use { scenario ->
|
||||
scenario.onActivity { activity ->
|
||||
var fallbackCalled = false
|
||||
activity.onBackPressedDispatcher.addCallback(
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
fallbackCalled = true
|
||||
}
|
||||
},
|
||||
)
|
||||
val appCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() = Unit
|
||||
}
|
||||
activity.onBackPressedDispatcher.addCallback(appCallback)
|
||||
|
||||
appCallback.isEnabled = false
|
||||
activity.onBackPressedDispatcher.onBackPressed()
|
||||
|
||||
assertTrue(fallbackCalled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun predictiveLifecycleTargetsOneEnabledCallback() {
|
||||
ActivityScenario.launch(MainActivity::class.java).use { scenario ->
|
||||
scenario.onActivity { activity ->
|
||||
val phases = mutableListOf<String>()
|
||||
activity.onBackPressedDispatcher.addCallback(
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackStarted(backEvent: BackEventCompat) {
|
||||
phases.add("begin")
|
||||
}
|
||||
|
||||
override fun handleOnBackProgressed(backEvent: BackEventCompat) {
|
||||
phases.add("progress")
|
||||
}
|
||||
|
||||
override fun handleOnBackCancelled() {
|
||||
phases.add("cancel")
|
||||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
phases.add("commit")
|
||||
}
|
||||
},
|
||||
)
|
||||
val event = BackEventCompat(0f, 0f, 0.5f, BackEventCompat.EDGE_LEFT)
|
||||
activity.onBackPressedDispatcher.dispatchOnBackStarted(event)
|
||||
activity.onBackPressedDispatcher.dispatchOnBackProgressed(event)
|
||||
activity.onBackPressedDispatcher.dispatchOnBackCancelled()
|
||||
activity.onBackPressedDispatcher.dispatchOnBackStarted(event)
|
||||
activity.onBackPressedDispatcher.onBackPressed()
|
||||
|
||||
assertEquals(
|
||||
listOf("begin", "progress", "cancel", "begin", "commit"),
|
||||
phases,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="@string/title_activity_main"
|
||||
|
||||
@@ -3,6 +3,12 @@ package app.affine.pro
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.SystemClock
|
||||
import androidx.webkit.WebViewCompat
|
||||
import androidx.webkit.WebViewOutcomeReceiver
|
||||
import androidx.webkit.WebViewStartUpConfig
|
||||
import androidx.webkit.WebViewStartUpResult
|
||||
import androidx.webkit.WebViewStartupException
|
||||
import app.affine.pro.utils.logger.AffineDebugTree
|
||||
import app.affine.pro.utils.logger.CrashlyticsTree
|
||||
import app.affine.pro.utils.logger.FileTree
|
||||
@@ -11,12 +17,14 @@ import com.google.firebase.crashlytics.setCustomKeys
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@HiltAndroidApp
|
||||
class AFFiNEApp : Application() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
startWebView()
|
||||
_context = applicationContext
|
||||
// init logger
|
||||
if (BuildConfig.DEBUG) {
|
||||
@@ -33,6 +41,30 @@ class AFFiNEApp : Application() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun startWebView() {
|
||||
val startedAt = SystemClock.elapsedRealtime()
|
||||
val executor = Executors.newSingleThreadExecutor()
|
||||
val config = WebViewStartUpConfig.Builder(executor).build()
|
||||
WebViewCompat.startUpWebView(
|
||||
this,
|
||||
config,
|
||||
object : WebViewOutcomeReceiver<WebViewStartUpResult, WebViewStartupException> {
|
||||
override fun onResult(result: WebViewStartUpResult) {
|
||||
executor.shutdown()
|
||||
Timber.i(
|
||||
"WebView startup completed asynchronously in %d ms.",
|
||||
SystemClock.elapsedRealtime() - startedAt,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onError(error: WebViewStartupException) {
|
||||
executor.shutdown()
|
||||
Timber.w(error, "WebView asynchronous startup failed.")
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
_context = null
|
||||
super.onTerminate()
|
||||
@@ -44,4 +76,4 @@ class AFFiNEApp : Application() {
|
||||
|
||||
fun context() = requireNotNull(_context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ object AuthInitializer {
|
||||
fun initialize(bridge: Bridge) {
|
||||
bridge.addWebViewListener(object : WebViewListener() {
|
||||
override fun onPageLoaded(webView: WebView?) {
|
||||
bridge.removeWebViewListener(this)
|
||||
webView?.post { bridge.removeWebViewListener(this) }
|
||||
MainScope().launch(Dispatchers.IO) {
|
||||
try {
|
||||
FileTree.get()?.checkAndUploadOldLogs(
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package app.affine.pro
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.ComponentCallbacks2
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.webkit.WebSettings
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updateMargins
|
||||
@@ -19,6 +22,7 @@ import app.affine.pro.plugin.AFFiNEThemePlugin
|
||||
import app.affine.pro.plugin.AuthPlugin
|
||||
import app.affine.pro.plugin.HashCashPlugin
|
||||
import app.affine.pro.plugin.NbStorePlugin
|
||||
import app.affine.pro.plugin.MobileBackPlugin
|
||||
import app.affine.pro.plugin.PreviewPlugin
|
||||
import app.affine.pro.service.GraphQLService
|
||||
import app.affine.pro.service.SSEService
|
||||
@@ -53,6 +57,7 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AFFiNEThemePlugi
|
||||
AuthPlugin::class.java,
|
||||
HashCashPlugin::class.java,
|
||||
NbStorePlugin::class.java,
|
||||
MobileBackPlugin::class.java,
|
||||
PreviewPlugin::class.java,
|
||||
)
|
||||
)
|
||||
@@ -83,6 +88,8 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AFFiNEThemePlugi
|
||||
private var navHeight = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen()
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
|
||||
navHeight = px2dp(insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom)
|
||||
@@ -96,6 +103,16 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AFFiNEThemePlugi
|
||||
configureEditorWebView()
|
||||
}
|
||||
|
||||
override fun onTrimMemory(level: Int) {
|
||||
super.onTrimMemory(level)
|
||||
if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
|
||||
bridge.webView.evaluateJavascript(
|
||||
"window.dispatchEvent(new Event('affine:memory-pressure'))",
|
||||
null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureEditorWebView() {
|
||||
bridge.webView.apply {
|
||||
overScrollMode = View.OVER_SCROLL_NEVER
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package app.affine.pro.plugin
|
||||
|
||||
import androidx.activity.BackEventCompat
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import com.getcapacitor.JSObject
|
||||
import com.getcapacitor.Plugin
|
||||
import com.getcapacitor.PluginCall
|
||||
import com.getcapacitor.PluginMethod
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
|
||||
@CapacitorPlugin(name = "MobileBack")
|
||||
class MobileBackPlugin : Plugin() {
|
||||
private val callback = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackStarted(backEvent: BackEventCompat) {
|
||||
emit("begin", backEvent.progress)
|
||||
}
|
||||
|
||||
override fun handleOnBackProgressed(backEvent: BackEventCompat) {
|
||||
emit("progress", backEvent.progress)
|
||||
}
|
||||
|
||||
override fun handleOnBackCancelled() {
|
||||
emit("cancel")
|
||||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
emit("commit")
|
||||
}
|
||||
}
|
||||
|
||||
override fun load() {
|
||||
activity.onBackPressedDispatcher.addCallback(activity, callback)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun setEnabled(call: PluginCall) {
|
||||
callback.isEnabled = call.getBoolean("enabled", false) ?: false
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
private fun emit(phase: String, progress: Float? = null) {
|
||||
notifyListeners("back", JSObject().apply {
|
||||
put("phase", phase)
|
||||
progress?.let { put("progress", it) }
|
||||
})
|
||||
}
|
||||
|
||||
override fun handleOnDestroy() {
|
||||
callback.remove()
|
||||
super.handleOnDestroy()
|
||||
}
|
||||
}
|
||||
+9
-6
@@ -7,11 +7,14 @@ import com.getcapacitor.PluginCall
|
||||
import com.getcapacitor.PluginMethod
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.json.JSONObject
|
||||
import timber.log.Timber
|
||||
import uniffi.affine_mobile_native.DocRecord
|
||||
import uniffi.affine_mobile_native.SetBlob
|
||||
import uniffi.affine_mobile_native.newDocStoragePool
|
||||
|
||||
private const val ANDROID_INDEXER_VERSION_OFFSET = 1u
|
||||
|
||||
@CapacitorPlugin(name = "NbStoreDocStorage")
|
||||
class NbStorePlugin : Plugin() {
|
||||
|
||||
@@ -598,10 +601,10 @@ class NbStorePlugin : Plugin() {
|
||||
JSObject()
|
||||
.put("blockId", block.blockId)
|
||||
.put("flavour", block.flavour)
|
||||
.put("content", block.content)
|
||||
.put("blob", block.blob)
|
||||
.put("refDocId", block.refDocId)
|
||||
.put("refInfo", block.refInfo)
|
||||
.put("content", block.content?.let(::JSArray))
|
||||
.put("blob", block.blob?.let(::JSArray))
|
||||
.put("refDocId", block.refDocId?.let(::JSArray))
|
||||
.put("refInfo", block.refInfo?.let(::JSArray))
|
||||
.put("parentFlavour", block.parentFlavour)
|
||||
.put("parentBlockId", block.parentBlockId)
|
||||
.put("additional", block.additional)
|
||||
@@ -683,7 +686,7 @@ class NbStorePlugin : Plugin() {
|
||||
val indexName = call.getStringEnsure("indexName")
|
||||
val docId = call.getStringEnsure("docId")
|
||||
val text = docStoragePool.ftsGetDocument(id, indexName, docId)
|
||||
call.resolve(JSObject().put("text", text))
|
||||
call.resolve(JSObject().put("text", text ?: JSONObject.NULL))
|
||||
} catch (e: Exception) {
|
||||
call.reject("Failed to get fts document: ${e.message}", null, e)
|
||||
}
|
||||
@@ -728,7 +731,7 @@ class NbStorePlugin : Plugin() {
|
||||
fun ftsIndexVersion(call: PluginCall) {
|
||||
launch(Dispatchers.IO) {
|
||||
try {
|
||||
val version = docStoragePool.ftsIndexVersion()
|
||||
val version = docStoragePool.ftsIndexVersion() + ANDROID_INDEXER_VERSION_OFFSET
|
||||
call.resolve(JSObject().put("indexVersion", version))
|
||||
} catch (e: Exception) {
|
||||
call.reject("Failed to get fts index version: ${e.message}", null, e)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="windowSplashScreenBackground">#FFFFFF</item>
|
||||
<item name="postSplashScreenTheme">@style/AppTheme.NoActionBar</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ext {
|
||||
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
|
||||
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '10.1.1'
|
||||
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
||||
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '14.0.1'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
@@ -9,21 +9,23 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.2'
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
namespace "capacitor.cordova.android.plugins"
|
||||
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
||||
namespace = "capacitor.cordova.android.plugins"
|
||||
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
||||
defaultConfig {
|
||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
abortOnError = false
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
@@ -54,4 +56,4 @@ apply from: "cordova.variables.gradle"
|
||||
|
||||
for (def func : cdvPluginPostBuildExtras) {
|
||||
func()
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
ext {
|
||||
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
||||
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
||||
// Plugin gradle extensions can append to this to have code run at the end.
|
||||
cdvPluginPostBuildExtras = []
|
||||
cordovaConfig = [:]
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:amazon="http://schemas.amazon.com/apk/res/android">
|
||||
<application android:usesCleartextTraffic="true">
|
||||
<application >
|
||||
|
||||
</application>
|
||||
|
||||
|
||||
@@ -20,5 +20,6 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.r8.optimizedResourceShrinking=true
|
||||
ksp.incremental.apt=true
|
||||
ksp.useKSP2=true
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[versions]
|
||||
android-gradle-plugin = "8.13.2"
|
||||
androidx-activity-compose = "1.10.1"
|
||||
androidx-appcompat = "1.7.0"
|
||||
androidx-browser = "1.8.0"
|
||||
androidx-activity-compose = "1.13.0"
|
||||
androidx-appcompat = "1.7.1"
|
||||
androidx-browser = "1.9.0"
|
||||
androidx-compose-bom = "2025.05.00"
|
||||
androidx-coordinatorlayout = "1.3.0"
|
||||
androidx-core-ktx = "1.16.0"
|
||||
androidx-core-splashscreen = "1.0.1"
|
||||
androidx-core-ktx = "1.17.0"
|
||||
androidx-core-splashscreen = "1.2.0"
|
||||
androidx-datastore-preferences = "1.2.0-alpha02"
|
||||
androidx-espresso-core = "3.6.1"
|
||||
androidx-junit = "1.2.1"
|
||||
androidx-espresso-core = "3.7.0"
|
||||
androidx-junit = "1.3.0"
|
||||
androidx-lifecycle-compose = "2.9.0"
|
||||
androidx-material3 = "1.3.1"
|
||||
androidx-navigation = "2.9.0"
|
||||
@@ -19,25 +19,26 @@ apollo-kotlin-adapters = "0.0.6"
|
||||
compileSdk = "36"
|
||||
firebase-bom = "33.13.0"
|
||||
firebase-crashlytics = "3.0.3"
|
||||
google-services = "4.4.2"
|
||||
google-services = "4.4.4"
|
||||
gradle-versions = "0.52.0"
|
||||
hilt = "2.56.2"
|
||||
hilt-ext = "1.2.0"
|
||||
jna = "5.17.0"
|
||||
junit = "4.13.2"
|
||||
kotlin = "2.1.20"
|
||||
kotlin = "2.2.20"
|
||||
kotlinx-coroutines = "1.10.2"
|
||||
kotlinx-datetime = "0.6.2"
|
||||
kotlinx-serialization-json = "1.8.1"
|
||||
ksp = "2.1.20-2.0.1"
|
||||
ksp = "2.2.20-2.0.4"
|
||||
# @keep
|
||||
minSdk = "23"
|
||||
minSdk = "24"
|
||||
mozilla-rust-android = "0.9.6"
|
||||
okhttp-bom = "5.0.0-alpha.14"
|
||||
richtext = "1.0.0-alpha02"
|
||||
# @keep
|
||||
targetSdk = "35"
|
||||
targetSdk = "36"
|
||||
timber = "5.0.1"
|
||||
webkit = "1.16.0"
|
||||
version-catalog-update = "1.0.0"
|
||||
|
||||
[libraries]
|
||||
@@ -67,6 +68,7 @@ androidx-lifecycle-viewModelCompose = { module = "androidx.lifecycle:lifecy
|
||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }
|
||||
androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" }
|
||||
androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" }
|
||||
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
|
||||
apollo-adapters-core = { module = "com.apollographql.adapters:apollo-adapters-core", version.ref = "apollo-kotlin-adapters" }
|
||||
apollo-adapters-kotlinx-datetime = { module = "com.apollographql.adapters:apollo-adapters-kotlinx-datetime", version.ref = "apollo-kotlin-adapters" }
|
||||
apollo-api = { module = "com.apollographql.apollo:apollo-api", version.ref = "apollo" }
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Reference in New Issue
Block a user