fix: separate update,delete buttons | TOS, privpol

This commit is contained in:
rebel onion 2024-12-30 21:37:31 -06:00
parent 43dee6ee49
commit 116de6324e
12 changed files with 197 additions and 117 deletions

View file

@ -51,6 +51,7 @@ import ani.dantotsu.others.calc.CalcActivity
import ani.dantotsu.profile.ProfileActivity import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.profile.activity.FeedActivity import ani.dantotsu.profile.activity.FeedActivity
import ani.dantotsu.profile.notification.NotificationActivity import ani.dantotsu.profile.notification.NotificationActivity
import ani.dantotsu.settings.AddRepositoryBottomSheet
import ani.dantotsu.settings.ExtensionsActivity import ani.dantotsu.settings.ExtensionsActivity
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefManager.asLiveBool import ani.dantotsu.settings.saving.PrefManager.asLiveBool
@ -457,9 +458,11 @@ class MainActivity : AppCompatActivity() {
} }
val savedRepos: Set<String> = PrefManager.getVal(prefName) val savedRepos: Set<String> = PrefManager.getVal(prefName)
val newRepos = savedRepos.toMutableSet() val newRepos = savedRepos.toMutableSet()
newRepos.add(url) AddRepositoryBottomSheet.addRepoWarning(this) {
PrefManager.setVal(prefName, newRepos) newRepos.add(url)
toast("${if (uri.scheme == "tachiyomi") "Manga" else "Anime"} Extension Repo added") PrefManager.setVal(prefName, newRepos)
toast("${if (uri.scheme == "tachiyomi") "Manga" else "Anime"} Extension Repo added")
}
return return
} }
if (intent.type == null) return if (intent.type == null) return

View file

@ -22,7 +22,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
suspend fun getUserId(context: Context, block: () -> Unit) { suspend fun getUserId(context: Context, block: () -> Unit) {
if (!Anilist.initialized) { if (!Anilist.initialized && PrefManager.getVal<String>(PrefName.AnilistToken) != "") {
if (Anilist.query.getUserData()) { if (Anilist.query.getUserData()) {
tryWithSuspend { tryWithSuspend {
if (MAL.token != null && !MAL.query.getUserData()) if (MAL.token != null && !MAL.query.getUserData())

View file

@ -159,7 +159,7 @@ class NovelExtensionManager(private val context: Context) {
* *
* @param pkgName The package name of the application to uninstall. * @param pkgName The package name of the application to uninstall.
*/ */
fun uninstallExtension(pkgName: String, context: Context) { fun uninstallExtension(pkgName: String) {
installer.uninstallApk(pkgName) installer.uninstallApk(pkgName)
} }

View file

@ -1,5 +1,6 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
import android.view.LayoutInflater import android.view.LayoutInflater
@ -12,6 +13,7 @@ import ani.dantotsu.R
import ani.dantotsu.databinding.BottomSheetAddRepositoryBinding import ani.dantotsu.databinding.BottomSheetAddRepositoryBinding
import ani.dantotsu.databinding.ItemRepoBinding import ani.dantotsu.databinding.ItemRepoBinding
import ani.dantotsu.media.MediaType import ani.dantotsu.media.MediaType
import ani.dantotsu.util.customAlertDialog
import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.GroupieAdapter
import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.BindableItem
@ -72,8 +74,12 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
val input = binding.repositoryInput.text.toString() val input = binding.repositoryInput.text.toString()
val error = isValidUrl(input) val error = isValidUrl(input)
if (error == null) { if (error == null) {
onRepositoryAdded?.invoke(input, mediaType) context?.let { context ->
dismiss() addRepoWarning(context) {
onRepositoryAdded?.invoke(input, mediaType)
dismiss()
}
}
} else { } else {
binding.repositoryInput.error = error binding.repositoryInput.error = error
} }
@ -86,11 +92,16 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
binding.repositoryInput.setOnEditorActionListener { textView, action, keyEvent -> binding.repositoryInput.setOnEditorActionListener { textView, action, keyEvent ->
if (action == EditorInfo.IME_ACTION_DONE || if (action == EditorInfo.IME_ACTION_DONE ||
(keyEvent?.action == KeyEvent.ACTION_UP && keyEvent.keyCode == KeyEvent.KEYCODE_ENTER)) { (keyEvent?.action == KeyEvent.ACTION_UP && keyEvent.keyCode == KeyEvent.KEYCODE_ENTER)) {
if (!textView.text.isNullOrBlank()) { val url = textView.text.toString()
val error = isValidUrl(textView.text.toString()) if (url.isNotBlank()) {
val error = isValidUrl(url)
if (error == null) { if (error == null) {
onRepositoryAdded?.invoke(textView.text.toString(), mediaType) context?.let { context ->
dismiss() addRepoWarning(context) {
onRepositoryAdded?.invoke(url, mediaType)
dismiss()
}
}
return@setOnEditorActionListener true return@setOnEditorActionListener true
} else { } else {
binding.repositoryInput.error = error binding.repositoryInput.error = error
@ -121,6 +132,16 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
} }
companion object { companion object {
fun addRepoWarning(context: Context, onRepositoryAdded: () -> Unit) {
context.customAlertDialog()
.setTitle(R.string.warning)
.setMessage(R.string.add_repository_warning)
.setPosButton(R.string.ok) {
onRepositoryAdded.invoke()
}
.setNegButton(R.string.cancel) { }
.show()
}
fun newInstance( fun newInstance(
mediaType: MediaType, mediaType: MediaType,
repositories: List<String>, repositories: List<String>,

View file

@ -1,6 +1,5 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.app.AlertDialog
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
@ -44,13 +43,10 @@ import kotlinx.coroutines.launch
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Collections
import java.util.Locale import java.util.Locale
class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler { class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
private var _binding: FragmentExtensionsBinding? = null private var _binding: FragmentExtensionsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var extensionsRecyclerView: RecyclerView private lateinit var extensionsRecyclerView: RecyclerView
@ -122,15 +118,20 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
.show() .show()
} }
}, },
{ pkg, forceDelete -> { pkg ->
if (isAdded) { // Check if the fragment is currently added to its activity if (isAdded) {
val context = requireContext() // Store context in a variable animeExtensionManager.uninstallExtension(pkg.pkgName)
snackString("Extension uninstalled")
}
}, { pkg ->
if (isAdded) {
val context = requireContext()
val notificationManager = val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (pkg.hasUpdate && !forceDelete) { if (pkg.hasUpdate) {
animeExtensionManager.updateExtension(pkg) animeExtensionManager.updateExtension(pkg)
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
{ installStep -> { installStep ->
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(
@ -145,7 +146,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
}, },
{ error -> { error ->
Injekt.get<CrashlyticsInterface>().logException(error) Injekt.get<CrashlyticsInterface>().logException(error)
Logger.log(error) // Log the error Logger.log(error)
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(
context, context,
Notifications.CHANNEL_DOWNLOADER_ERROR Notifications.CHANNEL_DOWNLOADER_ERROR
@ -171,14 +172,13 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
} }
) )
} else { } else {
animeExtensionManager.uninstallExtension(pkg.pkgName) snackString("No update available")
snackString("Extension uninstalled")
} }
} }
}, skipIcons }, skipIcons
) )
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -198,17 +198,10 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder target: RecyclerView.ViewHolder
): Boolean { ): Boolean {
val newList = extensionsAdapter.currentList.toMutableList()
val fromPosition = viewHolder.absoluteAdapterPosition val fromPosition = viewHolder.absoluteAdapterPosition
val toPosition = target.absoluteAdapterPosition val toPosition = target.absoluteAdapterPosition
if (fromPosition < toPosition) { //probably need to switch to a recyclerview adapter val newList = extensionsAdapter.currentList.toMutableList().apply {
for (i in fromPosition until toPosition) { add(toPosition, removeAt(fromPosition))
Collections.swap(newList, i, i + 1)
}
} else {
for (i in fromPosition downTo toPosition + 1) {
Collections.swap(newList, i, i - 1)
}
} }
extensionsAdapter.submitList(newList) extensionsAdapter.submitList(newList)
return true return true
@ -270,7 +263,8 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
private class AnimeExtensionsAdapter( private class AnimeExtensionsAdapter(
private val onSettingsClicked: (AnimeExtension.Installed) -> Unit, private val onSettingsClicked: (AnimeExtension.Installed) -> Unit,
private val onUninstallClicked: (AnimeExtension.Installed, Boolean) -> Unit, private val onUninstallClicked: (AnimeExtension.Installed) -> Unit,
private val onUpdateClicked: (AnimeExtension.Installed) -> Unit,
val skipIcons: Boolean val skipIcons: Boolean
) : ListAdapter<AnimeExtension.Installed, AnimeExtensionsAdapter.ViewHolder>( ) : ListAdapter<AnimeExtension.Installed, AnimeExtensionsAdapter.ViewHolder>(
DIFF_CALLBACK_INSTALLED DIFF_CALLBACK_INSTALLED
@ -304,20 +298,19 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
holder.extensionIconImageView.setImageDrawable(extension.icon) holder.extensionIconImageView.setImageDrawable(extension.icon)
} }
if (extension.hasUpdate) { if (extension.hasUpdate) {
holder.closeTextView.setImageResource(R.drawable.ic_round_sync_24) holder.updateView.isVisible = true
} else { } else {
holder.closeTextView.setImageResource(R.drawable.ic_round_delete_24) holder.updateView.isVisible = false
} }
holder.closeTextView.setOnClickListener { holder.deleteView.setOnClickListener {
onUninstallClicked(extension, false) onUninstallClicked(extension)
}
holder.updateView.setOnClickListener {
onUpdateClicked(extension)
} }
holder.settingsImageView.setOnClickListener { holder.settingsImageView.setOnClickListener {
onSettingsClicked(extension) onSettingsClicked(extension)
} }
holder.closeTextView.setOnLongClickListener {
onUninstallClicked(extension, true)
true
}
} }
fun filter(query: String, currentList: List<AnimeExtension.Installed>) { fun filter(query: String, currentList: List<AnimeExtension.Installed>) {
@ -337,7 +330,8 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
view.findViewById(R.id.extensionVersionTextView) view.findViewById(R.id.extensionVersionTextView)
val settingsImageView: ImageView = view.findViewById(R.id.settingsImageView) val settingsImageView: ImageView = view.findViewById(R.id.settingsImageView)
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView) val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
val closeTextView: ImageView = view.findViewById(R.id.closeTextView) val deleteView: ImageView = view.findViewById(R.id.deleteTextView)
val updateView: ImageView = view.findViewById(R.id.updateTextView)
} }
companion object { companion object {

View file

@ -1,8 +1,6 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
@ -28,6 +26,7 @@ import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.databinding.FragmentExtensionsBinding import ani.dantotsu.databinding.FragmentExtensionsBinding
import ani.dantotsu.others.LanguageMapper import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.others.LanguageMapper.Companion.getLanguageName
import ani.dantotsu.parsers.MangaSources import ani.dantotsu.parsers.MangaSources
import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
@ -45,7 +44,6 @@ import kotlinx.coroutines.launch
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Collections
import java.util.Locale import java.util.Locale
class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler { class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
@ -120,15 +118,20 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
.show() .show()
} }
}, },
{ pkg: MangaExtension.Installed, forceDelete: Boolean -> { pkg: MangaExtension.Installed ->
if (isAdded) { // Check if the fragment is currently added to its activity if (isAdded) {
val context = requireContext() // Store context in a variable mangaExtensionManager.uninstallExtension(pkg.pkgName)
snackString("Extension uninstalled")
}
}, { pkg ->
if (isAdded) {
val context = requireContext()
val notificationManager = val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (pkg.hasUpdate && !forceDelete) { if (pkg.hasUpdate) {
mangaExtensionManager.updateExtension(pkg) mangaExtensionManager.updateExtension(pkg)
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
{ installStep -> { installStep ->
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(
@ -143,7 +146,7 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
}, },
{ error -> { error ->
Injekt.get<CrashlyticsInterface>().logException(error) Injekt.get<CrashlyticsInterface>().logException(error)
Logger.log(error) // Log the error Logger.log(error)
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(
context, context,
Notifications.CHANNEL_DOWNLOADER_ERROR Notifications.CHANNEL_DOWNLOADER_ERROR
@ -160,7 +163,7 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
context, context,
Notifications.CHANNEL_DOWNLOADER_PROGRESS Notifications.CHANNEL_DOWNLOADER_PROGRESS
) )
.setSmallIcon(R.drawable.ic_check) .setSmallIcon(R.drawable.ic_circle_check)
.setContentTitle("Update complete") .setContentTitle("Update complete")
.setContentText("The extension has been successfully updated.") .setContentText("The extension has been successfully updated.")
.setPriority(NotificationCompat.PRIORITY_LOW) .setPriority(NotificationCompat.PRIORITY_LOW)
@ -169,9 +172,9 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
} }
) )
} else { } else {
mangaExtensionManager.uninstallExtension(pkg.pkgName) snackString("No update available")
snackString("Extension uninstalled")
} }
} }
}, skipIcons }, skipIcons
) )
@ -195,17 +198,10 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder target: RecyclerView.ViewHolder
): Boolean { ): Boolean {
val newList = extensionsAdapter.currentList.toMutableList()
val fromPosition = viewHolder.absoluteAdapterPosition val fromPosition = viewHolder.absoluteAdapterPosition
val toPosition = target.absoluteAdapterPosition val toPosition = target.absoluteAdapterPosition
if (fromPosition < toPosition) { //probably need to switch to a recyclerview adapter val newList = extensionsAdapter.currentList.toMutableList().apply {
for (i in fromPosition until toPosition) { add(toPosition, removeAt(fromPosition))
Collections.swap(newList, i, i + 1)
}
} else {
for (i in fromPosition downTo toPosition + 1) {
Collections.swap(newList, i, i - 1)
}
} }
extensionsAdapter.submitList(newList) extensionsAdapter.submitList(newList)
return true return true
@ -266,7 +262,8 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
private class MangaExtensionsAdapter( private class MangaExtensionsAdapter(
private val onSettingsClicked: (MangaExtension.Installed) -> Unit, private val onSettingsClicked: (MangaExtension.Installed) -> Unit,
private val onUninstallClicked: (MangaExtension.Installed, Boolean) -> Unit, private val onUninstallClicked: (MangaExtension.Installed) -> Unit,
private val onUpdateClicked: (MangaExtension.Installed) -> Unit,
val skipIcons: Boolean val skipIcons: Boolean
) : ListAdapter<MangaExtension.Installed, MangaExtensionsAdapter.ViewHolder>( ) : ListAdapter<MangaExtension.Installed, MangaExtensionsAdapter.ViewHolder>(
DIFF_CALLBACK_INSTALLED DIFF_CALLBACK_INSTALLED
@ -276,24 +273,23 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
submitList(newExtensions) submitList(newExtensions)
} }
fun updatePref() {
val map = currentList.map { it.name }
PrefManager.setVal(PrefName.MangaSourcesOrder, map)
MangaSources.pinnedMangaSources = map
MangaSources.performReorderMangaSources()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context) val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_extension, parent, false) .inflate(R.layout.item_extension, parent, false)
return ViewHolder(view) return ViewHolder(view)
} }
fun updatePref() {
val map = currentList.map { it.name }.toList()
PrefManager.setVal(PrefName.MangaSourcesOrder, map)
MangaSources.pinnedMangaSources = map
MangaSources.performReorderMangaSources()
}
@SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val extension = getItem(position) // Use getItem() from ListAdapter val extension = getItem(position)
val nsfw = if (extension.isNsfw) "(18+)" else "" val nsfw = if (extension.isNsfw) "(18+)" else ""
val lang = LanguageMapper.getLanguageName(extension.lang) val lang = getLanguageName(extension.lang)
holder.extensionNameTextView.text = extension.name holder.extensionNameTextView.text = extension.name
val versionText = "$lang ${extension.versionName} $nsfw" val versionText = "$lang ${extension.versionName} $nsfw"
holder.extensionVersionTextView.text = versionText holder.extensionVersionTextView.text = versionText
@ -301,12 +297,15 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
holder.extensionIconImageView.setImageDrawable(extension.icon) holder.extensionIconImageView.setImageDrawable(extension.icon)
} }
if (extension.hasUpdate) { if (extension.hasUpdate) {
holder.closeTextView.setImageResource(R.drawable.ic_round_sync_24) holder.updateView.isVisible = true
} else { } else {
holder.closeTextView.setImageResource(R.drawable.ic_round_delete_24) holder.updateView.isVisible = false
} }
holder.closeTextView.setOnClickListener { holder.deleteView.setOnClickListener {
onUninstallClicked(extension, false) onUninstallClicked(extension)
}
holder.updateView.setOnClickListener {
onUpdateClicked(extension)
} }
holder.settingsImageView.setOnClickListener { holder.settingsImageView.setOnClickListener {
onSettingsClicked(extension) onSettingsClicked(extension)
@ -330,7 +329,8 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
view.findViewById(R.id.extensionVersionTextView) view.findViewById(R.id.extensionVersionTextView)
val settingsImageView: ImageView = view.findViewById(R.id.settingsImageView) val settingsImageView: ImageView = view.findViewById(R.id.settingsImageView)
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView) val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
val closeTextView: ImageView = view.findViewById(R.id.closeTextView) val deleteView: ImageView = view.findViewById(R.id.deleteTextView)
val updateView: ImageView = view.findViewById(R.id.updateTextView)
} }
companion object { companion object {

View file

@ -10,6 +10,7 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
@ -19,7 +20,6 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.currContext
import ani.dantotsu.databinding.FragmentNovelExtensionsBinding import ani.dantotsu.databinding.FragmentNovelExtensionsBinding
import ani.dantotsu.others.LanguageMapper import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.NovelSources import ani.dantotsu.parsers.NovelSources
@ -34,7 +34,6 @@ import kotlinx.coroutines.launch
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Collections
import java.util.Locale import java.util.Locale
class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler { class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
@ -48,15 +47,21 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT) Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT)
.show() .show()
}, },
{ pkg, forceDelete -> { pkg ->
if (isAdded) { // Check if the fragment is currently added to its activity if (isAdded) {
val context = requireContext() // Store context in a variable novelExtensionManager.uninstallExtension(pkg.pkgName)
val notificationManager = snackString("Extension uninstalled")
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once
if (pkg.hasUpdate && !forceDelete) { }
},
{ pkg ->
if (isAdded) {
val context = requireContext()
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (pkg.hasUpdate) {
novelExtensionManager.updateExtension(pkg) novelExtensionManager.updateExtension(pkg)
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
{ installStep -> { installStep ->
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(
@ -71,7 +76,7 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
}, },
{ error -> { error ->
Injekt.get<CrashlyticsInterface>().logException(error) Injekt.get<CrashlyticsInterface>().logException(error)
Logger.log(error) // Log the error Logger.log(error)
val builder = NotificationCompat.Builder( val builder = NotificationCompat.Builder(
context, context,
Notifications.CHANNEL_DOWNLOADER_ERROR Notifications.CHANNEL_DOWNLOADER_ERROR
@ -97,8 +102,7 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
} }
) )
} else { } else {
novelExtensionManager.uninstallExtension(pkg.pkgName, currContext() ?: context) snackString("No update available")
snackString("Extension uninstalled")
} }
} }
}, skipIcons }, skipIcons
@ -123,17 +127,10 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder target: RecyclerView.ViewHolder
): Boolean { ): Boolean {
val newList = extensionsAdapter.currentList.toMutableList()
val fromPosition = viewHolder.absoluteAdapterPosition val fromPosition = viewHolder.absoluteAdapterPosition
val toPosition = target.absoluteAdapterPosition val toPosition = target.absoluteAdapterPosition
if (fromPosition < toPosition) { //probably need to switch to a recyclerview adapter val newList = extensionsAdapter.currentList.toMutableList().apply {
for (i in fromPosition until toPosition) { add(toPosition, removeAt(fromPosition))
Collections.swap(newList, i, i + 1)
}
} else {
for (i in fromPosition downTo toPosition + 1) {
Collections.swap(newList, i, i - 1)
}
} }
extensionsAdapter.submitList(newList) extensionsAdapter.submitList(newList)
return true return true
@ -195,7 +192,8 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
private class NovelExtensionsAdapter( private class NovelExtensionsAdapter(
private val onSettingsClicked: (NovelExtension.Installed) -> Unit, private val onSettingsClicked: (NovelExtension.Installed) -> Unit,
private val onUninstallClicked: (NovelExtension.Installed, Boolean) -> Unit, private val onUninstallClicked: (NovelExtension.Installed) -> Unit,
private val onUpdateClicked: (NovelExtension.Installed) -> Unit,
val skipIcons: Boolean val skipIcons: Boolean
) : ListAdapter<NovelExtension.Installed, NovelExtensionsAdapter.ViewHolder>( ) : ListAdapter<NovelExtension.Installed, NovelExtensionsAdapter.ViewHolder>(
DIFF_CALLBACK_INSTALLED DIFF_CALLBACK_INSTALLED
@ -230,20 +228,19 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
holder.extensionIconImageView.setImageDrawable(extension.icon) holder.extensionIconImageView.setImageDrawable(extension.icon)
} }
if (extension.hasUpdate) { if (extension.hasUpdate) {
holder.closeTextView.setImageResource(R.drawable.ic_round_sync_24) holder.updateView.isVisible = true
} else { } else {
holder.closeTextView.setImageResource(R.drawable.ic_round_delete_24) holder.updateView.isVisible = false
} }
holder.closeTextView.setOnClickListener { holder.deleteView.setOnClickListener {
onUninstallClicked(extension, false) onUninstallClicked(extension)
}
holder.updateView.setOnClickListener {
onUpdateClicked(extension)
} }
holder.settingsImageView.setOnClickListener { holder.settingsImageView.setOnClickListener {
onSettingsClicked(extension) onSettingsClicked(extension)
} }
holder.closeTextView.setOnLongClickListener {
onUninstallClicked(extension, true)
true
}
} }
fun filter(query: String, currentList: List<NovelExtension.Installed>) { fun filter(query: String, currentList: List<NovelExtension.Installed>) {
@ -263,7 +260,8 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
view.findViewById(R.id.extensionVersionTextView) view.findViewById(R.id.extensionVersionTextView)
val settingsImageView: ImageView = view.findViewById(R.id.settingsImageView) val settingsImageView: ImageView = view.findViewById(R.id.settingsImageView)
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView) val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
val closeTextView: ImageView = view.findViewById(R.id.closeTextView) val deleteView: ImageView = view.findViewById(R.id.deleteTextView)
val updateView: ImageView = view.findViewById(R.id.updateTextView)
} }
companion object { companion object {

View file

@ -10,6 +10,8 @@ import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.BuildConfig import ani.dantotsu.BuildConfig
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.buildMarkwon
import ani.dantotsu.client
import ani.dantotsu.databinding.ActivitySettingsAboutBinding import ani.dantotsu.databinding.ActivitySettingsAboutBinding
import ani.dantotsu.initActivity import ani.dantotsu.initActivity
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
@ -20,6 +22,9 @@ import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.util.Logger import ani.dantotsu.util.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class SettingsAboutActivity : AppCompatActivity() { class SettingsAboutActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsAboutBinding private lateinit var binding: ActivitySettingsAboutBinding
@ -130,6 +135,48 @@ class SettingsAboutActivity : AppCompatActivity() {
} }
} }
), ),
Settings(
type = 1,
name = getString(R.string.privacy_policy),
desc = getString(R.string.privacy_policy_desc),
icon = R.drawable.ic_incognito_24,
onClick = {
val text = TextView(context)
val pPLink = "https://raw.githubusercontent.com/rebelonion/Dantotsu/main/privacy_policy.md"
val backup = "https://gcore.jsdelivr.net/gh/rebelonion/dantotsu/privacy_policy.md"
text.text = getString(R.string.loading)
val markWon = try {
buildMarkwon(this@SettingsAboutActivity, false)
} catch (e: IllegalArgumentException) {
return@Settings
}
CoroutineScope(Dispatchers.IO).launch {
val res = try {
val out = client.get(pPLink)
if (out.code != 200) {
client.get(backup)
} else {
out
}.text
} catch (e: Exception) {
getString(R.string.failed_to_load)
}
runOnUiThread {
markWon.setMarkdown(text, res)
}
}
CustomBottomDialog.newInstance().apply {
setTitleText(context.getString(R.string.privacy_policy))
addView(text)
setNegativeButton(context.getString(R.string.close)) {
dismiss()
}
show(supportFragmentManager, "dialog")
}
}
),
) )
) )
binding.settingsRecyclerView.layoutManager = binding.settingsRecyclerView.layoutManager =

View file

@ -48,7 +48,8 @@ class SubscriptionSource(
binding.extensionPinImageView.visibility = View.GONE binding.extensionPinImageView.visibility = View.GONE
binding.extensionVersionTextView.visibility = View.GONE binding.extensionVersionTextView.visibility = View.GONE
binding.closeTextView.visibility = View.GONE binding.deleteTextView.visibility = View.GONE
binding.updateTextView.visibility = View.GONE
binding.settingsImageView.visibility = View.GONE binding.settingsImageView.visibility = View.GONE
} }

View file

@ -52,7 +52,7 @@ internal class ExtensionGithubApi {
sources = it.sources?.toAnimeExtensionSources().orEmpty(), sources = it.sources?.toAnimeExtensionSources().orEmpty(),
apkName = it.apk, apkName = it.apk,
repository = repository, repository = repository,
iconUrl = "${repository}/icon/${it.pkg}.png", iconUrl = "${repository.removeSuffix("/index.min.json")}/icon/${it.pkg}.png",
) )
} }
} }
@ -135,7 +135,7 @@ internal class ExtensionGithubApi {
sources = it.sources?.toMangaExtensionSources().orEmpty(), sources = it.sources?.toMangaExtensionSources().orEmpty(),
apkName = it.apk, apkName = it.apk,
repository = repository, repository = repository,
iconUrl = "${repository}/icon/${it.pkg}.png", iconUrl = "${repository.removeSuffix("/index.min.json")}/icon/${it.pkg}.png",
) )
} }
} }

View file

@ -73,11 +73,23 @@
tools:ignore="ContentDescription"/> tools:ignore="ContentDescription"/>
<ImageView <ImageView
android:id="@+id/closeTextView" android:id="@+id/updateTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_weight="0" android:layout_weight="0"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_round_sync_24"
app:tint="?attr/colorOnBackground"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/deleteTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_round_delete_24" android:src="@drawable/ic_round_delete_24"
app:tint="?attr/colorOnBackground" app:tint="?attr/colorOnBackground"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />

View file

@ -1091,5 +1091,9 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="add_repository">Add Repository</string> <string name="add_repository">Add Repository</string>
<string name="add_repository_desc">A repository link should look like this: https://raw.githubusercontent.com/username/repo/branch/index.min.json</string> <string name="add_repository_desc">A repository link should look like this: https://raw.githubusercontent.com/username/repo/branch/index.min.json</string>
<string name="current_repositories">Current Repositories</string> <string name="current_repositories">Current Repositories</string>
<string name="add_repository_warning">Warning: Extensions from the repository can run arbitrary code on your device. Only use repositories you trust. \n\nBy adding a repository, you agree to: \n\n1. Not use the app for viewing or distributing copyrighted content. \n2. Not use the app for any illegal activities. \n3. Not use the app for any activities that violate the terms of service of the content providers. \n\nThe app or it\'s maintainer are not affiliated in any way with extension providers. The developers are not responsible for any damages caused by the app. \n\nBy adding a repository, you agree to these terms.</string>
<string name="privacy_policy">Privacy Policy</string>
<string name="privacy_policy_desc">Read our privacy policy</string>
<string name="failed_to_load">Failed to load</string>
</resources> </resources>