diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 465f98286..21a8ccd25 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,10 +13,6 @@ android { compileOptions { isCoreLibraryDesugaringEnabled = true } - ksp { - arg("room.incremental", "true") - arg("room.schemaLocation", "$projectDir/schemas") - } bundle { language { enableSplit = false @@ -38,6 +34,14 @@ android { } } +// KSP options (room schema export). The `ksp { }` extension is registered by the KSP Gradle +// plugin at the project level, not inside the Android DSL, so it is declared as a top-level +// block here. +ksp { + arg("room.incremental", "true") + arg("room.schemaLocation", "$projectDir/schemas") +} + dependencies { implementation(fileTree("libs")) @@ -76,7 +80,7 @@ dependencies { // widget; it replaces the archived com.blacksquircle.ui:editorkit. Syntax highlighting // is provided via TextMate grammars (language-textmate), with JSON grammar + themes // bundled in assets/textmate/. Versions are managed by the editor-bom platform. - implementation(platform("io.github.rosemoe:editor-bom:0.23.7")) + implementation(platform("io.github.rosemoe:editor-bom:0.24.6")) implementation("io.github.rosemoe:editor") implementation("io.github.rosemoe:language-textmate") @@ -87,16 +91,11 @@ dependencies { implementation("com.google.guava:guava:33.4.0-android") implementation("org.ini4j:ini4j:0.5.4") - implementation("com.simplecityapps:recyclerview-fastscroll:2.0.1") { - exclude(group = "androidx.recyclerview") - exclude(group = "androidx.appcompat") - } + implementation("me.zhanghai.android.fastscroll:library:1.3.0") implementation("androidx.room:room-runtime:2.7.2") ksp("androidx.room:room-compiler:2.7.2") implementation("androidx.room:room-ktx:2.7.2") - implementation("com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4") - ksp("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") } diff --git a/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt b/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt index 7292faaa8..7d5df6973 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt @@ -5,7 +5,6 @@ import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.TypeConverters -import dev.matrix.roomigrant.GenerateRoomMigrations import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.SagerNet import io.nekohasekai.sagernet.fmt.KryoConverters @@ -26,7 +25,6 @@ import kotlinx.coroutines.launch ] ) @TypeConverters(value = [KryoConverters::class, GsonConverters::class]) -@GenerateRoomMigrations abstract class SagerDatabase : RoomDatabase() { companion object { @@ -35,7 +33,6 @@ abstract class SagerDatabase : RoomDatabase() { val instance by lazy { SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs() Room.databaseBuilder(SagerNet.application, SagerDatabase::class.java, Key.DB_PROFILE) -// .addMigrations(*SagerDatabase_Migrations.build()) .setJournalMode(JournalMode.TRUNCATE) .allowMainThreadQueries() .enableMultiInstanceInvalidation() diff --git a/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt b/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt index d4ebf9800..a06bf1f03 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt @@ -3,14 +3,12 @@ package io.nekohasekai.sagernet.database.preference import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase -import dev.matrix.roomigrant.GenerateRoomMigrations import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.SagerNet import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @Database(entities = [KeyValuePair::class], version = 1) -@GenerateRoomMigrations abstract class PublicDatabase : RoomDatabase() { companion object { val instance by lazy { diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt index fc462b880..f89fbc866 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt @@ -23,7 +23,8 @@ import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView +import me.zhanghai.android.fastscroll.FastScrollerBuilder +import me.zhanghai.android.fastscroll.PopupTextProvider import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.SagerNet @@ -97,7 +98,7 @@ class AppListActivity : ThemedActivity() { private inner class AppsAdapter : RecyclerView.Adapter(), Filterable, - FastScrollRecyclerView.SectionedAdapter { + PopupTextProvider { var filteredApps = apps suspend fun reload() { @@ -146,7 +147,7 @@ class AppListActivity : ThemedActivity() { override fun getFilter(): Filter = filterImpl - override fun getSectionName(position: Int): String { + override fun getPopupText(view: View, position: Int): CharSequence { return filteredApps[position].name.firstOrNull()?.toString() ?: "" } @@ -214,6 +215,7 @@ class AppListActivity : ThemedActivity() { binding.list.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) binding.list.itemAnimator = DefaultItemAnimator() binding.list.adapter = appsAdapter + FastScrollerBuilder(binding.list).useMd2Style().build() ViewCompat.setOnApplyWindowInsetsListener(binding.root, ListListener) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt index 95b7a9b6a..713d40c6e 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt @@ -24,7 +24,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView +import me.zhanghai.android.fastscroll.FastScrollerBuilder +import me.zhanghai.android.fastscroll.PopupTextProvider import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.SagerNet @@ -101,7 +102,7 @@ class AppManagerActivity : ThemedActivity() { } private inner class AppsAdapter : RecyclerView.Adapter(), - FastScrollRecyclerView.SectionedAdapter { + PopupTextProvider { var filteredApps = apps suspend fun reload() { @@ -149,7 +150,7 @@ class AppManagerActivity : ThemedActivity() { notifyDataSetChanged() } - override fun getSectionName(position: Int): String { + override fun getPopupText(view: View, position: Int): CharSequence { return filteredApps[position].name.firstOrNull()?.toString() ?: "" } @@ -253,6 +254,7 @@ class AppManagerActivity : ThemedActivity() { binding.list.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) binding.list.itemAnimator = DefaultItemAnimator() binding.list.adapter = appsAdapter + FastScrollerBuilder(binding.list).useMd2Style().build() ViewCompat.setOnApplyWindowInsetsListener(binding.root, ListListener) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt index c2858156f..3489e2d16 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt @@ -115,6 +115,7 @@ import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import me.zhanghai.android.fastscroll.FastScrollerBuilder import moe.matsuri.nb4a.Protocols import moe.matsuri.nb4a.Protocols.getProtocolColor import moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity @@ -1400,6 +1401,7 @@ class ConfigurationFragment @JvmOverloads constructor( GroupManager.addListener(adapter!!) configurationListView.adapter = adapter configurationListView.setItemViewCacheSize(20) + FastScrollerBuilder(configurationListView).useMd2Style().build() // Hide the docked FAB while scrolling down (so it never overlaps the // bottom card) and bring it back on upward scroll or when the list diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt index 3c3345e24..5df30574b 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt @@ -24,6 +24,7 @@ import io.nekohasekai.sagernet.databinding.LayoutGroupItemBinding import io.nekohasekai.sagernet.fmt.toUniversalLink import io.nekohasekai.sagernet.group.GroupUpdater import io.nekohasekai.sagernet.ktx.* +import me.zhanghai.android.fastscroll.FastScrollerBuilder import io.nekohasekai.sagernet.widget.ListListener import io.nekohasekai.sagernet.widget.QRCodeDialog import io.nekohasekai.sagernet.widget.UndoSnackbarManager @@ -57,6 +58,7 @@ class GroupFragment : ToolbarFragment(R.layout.layout_group), groupAdapter = GroupAdapter() GroupManager.addListener(groupAdapter) groupListView.adapter = groupAdapter + FastScrollerBuilder(groupListView).useMd2Style().build() undoManager = UndoSnackbarManager(activity, groupAdapter) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt index d49ab1832..473b12f32 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt @@ -21,6 +21,7 @@ import io.nekohasekai.sagernet.databinding.LayoutEmptyRouteBinding import io.nekohasekai.sagernet.databinding.LayoutRouteBinding import io.nekohasekai.sagernet.databinding.LayoutRouteItemBinding import io.nekohasekai.sagernet.ktx.* +import me.zhanghai.android.fastscroll.FastScrollerBuilder import io.nekohasekai.sagernet.widget.ListListener import io.nekohasekai.sagernet.widget.UndoSnackbarManager @@ -46,6 +47,7 @@ class RouteFragment : ToolbarFragment(R.layout.layout_route), Toolbar.OnMenuItem ruleAdapter = RuleAdapter() ProfileManager.addListener(ruleAdapter) ruleListView.adapter = ruleAdapter + FastScrollerBuilder(ruleListView).useMd2Style().build() undoManager = UndoSnackbarManager(activity, ruleAdapter) ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.START) { diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ChainSettingsActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ChainSettingsActivity.kt index 5e573c66f..3465dfcfb 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ChainSettingsActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ChainSettingsActivity.kt @@ -27,6 +27,7 @@ import io.nekohasekai.sagernet.databinding.LayoutProfileBinding import io.nekohasekai.sagernet.fmt.internal.ChainBean import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ui.ProfileSelectActivity +import me.zhanghai.android.fastscroll.FastScrollerBuilder import moe.matsuri.nb4a.Protocols.getProtocolColor class ChainSettingsActivity : ProfileSettingsActivity(R.layout.layout_chain_settings) { @@ -69,6 +70,7 @@ class ChainSettingsActivity : ProfileSettingsActivity(R.layout.layout configurationList.layoutManager = layoutManager configurationAdapter = ProxiesAdapter() configurationList.adapter = configurationAdapter + FastScrollerBuilder(configurationList).useMd2Style().build() ItemTouchHelper(object : ItemTouchHelper.SimpleCallback( ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.START diff --git a/app/src/main/res/layout/layout_app_list.xml b/app/src/main/res/layout/layout_app_list.xml index 73b4a1633..443c3164c 100644 --- a/app/src/main/res/layout/layout_app_list.xml +++ b/app/src/main/res/layout/layout_app_list.xml @@ -101,17 +101,13 @@ - diff --git a/app/src/main/res/layout/layout_apps.xml b/app/src/main/res/layout/layout_apps.xml index decab9af6..aece62a66 100644 --- a/app/src/main/res/layout/layout_apps.xml +++ b/app/src/main/res/layout/layout_apps.xml @@ -138,17 +138,13 @@ - diff --git a/app/src/main/res/layout/layout_chain_settings.xml b/app/src/main/res/layout/layout_chain_settings.xml index 60888d105..2034bfd15 100644 --- a/app/src/main/res/layout/layout_chain_settings.xml +++ b/app/src/main/res/layout/layout_chain_settings.xml @@ -1,5 +1,4 @@ @@ -21,20 +20,13 @@ android:background="@android:color/darker_gray" android:orientation="horizontal" /> - + android:overScrollMode="never" /> - - - \ No newline at end of file + diff --git a/app/src/main/res/layout/layout_group.xml b/app/src/main/res/layout/layout_group.xml index caf90435b..1aa7679a8 100644 --- a/app/src/main/res/layout/layout_group.xml +++ b/app/src/main/res/layout/layout_group.xml @@ -1,6 +1,5 @@ @@ -14,17 +13,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - - - + android:scrollbarSize="0dp" /> diff --git a/app/src/main/res/layout/layout_profile_list.xml b/app/src/main/res/layout/layout_profile_list.xml index 04acc1496..7dfd6fa9f 100644 --- a/app/src/main/res/layout/layout_profile_list.xml +++ b/app/src/main/res/layout/layout_profile_list.xml @@ -1,6 +1,5 @@ - \ No newline at end of file + tools:listitem="@layout/layout_profile" /> diff --git a/app/src/main/res/layout/layout_route.xml b/app/src/main/res/layout/layout_route.xml index a2bce33ba..5351670ef 100644 --- a/app/src/main/res/layout/layout_route.xml +++ b/app/src/main/res/layout/layout_route.xml @@ -1,6 +1,5 @@ @@ -14,7 +13,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - - - + android:scrollbarSize="0dp" /> diff --git a/build.gradle.kts b/build.gradle.kts index 1dfefd7db..42ccd3663 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,5 +8,5 @@ tasks.register("clean") { } plugins { - id("com.google.devtools.ksp") version "2.1.21-2.0.2" apply false + id("com.google.devtools.ksp") version "2.3.9" apply false } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7c0687f09..271df8d0b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -8,5 +8,5 @@ apply(from = "../repositories.gradle.kts") dependencies { // Gradle Plugins implementation("com.android.tools.build:gradle:8.13.2") - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.21") + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.10") } diff --git a/buildSrc/src/main/kotlin/Helpers.kt b/buildSrc/src/main/kotlin/Helpers.kt index 541a990b4..6435cb038 100644 --- a/buildSrc/src/main/kotlin/Helpers.kt +++ b/buildSrc/src/main/kotlin/Helpers.kt @@ -3,9 +3,10 @@ import com.android.build.gradle.AbstractAppExtension import com.android.build.gradle.internal.api.BaseVariantOutputImpl import org.gradle.api.JavaVersion import org.gradle.api.Project -import org.gradle.api.plugins.ExtensionAware import org.gradle.kotlin.dsl.getByName -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.util.Base64 import java.util.Properties import kotlin.system.exitProcess @@ -56,9 +57,6 @@ fun Project.setupCommon() { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } - (android as ExtensionAware).extensions.getByName("kotlinOptions").apply { - jvmTarget = JavaVersion.VERSION_17.toString() - } lint { showAll = true checkAllWarnings = true @@ -109,6 +107,16 @@ fun Project.setupCommon() { } } } + + // Kotlin JVM target. Configured via the compilerOptions DSL on the Kotlin compile tasks + // (a project-level call, hence outside the android.apply { } block above); the legacy + // `kotlinOptions { jvmTarget = ... }` / KotlinJvmOptions API was removed (turned into a + // hard error) in Kotlin 2.3. + tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } } fun Project.setupAppCommon() { diff --git a/repositories.gradle.kts b/repositories.gradle.kts index 11023ba78..82d1c35d3 100644 --- a/repositories.gradle.kts +++ b/repositories.gradle.kts @@ -2,5 +2,4 @@ repositories { google() mavenCentral() gradlePluginPortal() - maven(url = "https://jitpack.io") } \ No newline at end of file