Migrate open source licenses screen to Compose
This commit is contained in:
parent
2b79295240
commit
1b4d9fc4e9
@ -239,6 +239,7 @@ dependencies {
|
|||||||
}
|
}
|
||||||
implementation(libs.insetter)
|
implementation(libs.insetter)
|
||||||
implementation(libs.markwon)
|
implementation(libs.markwon)
|
||||||
|
implementation(libs.aboutLibraries.compose)
|
||||||
|
|
||||||
// Conductor
|
// Conductor
|
||||||
implementation(libs.bundles.conductor)
|
implementation(libs.bundles.conductor)
|
||||||
@ -253,9 +254,6 @@ dependencies {
|
|||||||
implementation(libs.acra.http)
|
implementation(libs.acra.http)
|
||||||
"standardImplementation"(libs.firebase.analytics)
|
"standardImplementation"(libs.firebase.analytics)
|
||||||
|
|
||||||
// Licenses
|
|
||||||
implementation(libs.aboutlibraries.core)
|
|
||||||
|
|
||||||
// Shizuku
|
// Shizuku
|
||||||
implementation(libs.bundles.shizuku)
|
implementation(libs.bundles.shizuku)
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ import eu.kanade.presentation.theme.TachiyomiTheme
|
|||||||
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
|
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
|
||||||
import nucleus.presenter.Presenter
|
import nucleus.presenter.Presenter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose controller with a Nucleus presenter.
|
||||||
|
*/
|
||||||
abstract class ComposeController<P : Presenter<*>> : NucleusController<ComposeControllerBinding, P>() {
|
abstract class ComposeController<P : Presenter<*>> : NucleusController<ComposeControllerBinding, P>() {
|
||||||
|
|
||||||
override fun createBinding(inflater: LayoutInflater): ComposeControllerBinding =
|
override fun createBinding(inflater: LayoutInflater): ComposeControllerBinding =
|
||||||
@ -24,3 +27,24 @@ abstract class ComposeController<P : Presenter<*>> : NucleusController<ComposeCo
|
|||||||
|
|
||||||
@Composable abstract fun ComposeContent()
|
@Composable abstract fun ComposeContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic Compose controller without a presenter.
|
||||||
|
*/
|
||||||
|
abstract class BasicComposeController : BaseController<ComposeControllerBinding>() {
|
||||||
|
|
||||||
|
override fun createBinding(inflater: LayoutInflater): ComposeControllerBinding =
|
||||||
|
ComposeControllerBinding.inflate(inflater)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View) {
|
||||||
|
super.onViewCreated(view)
|
||||||
|
|
||||||
|
binding.root.setContent {
|
||||||
|
TachiyomiTheme {
|
||||||
|
ComposeContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable abstract fun ComposeContent()
|
||||||
|
}
|
||||||
|
@ -9,7 +9,6 @@ import eu.kanade.tachiyomi.data.updater.RELEASE_URL
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.NoAppBarElevationController
|
import eu.kanade.tachiyomi.ui.base.controller.NoAppBarElevationController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.more.licenses.LicensesController
|
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||||
import eu.kanade.tachiyomi.util.lang.launchNow
|
import eu.kanade.tachiyomi.util.lang.launchNow
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.more
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||||
|
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
||||||
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults.libraryColors
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.BasicComposeController
|
||||||
|
|
||||||
|
class LicensesController : BasicComposeController() {
|
||||||
|
|
||||||
|
override fun getTitle() = resources?.getString(R.string.licenses)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun ComposeContent() {
|
||||||
|
val nestedScrollInterop = rememberNestedScrollInteropConnection(binding.root)
|
||||||
|
|
||||||
|
LibrariesContainer(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.nestedScroll(nestedScrollInterop),
|
||||||
|
colors = libraryColors(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.background,
|
||||||
|
contentColor = contentColorFor(MaterialTheme.colorScheme.background),
|
||||||
|
badgeBackgroundColor = MaterialTheme.colorScheme.primary,
|
||||||
|
badgeContentColor = contentColorFor(MaterialTheme.colorScheme.primary),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.more.licenses
|
|
||||||
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
|
|
||||||
class LicensesAdapter(controller: LicensesController) :
|
|
||||||
FlexibleAdapter<LicensesItem>(null, controller, true)
|
|
@ -1,75 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.more.licenses
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import com.mikepenz.aboutlibraries.Libs
|
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.databinding.LicensesControllerBinding
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
|
||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
|
||||||
|
|
||||||
class LicensesController :
|
|
||||||
BaseController<LicensesControllerBinding>(),
|
|
||||||
FlexibleAdapter.OnItemClickListener {
|
|
||||||
|
|
||||||
private var adapter: LicensesAdapter? = null
|
|
||||||
|
|
||||||
override fun getTitle(): String? {
|
|
||||||
return resources?.getString(R.string.licenses)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createBinding(inflater: LayoutInflater) = LicensesControllerBinding.inflate(inflater)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View) {
|
|
||||||
super.onViewCreated(view)
|
|
||||||
binding.recycler.applyInsetter {
|
|
||||||
type(navigationBars = true) {
|
|
||||||
padding()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.progress.applyInsetter {
|
|
||||||
type(navigationBars = true) {
|
|
||||||
padding()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
|
||||||
adapter = LicensesAdapter(this)
|
|
||||||
binding.recycler.adapter = adapter
|
|
||||||
|
|
||||||
viewScope.launchUI {
|
|
||||||
val licenseItems = withIOContext {
|
|
||||||
Libs(view.context).libraries
|
|
||||||
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, { it.libraryName }))
|
|
||||||
.map { LicensesItem(it) }
|
|
||||||
}
|
|
||||||
binding.progress.hide()
|
|
||||||
adapter?.updateDataSet(licenseItems)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
|
||||||
adapter = null
|
|
||||||
super.onDestroyView(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemClick(view: View, position: Int): Boolean {
|
|
||||||
val adapter = adapter ?: return false
|
|
||||||
|
|
||||||
val item = adapter.getItem(position) ?: return false
|
|
||||||
openLicenseWebsite(item)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openLicenseWebsite(item: LicensesItem) {
|
|
||||||
val website = item.library.libraryWebsite
|
|
||||||
if (website.isNotEmpty()) {
|
|
||||||
activity?.openInBrowser(website)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.more.licenses
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.view.View
|
|
||||||
import com.mikepenz.aboutlibraries.entity.Library
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
|
||||||
import eu.kanade.tachiyomi.databinding.LicensesItemBinding
|
|
||||||
|
|
||||||
class LicensesHolder(view: View, adapter: FlexibleAdapter<*>) :
|
|
||||||
FlexibleViewHolder(view, adapter) {
|
|
||||||
|
|
||||||
private val binding = LicensesItemBinding.bind(view)
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
fun bind(library: Library) {
|
|
||||||
binding.name.text = "${library.libraryName} ${library.libraryVersion}"
|
|
||||||
binding.artifactId.text = library.libraryArtifactId
|
|
||||||
binding.license.text = library.licenses?.joinToString { it.licenseName }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.more.licenses
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.mikepenz.aboutlibraries.entity.Library
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
class LicensesItem(val library: Library) : AbstractFlexibleItem<LicensesHolder>() {
|
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
|
||||||
return R.layout.licenses_item
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LicensesHolder {
|
|
||||||
return LicensesHolder(view, adapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun bindViewHolder(
|
|
||||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
|
||||||
holder: LicensesHolder,
|
|
||||||
position: Int,
|
|
||||||
payloads: List<Any?>?,
|
|
||||||
) {
|
|
||||||
holder.bind(library)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other is LicensesItem) {
|
|
||||||
return library.hashCode() == other.hashCode()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return library.hashCode()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
|
||||||
android:id="@+id/progress"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:indeterminate="true" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
tools:listitem="@layout/licenses_item" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/list_item_selector_background"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="8dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
tools:text="Library name" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/artifact_id"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
tools:text="artifact:id:1.0" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/license"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
tools:text="Apache Version 2.0" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -2,7 +2,7 @@ buildscript {
|
|||||||
dependencies {
|
dependencies {
|
||||||
classpath(libs.android.shortcut.gradle)
|
classpath(libs.android.shortcut.gradle)
|
||||||
classpath(libs.google.services.gradle)
|
classpath(libs.google.services.gradle)
|
||||||
classpath(libs.aboutlibraries.gradle)
|
classpath(libs.aboutLibraries.gradle)
|
||||||
classpath(kotlinx.serialization.gradle)
|
classpath(kotlinx.serialization.gradle)
|
||||||
classpath("com.squareup.sqldelight:gradle-plugin:1.5.3")
|
classpath("com.squareup.sqldelight:gradle-plugin:1.5.3")
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
aboutlib_version = "8.9.4"
|
aboutlib_version = "10.1.0"
|
||||||
okhttp_version = "4.9.3"
|
okhttp_version = "4.9.3"
|
||||||
nucleus_version = "3.0.0"
|
nucleus_version = "3.0.0"
|
||||||
coil_version = "2.0.0-rc03"
|
coil_version = "2.0.0-rc03"
|
||||||
@ -83,8 +83,8 @@ logcat = "com.squareup.logcat:logcat:0.1"
|
|||||||
acra-http = "ch.acra:acra-http:5.9.1"
|
acra-http = "ch.acra:acra-http:5.9.1"
|
||||||
firebase-analytics = "com.google.firebase:firebase-analytics-ktx:20.0.2"
|
firebase-analytics = "com.google.firebase:firebase-analytics-ktx:20.0.2"
|
||||||
|
|
||||||
aboutlibraries-core = { module = "com.mikepenz:aboutlibraries-core", version.ref = "aboutlib_version" }
|
aboutLibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" }
|
||||||
aboutlibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" }
|
aboutLibraries-compose = { module = "com.mikepenz:aboutlibraries-compose", version.ref ="aboutlib_version" }
|
||||||
|
|
||||||
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" }
|
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" }
|
||||||
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" }
|
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" }
|
||||||
|
Loading…
Reference in New Issue
Block a user