mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Replace material-dialogs usage with Material Components' (#5423)
* Use Material Components' dialogs For all dialogs that has direct replacement. * Convert text input dialogs * Convert quad-state multi choices dialogs * Convert date picker dialogs This also changes the flow to remove selected start/finish tracking date and the track item itself * Remove material-dialogs dependencies
This commit is contained in:
		| @@ -2,9 +2,6 @@ package eu.kanade.tachiyomi.data.track.anilist | ||||
|  | ||||
| import android.net.Uri | ||||
| import androidx.core.net.toUri | ||||
| import com.afollestad.date.dayOfMonth | ||||
| import com.afollestad.date.month | ||||
| import com.afollestad.date.year | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.model.TrackSearch | ||||
| import eu.kanade.tachiyomi.network.POST | ||||
| @@ -315,9 +312,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { | ||||
|         val calendar = Calendar.getInstance() | ||||
|         calendar.timeInMillis = dateValue | ||||
|         return buildJsonObject { | ||||
|             put("year", calendar.year) | ||||
|             put("month", calendar.month + 1) | ||||
|             put("day", calendar.dayOfMonth) | ||||
|             put("year", calendar.get(Calendar.YEAR)) | ||||
|             put("month", calendar.get(Calendar.MONTH) + 1) | ||||
|             put("day", calendar.get(Calendar.DAY_OF_MONTH)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.browse.extension | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
|  | ||||
| @@ -21,15 +21,16 @@ class ExtensionTrustDialog<T>(bundle: Bundle? = null) : DialogController(bundle) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.untrusted_extension) | ||||
|             .message(R.string.untrusted_extension_message) | ||||
|             .positiveButton(R.string.ext_trust) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.untrusted_extension) | ||||
|             .setMessage(R.string.untrusted_extension_message) | ||||
|             .setPositiveButton(R.string.ext_trust) { _, _ -> | ||||
|                 (targetController as? Listener)?.trustSignature(args.getString(SIGNATURE_KEY)!!) | ||||
|             } | ||||
|             .negativeButton(R.string.ext_uninstall) { | ||||
|             .setNegativeButton(R.string.ext_uninstall) { _, _ -> | ||||
|                 (targetController as? Listener)?.uninstallExtension(args.getString(PKGNAME_KEY)!!) | ||||
|             } | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     private companion object { | ||||
|   | ||||
| @@ -3,10 +3,9 @@ package eu.kanade.tachiyomi.ui.browse.migration.search | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.view.isVisible | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsMultiChoice | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.bluelinelabs.conductor.RouterTransaction | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| @@ -89,26 +88,26 @@ class SearchController( | ||||
|         @Suppress("DEPRECATION") | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             val prefValue = preferences.migrateFlags().get() | ||||
|             val enabledFlagsPositions = MigrationFlags.getEnabledFlagsPositions(prefValue) | ||||
|             val items = MigrationFlags.titles | ||||
|                 .map { resources?.getString(it) } | ||||
|                 .toTypedArray() | ||||
|             val selected = items | ||||
|                 .mapIndexed { i, _ -> enabledFlagsPositions.contains(i) } | ||||
|                 .toBooleanArray() | ||||
|  | ||||
|             val preselected = | ||||
|                 MigrationFlags.getEnabledFlagsPositions( | ||||
|                     prefValue | ||||
|                 ) | ||||
|  | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .title(R.string.migration_dialog_what_to_include) | ||||
|                 .listItemsMultiChoice( | ||||
|                     items = MigrationFlags.titles.map { resources?.getString(it) as CharSequence }, | ||||
|                     initialSelection = preselected.toIntArray() | ||||
|                 ) { _, positions, _ -> | ||||
|                     // Save current settings for the next time | ||||
|                     val newValue = | ||||
|                         MigrationFlags.getFlagsFromPositions( | ||||
|                             positions.toTypedArray() | ||||
|                         ) | ||||
|                     preferences.migrateFlags().set(newValue) | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setTitle(R.string.migration_dialog_what_to_include) | ||||
|                 .setMultiChoiceItems(items, selected) { _, which, checked -> | ||||
|                     selected[which] = checked | ||||
|                 } | ||||
|                 .positiveButton(R.string.migrate) { | ||||
|                 .setPositiveButton(R.string.migrate) { _, _ -> | ||||
|                     // Save current settings for the next time | ||||
|                     val selectedIndices = mutableListOf<Int>() | ||||
|                     selected.forEachIndexed { i, b -> if (b) selectedIndices.add(i) } | ||||
|                     val newValue = MigrationFlags.getFlagsFromPositions(selectedIndices.toTypedArray()) | ||||
|                     preferences.migrateFlags().set(newValue) | ||||
|  | ||||
|                     if (callingController != null) { | ||||
|                         if (callingController.javaClass == SourceSearchController::class.java) { | ||||
|                             router.popController(callingController) | ||||
| @@ -116,7 +115,7 @@ class SearchController( | ||||
|                     } | ||||
|                     (targetController as? SearchController)?.migrateManga(manga, newManga) | ||||
|                 } | ||||
|                 .negativeButton(R.string.copy) { | ||||
|                 .setNegativeButton(R.string.copy) { _, _, -> | ||||
|                     if (callingController != null) { | ||||
|                         if (callingController.javaClass == SourceSearchController::class.java) { | ||||
|                             router.popController(callingController) | ||||
| @@ -124,7 +123,8 @@ class SearchController( | ||||
|                     } | ||||
|                     (targetController as? SearchController)?.copyManga(manga, newManga) | ||||
|                 } | ||||
|                 .neutralButton(android.R.string.cancel) | ||||
|                 .setNeutralButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -9,10 +9,9 @@ import android.view.MenuInflater | ||||
| import android.view.MenuItem | ||||
| import android.view.View | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItems | ||||
| import com.bluelinelabs.conductor.ControllerChangeHandler | ||||
| import com.bluelinelabs.conductor.ControllerChangeType | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.davidea.flexibleadapter.items.IFlexible | ||||
| @@ -238,15 +237,13 @@ class SourceController : | ||||
|         } | ||||
|  | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .title(text = source) | ||||
|                 .listItems( | ||||
|                     items = items.map { it.first }, | ||||
|                     waitForPositiveButton = false | ||||
|                 ) { dialog, which, _ -> | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setTitle(source) | ||||
|                 .setItems(items.map { it.first }.toTypedArray()) { dialog, which -> | ||||
|                     items[which].second() | ||||
|                     dialog.dismiss() | ||||
|                 } | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -13,8 +13,7 @@ import androidx.core.view.updatePadding | ||||
| import androidx.recyclerview.widget.GridLayoutManager | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItems | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton | ||||
| import com.google.android.material.snackbar.Snackbar | ||||
| import com.tfcporciuncula.flow.Preference | ||||
| @@ -589,11 +588,9 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|         val manga = (adapter?.getItem(position) as? SourceItem?)?.manga ?: return | ||||
|  | ||||
|         if (manga.favorite) { | ||||
|             MaterialDialog(activity) | ||||
|                 .listItems( | ||||
|                     items = listOf(activity.getString(R.string.remove_from_library)), | ||||
|                     waitForPositiveButton = false | ||||
|                 ) { _, which, _ -> | ||||
|             MaterialAlertDialogBuilder(activity) | ||||
|                 .setTitle(manga.title) | ||||
|                 .setItems(arrayOf(activity.getString(R.string.remove_from_library))) { _, which -> | ||||
|                     when (which) { | ||||
|                         0 -> { | ||||
|                             presenter.changeMangaFavorite(manga) | ||||
|   | ||||
| @@ -2,11 +2,11 @@ package eu.kanade.tachiyomi.ui.category | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.input.input | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput | ||||
|  | ||||
| /** | ||||
|  * Dialog to create a new category for the library. | ||||
| @@ -30,18 +30,16 @@ class CategoryCreateDialog<T>(bundle: Bundle? = null) : DialogController(bundle) | ||||
|      * @return a new dialog instance. | ||||
|      */ | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.action_add_category) | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .input( | ||||
|                 hint = resources?.getString(R.string.name), | ||||
|                 prefill = currentName | ||||
|             ) { _, input -> | ||||
|                 currentName = input.toString() | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.action_add_category) | ||||
|             .setTextInput(prefill = currentName) { | ||||
|                 currentName = it | ||||
|             } | ||||
|             .positiveButton(android.R.string.ok) { | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 (targetController as? Listener)?.createCategory(currentName) | ||||
|             } | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.ui.category | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.input.input | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput | ||||
|  | ||||
| /** | ||||
|  * Dialog to rename an existing category of the library. | ||||
| @@ -35,16 +35,14 @@ class CategoryRenameDialog<T>(bundle: Bundle? = null) : DialogController(bundle) | ||||
|      * @return a new dialog instance. | ||||
|      */ | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.action_rename_category) | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .input( | ||||
|                 hint = resources?.getString(R.string.name), | ||||
|                 prefill = currentName | ||||
|             ) { _, input -> | ||||
|                 currentName = input.toString() | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.action_rename_category) | ||||
|             .setTextInput(prefill = currentName) { | ||||
|                 currentName = it | ||||
|             } | ||||
|             .positiveButton(android.R.string.ok) { onPositive() } | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> onPositive() } | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.library | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsMultiChoice | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| @@ -32,32 +31,34 @@ class ChangeMangaCategoriesDialog<T>(bundle: Bundle? = null) : | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.action_move_category) | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.action_move_category) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .apply { | ||||
|                 if (categories.isNotEmpty()) { | ||||
|                     listItemsMultiChoice( | ||||
|                         items = categories.map { it.name }, | ||||
|                         initialSelection = preselected.toIntArray(), | ||||
|                         allowEmptySelection = true | ||||
|                     ) { _, selections, _ -> | ||||
|                         val newCategories = selections.map { categories[it] } | ||||
|                     val selected = categories | ||||
|                         .mapIndexed { i, _ -> preselected.contains(i) } | ||||
|                         .toBooleanArray() | ||||
|                     setMultiChoiceItems(categories.map { it.name }.toTypedArray(), selected) { _, which, checked -> | ||||
|                         selected[which] = checked | ||||
|                     } | ||||
|                     setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                         val newCategories = categories.filterIndexed { i, _ -> selected[i] } | ||||
|                         (targetController as? Listener)?.updateCategoriesForMangas(mangas, newCategories) | ||||
|                     } | ||||
|                         .positiveButton(android.R.string.ok) | ||||
|                 } else { | ||||
|                     message(R.string.information_empty_category_dialog) | ||||
|                         .positiveButton(R.string.action_edit_categories) { | ||||
|                             if (targetController is LibraryController) { | ||||
|                                 val libController = targetController as LibraryController | ||||
|                                 libController.clearSelection() | ||||
|                             } | ||||
|                             router.popCurrentController() | ||||
|                             router.pushController(CategoryController().withFadeTransaction()) | ||||
|                     setMessage(R.string.information_empty_category_dialog) | ||||
|                     setPositiveButton(R.string.action_edit_categories) { _, _ -> | ||||
|                         if (targetController is LibraryController) { | ||||
|                             val libController = targetController as LibraryController | ||||
|                             libController.clearSelection() | ||||
|                         } | ||||
|                         router.popCurrentController() | ||||
|                         router.pushController(CategoryController().withFadeTransaction()) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.library | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| @@ -20,15 +20,16 @@ class ChangeMangaCoverDialog<T>(bundle: Bundle? = null) : | ||||
|  | ||||
|     @Suppress("DEPRECATION") | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.action_edit_cover) | ||||
|             .positiveButton(R.string.action_edit) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.action_edit_cover) | ||||
|             .setPositiveButton(R.string.action_edit) { _, _ -> | ||||
|                 (targetController as? Listener)?.openMangaCoverPicker(manga) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .neutralButton(R.string.action_delete) { | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .setNeutralButton(R.string.action_delete) { _, _ -> | ||||
|                 (targetController as? Listener)?.deleteMangaCover(manga) | ||||
|             } | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.library | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsMultiChoice | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| @@ -20,18 +19,22 @@ class DeleteLibraryMangasDialog<T>(bundle: Bundle? = null) : | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.action_remove) | ||||
|             .listItemsMultiChoice( | ||||
|                 R.array.delete_selected_mangas, | ||||
|                 initialSelection = intArrayOf(0) | ||||
|             ) { _, selections, _ -> | ||||
|                 val deleteFromLibrary = 0 in selections | ||||
|                 val deleteChapters = 1 in selections | ||||
|         val items = resources!!.getStringArray(R.array.delete_selected_mangas) | ||||
|         val selected = items | ||||
|             .mapIndexed { i, _ -> i == 0 } | ||||
|             .toBooleanArray() | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.action_remove) | ||||
|             .setMultiChoiceItems(items, selected) { _, which, checked -> | ||||
|                 selected[which] = checked | ||||
|             } | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 val deleteFromLibrary = selected[0] | ||||
|                 val deleteChapters = selected[1] | ||||
|                 (targetController as? Listener)?.deleteMangas(mangas, deleteFromLibrary, deleteChapters) | ||||
|             } | ||||
|             .positiveButton(android.R.string.ok) | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.main | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| @@ -12,11 +12,12 @@ class WhatsNewDialogController(bundle: Bundle? = null) : DialogController(bundle | ||||
|  | ||||
|     @Suppress("DEPRECATION") | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(text = activity!!.getString(R.string.updated_version, BuildConfig.VERSION_NAME)) | ||||
|             .positiveButton(android.R.string.ok) | ||||
|             .neutralButton(R.string.whats_new) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(activity!!.getString(R.string.updated_version, BuildConfig.VERSION_NAME)) | ||||
|             .setPositiveButton(android.R.string.ok, null) | ||||
|             .setNeutralButton(R.string.whats_new) { _, _ -> | ||||
|                 openInBrowser("https://github.com/tachiyomiorg/tachiyomi/releases/tag/v${BuildConfig.VERSION_NAME}") | ||||
|             } | ||||
|             .create() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -289,7 +289,7 @@ class MangaController : | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         trackSheet = TrackSheet(this, manga!!) | ||||
|         trackSheet = TrackSheet(this, manga!!, (activity as MainActivity).supportFragmentManager) | ||||
|  | ||||
|         updateFilterIconState() | ||||
|     } | ||||
|   | ||||
| @@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.manga.chapter | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
|  | ||||
| @@ -15,12 +15,13 @@ class DeleteChaptersDialog<T>(bundle: Bundle? = null) : DialogController(bundle) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .message(R.string.confirm_delete_chapters) | ||||
|             .positiveButton(android.R.string.ok) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setMessage(R.string.confirm_delete_chapters) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 (targetController as? Listener)?.deleteChapters() | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -3,9 +3,8 @@ package eu.kanade.tachiyomi.ui.manga.chapter | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.widget.DialogCustomDownloadView | ||||
| @@ -57,13 +56,14 @@ class DownloadCustomChaptersDialog<T> : DialogController | ||||
|  | ||||
|         // Build dialog. | ||||
|         // when positive dialog is pressed call custom listener. | ||||
|         return MaterialDialog(activity) | ||||
|             .title(R.string.custom_download) | ||||
|             .customView(view = view, scrollable = true) | ||||
|             .positiveButton(android.R.string.ok) { | ||||
|         return MaterialAlertDialogBuilder(activity) | ||||
|             .setTitle(R.string.custom_download) | ||||
|             .setView(view) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 (targetController as? Listener)?.downloadCustomChapters(view.amount) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -3,8 +3,7 @@ package eu.kanade.tachiyomi.ui.manga.chapter | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| @@ -24,13 +23,10 @@ class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle | ||||
|             setOptionDescription(R.string.also_set_chapter_settings_for_library) | ||||
|         } | ||||
|  | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.chapter_settings) | ||||
|             .customView( | ||||
|                 view = view, | ||||
|                 horizontalPadding = true | ||||
|             ) | ||||
|             .positiveButton(android.R.string.ok) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.chapter_settings) | ||||
|             .setView(view) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 ChapterSettingsHelper.setGlobalSettings(args.getSerializable(MANGA_KEY)!! as Manga) | ||||
|                 if (view.isChecked()) { | ||||
|                     ChapterSettingsHelper.updateAllMangasWithGlobalDefaults() | ||||
| @@ -38,7 +34,8 @@ class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle | ||||
|  | ||||
|                 activity?.toast(activity!!.getString(R.string.chapter_settings_updated)) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     private companion object { | ||||
|   | ||||
| @@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.manga.track | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import android.widget.NumberPicker | ||||
| import android.view.LayoutInflater | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.afollestad.materialdialogs.customview.getCustomView | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.databinding.TrackChaptersDialogBinding | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| @@ -38,23 +37,9 @@ class SetTrackChaptersDialog<T> : DialogController | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         val item = item | ||||
|         val pickerView = TrackChaptersDialogBinding.inflate(LayoutInflater.from(activity!!)) | ||||
|         val np = pickerView.chaptersPicker | ||||
|  | ||||
|         val dialog = MaterialDialog(activity!!) | ||||
|             .title(R.string.chapters) | ||||
|             .customView(R.layout.track_chapters_dialog, dialogWrapContent = false) | ||||
|             .positiveButton(android.R.string.ok) { dialog -> | ||||
|                 val view = dialog.getCustomView() | ||||
|                 // Remove focus to update selected number | ||||
|                 val np: NumberPicker = view.findViewById(R.id.chapters_picker) | ||||
|                 np.clearFocus() | ||||
|  | ||||
|                 listener.setChaptersRead(item, np.value) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|  | ||||
|         val view = dialog.getCustomView() | ||||
|         val np: NumberPicker = view.findViewById(R.id.chapters_picker) | ||||
|         // Set initial value | ||||
|         np.value = item.track?.last_chapter_read ?: 0 | ||||
|  | ||||
| @@ -66,7 +51,15 @@ class SetTrackChaptersDialog<T> : DialogController | ||||
|         // Don't allow to go from 0 to 9999 | ||||
|         np.wrapSelectorWheel = false | ||||
|  | ||||
|         return dialog | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.chapters) | ||||
|             .setView(pickerView.root) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 np.clearFocus() | ||||
|                 listener.setChaptersRead(item, np.value) | ||||
|             } | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -1,87 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.ui.manga.track | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.datetime.datePicker | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.util.Calendar | ||||
|  | ||||
| class SetTrackReadingDatesDialog<T> : DialogController | ||||
|         where T : Controller { | ||||
|  | ||||
|     private val item: TrackItem | ||||
|  | ||||
|     private val dateToUpdate: ReadingDate | ||||
|  | ||||
|     private lateinit var listener: Listener | ||||
|  | ||||
|     constructor(target: T, listener: Listener, dateToUpdate: ReadingDate, item: TrackItem) : super( | ||||
|         bundleOf(KEY_ITEM_TRACK to item.track) | ||||
|     ) { | ||||
|         targetController = target | ||||
|         this.listener = listener | ||||
|         this.item = item | ||||
|         this.dateToUpdate = dateToUpdate | ||||
|     } | ||||
|  | ||||
|     @Suppress("unused") | ||||
|     constructor(bundle: Bundle) : super(bundle) { | ||||
|         val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track | ||||
|         val service = Injekt.get<TrackManager>().getService(track.sync_id)!! | ||||
|         item = TrackItem(track, service) | ||||
|         dateToUpdate = ReadingDate.Start | ||||
|     } | ||||
|  | ||||
|     @Suppress("DEPRECATION") | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title( | ||||
|                 when (dateToUpdate) { | ||||
|                     ReadingDate.Start -> R.string.track_started_reading_date | ||||
|                     ReadingDate.Finish -> R.string.track_finished_reading_date | ||||
|                 } | ||||
|             ) | ||||
|             .datePicker(currentDate = getCurrentDate()) { _, date -> | ||||
|                 listener.setReadingDate(item, dateToUpdate, date.timeInMillis) | ||||
|             } | ||||
|             .neutralButton(R.string.action_remove) { | ||||
|                 listener.setReadingDate(item, dateToUpdate, 0L) | ||||
|             } | ||||
|     } | ||||
|  | ||||
|     private fun getCurrentDate(): Calendar { | ||||
|         // Today if no date is set, otherwise the already set date | ||||
|         return Calendar.getInstance().apply { | ||||
|             item.track?.let { | ||||
|                 val date = when (dateToUpdate) { | ||||
|                     ReadingDate.Start -> it.started_reading_date | ||||
|                     ReadingDate.Finish -> it.finished_reading_date | ||||
|                 } | ||||
|                 if (date != 0L) { | ||||
|                     timeInMillis = date | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|         fun setReadingDate(item: TrackItem, type: ReadingDate, date: Long) | ||||
|     } | ||||
|  | ||||
|     enum class ReadingDate { | ||||
|         Start, | ||||
|         Finish | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         private const val KEY_ITEM_TRACK = "SetTrackReadingDatesDialog.item.track" | ||||
|     } | ||||
| } | ||||
| @@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.manga.track | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import android.widget.NumberPicker | ||||
| import android.view.LayoutInflater | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.afollestad.materialdialogs.customview.getCustomView | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.databinding.TrackScoreDialogBinding | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| @@ -38,23 +37,9 @@ class SetTrackScoreDialog<T> : DialogController | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         val item = item | ||||
|         val pickerView = TrackScoreDialogBinding.inflate(LayoutInflater.from(activity!!)) | ||||
|         val np = pickerView.scorePicker | ||||
|  | ||||
|         val dialog = MaterialDialog(activity!!) | ||||
|             .title(R.string.score) | ||||
|             .customView(R.layout.track_score_dialog, dialogWrapContent = false) | ||||
|             .positiveButton(android.R.string.ok) { dialog -> | ||||
|                 val view = dialog.getCustomView() | ||||
|                 // Remove focus to update selected number | ||||
|                 val np: NumberPicker = view.findViewById(R.id.score_picker) | ||||
|                 np.clearFocus() | ||||
|  | ||||
|                 listener.setScore(item, np.value) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|  | ||||
|         val view = dialog.getCustomView() | ||||
|         val np: NumberPicker = view.findViewById(R.id.score_picker) | ||||
|         val scores = item.service.getScoreList().toTypedArray() | ||||
|         np.maxValue = scores.size - 1 | ||||
|         np.displayedValues = scores | ||||
| @@ -66,7 +51,15 @@ class SetTrackScoreDialog<T> : DialogController | ||||
|             np.value = if (index != -1) index else 0 | ||||
|         } | ||||
|  | ||||
|         return dialog | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.score) | ||||
|             .setView(pickerView.root) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 np.clearFocus() | ||||
|                 listener.setScore(item, np.value) | ||||
|             } | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -3,9 +3,8 @@ package eu.kanade.tachiyomi.ui.manga.track | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsSingleChoice | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| @@ -36,22 +35,20 @@ class SetTrackStatusDialog<T> : DialogController | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         val item = item | ||||
|         val statusList = item.service.getStatusList() | ||||
|         val statusString = statusList.map { item.service.getStatus(it) } | ||||
|         val selectedIndex = statusList.indexOf(item.track?.status) | ||||
|         var selectedIndex = statusList.indexOf(item.track?.status) | ||||
|  | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(R.string.status) | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .listItemsSingleChoice( | ||||
|                 items = statusString, | ||||
|                 initialSelection = selectedIndex, | ||||
|                 waitForPositiveButton = false | ||||
|             ) { dialog, position, _ -> | ||||
|                 listener.setStatus(item, position) | ||||
|                 dialog.dismiss() | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(R.string.status) | ||||
|             .setSingleChoiceItems(statusString.toTypedArray(), selectedIndex) { _, which -> | ||||
|                 selectedIndex = which | ||||
|             } | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 listener.setStatus(item, selectedIndex) | ||||
|             } | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import android.view.ViewGroup | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import eu.kanade.tachiyomi.databinding.TrackItemBinding | ||||
| import eu.kanade.tachiyomi.util.view.applyElevationOverlay | ||||
| import uy.kohesive.injekt.api.get | ||||
|  | ||||
| class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder>() { | ||||
|  | ||||
| @@ -40,13 +39,16 @@ class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder | ||||
|     } | ||||
|  | ||||
|     interface OnClickListener { | ||||
|         fun onLogoClick(position: Int) | ||||
|         fun onOpenInBrowserClick(position: Int) | ||||
|         fun onSetClick(position: Int) | ||||
|         fun onTitleLongClick(position: Int) | ||||
|         fun onStatusClick(position: Int) | ||||
|         fun onChaptersClick(position: Int) | ||||
|         fun onScoreClick(position: Int) | ||||
|         fun onStartDateClick(position: Int) | ||||
|         fun onFinishDateClick(position: Int) | ||||
|         fun onStartDateEditClick(position: Int) | ||||
|         fun onStartDateRemoveClick(position: Int) | ||||
|         fun onFinishDateEditClick(position: Int) | ||||
|         fun onFinishDateRemoveClick(position: Int) | ||||
|         fun onRemoveItemClick(position: Int) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.databinding.TrackItemBinding | ||||
| import eu.kanade.tachiyomi.util.view.popupMenu | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.text.DateFormat | ||||
|  | ||||
| @@ -17,10 +18,9 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) | ||||
|         preferences.dateFormat() | ||||
|     } | ||||
|  | ||||
|     init { | ||||
|         val listener = adapter.rowClickListener | ||||
|     private val listener = adapter.rowClickListener | ||||
|  | ||||
|         binding.logoContainer.setOnClickListener { listener.onLogoClick(bindingAdapterPosition) } | ||||
|     init { | ||||
|         binding.trackSet.setOnClickListener { listener.onSetClick(bindingAdapterPosition) } | ||||
|         binding.trackTitle.setOnClickListener { listener.onSetClick(bindingAdapterPosition) } | ||||
|         binding.trackTitle.setOnLongClickListener { | ||||
| @@ -30,8 +30,6 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) | ||||
|         binding.trackStatus.setOnClickListener { listener.onStatusClick(bindingAdapterPosition) } | ||||
|         binding.trackChapters.setOnClickListener { listener.onChaptersClick(bindingAdapterPosition) } | ||||
|         binding.trackScore.setOnClickListener { listener.onScoreClick(bindingAdapterPosition) } | ||||
|         binding.trackStartDate.setOnClickListener { listener.onStartDateClick(bindingAdapterPosition) } | ||||
|         binding.trackFinishDate.setOnClickListener { listener.onFinishDateClick(bindingAdapterPosition) } | ||||
|     } | ||||
|  | ||||
|     @SuppressLint("SetTextI18n") | ||||
| @@ -42,6 +40,7 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) | ||||
|  | ||||
|         binding.trackSet.isVisible = track == null | ||||
|         binding.trackTitle.isVisible = track != null | ||||
|         binding.more.isVisible = track != null | ||||
|  | ||||
|         binding.middleRow.isVisible = track != null | ||||
|         binding.bottomDivider.isVisible = track != null | ||||
| @@ -77,20 +76,55 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter) | ||||
|                 if (track.started_reading_date != 0L) { | ||||
|                     binding.trackStartDate.text = dateFormat.format(track.started_reading_date) | ||||
|                     binding.trackStartDate.alpha = SET_STATUS_TEXT_ALPHA | ||||
|                     binding.trackStartDate.setOnClickListener { | ||||
|                         it.popupMenu(R.menu.track_item_date) { | ||||
|                             when (itemId) { | ||||
|                                 R.id.action_edit -> listener.onStartDateEditClick(bindingAdapterPosition) | ||||
|                                 R.id.action_remove -> listener.onStartDateRemoveClick(bindingAdapterPosition) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     binding.trackStartDate.text = ctx.getString(R.string.track_started_reading_date) | ||||
|                     binding.trackStartDate.alpha = UNSET_STATUS_TEXT_ALPHA | ||||
|                     binding.trackStartDate.setOnClickListener { | ||||
|                         listener.onStartDateEditClick(bindingAdapterPosition) | ||||
|                     } | ||||
|                 } | ||||
|                 if (track.finished_reading_date != 0L) { | ||||
|                     binding.trackFinishDate.text = dateFormat.format(track.finished_reading_date) | ||||
|                     binding.trackFinishDate.alpha = SET_STATUS_TEXT_ALPHA | ||||
|                     binding.trackFinishDate.setOnClickListener { | ||||
|                         it.popupMenu(R.menu.track_item_date) { | ||||
|                             when (itemId) { | ||||
|                                 R.id.action_edit -> listener.onFinishDateEditClick(bindingAdapterPosition) | ||||
|                                 R.id.action_remove -> listener.onFinishDateRemoveClick(bindingAdapterPosition) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     binding.trackFinishDate.text = ctx.getString(R.string.track_finished_reading_date) | ||||
|                     binding.trackFinishDate.alpha = UNSET_STATUS_TEXT_ALPHA | ||||
|                     binding.trackFinishDate.setOnClickListener { | ||||
|                         listener.onFinishDateEditClick(bindingAdapterPosition) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             binding.bottomDivider.isVisible = supportsReadingDates | ||||
|             binding.bottomRow.isVisible = supportsReadingDates | ||||
|  | ||||
|             binding.more.setOnClickListener { | ||||
|                 it.popupMenu(R.menu.track_item) { | ||||
|                     when (itemId) { | ||||
|                         R.id.action_open_in_browser -> { | ||||
|                             listener.onOpenInBrowserClick(bindingAdapterPosition) | ||||
|                         } | ||||
|                         R.id.action_remove -> { | ||||
|                             listener.onRemoveItemClick(bindingAdapterPosition) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -74,14 +74,9 @@ class TrackSearchDialog : DialogController { | ||||
|                         dialog?.dismiss() | ||||
|                     } | ||||
|                 } | ||||
|                 R.id.remove -> { | ||||
|                     trackController.presenter.unregisterTracking(service) | ||||
|                     dialog?.dismiss() | ||||
|                 } | ||||
|             } | ||||
|             true | ||||
|         } | ||||
|         binding!!.toolbar.menu.findItem(R.id.remove).isVisible = currentTrackUrl != null | ||||
|  | ||||
|         // Create adapter | ||||
|         adapter = TrackSearchAdapter(currentTrackUrl) { which -> | ||||
|   | ||||
| @@ -3,9 +3,14 @@ package eu.kanade.tachiyomi.ui.manga.track | ||||
| import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import androidx.fragment.app.FragmentManager | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import com.google.android.material.bottomsheet.BottomSheetBehavior | ||||
| import eu.kanade.tachiyomi.R.string | ||||
| import com.google.android.material.datepicker.CalendarConstraints | ||||
| import com.google.android.material.datepicker.DateValidatorPointBackward | ||||
| import com.google.android.material.datepicker.DateValidatorPointForward | ||||
| import com.google.android.material.datepicker.MaterialDatePicker | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.track.UnattendedTrackService | ||||
| import eu.kanade.tachiyomi.databinding.TrackControllerBinding | ||||
| @@ -13,6 +18,7 @@ import eu.kanade.tachiyomi.source.SourceManager | ||||
| import eu.kanade.tachiyomi.ui.base.controller.openInBrowser | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.util.lang.launchIO | ||||
| import eu.kanade.tachiyomi.util.lang.toUtcCalendar | ||||
| import eu.kanade.tachiyomi.util.lang.withUIContext | ||||
| import eu.kanade.tachiyomi.util.system.copyToClipboard | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| @@ -23,13 +29,13 @@ import uy.kohesive.injekt.api.get | ||||
| class TrackSheet( | ||||
|     val controller: MangaController, | ||||
|     val manga: Manga, | ||||
|     val fragmentManager: FragmentManager, | ||||
|     private val sourceManager: SourceManager = Injekt.get() | ||||
| ) : BaseBottomSheetDialog(controller.activity!!), | ||||
|     TrackAdapter.OnClickListener, | ||||
|     SetTrackStatusDialog.Listener, | ||||
|     SetTrackChaptersDialog.Listener, | ||||
|     SetTrackScoreDialog.Listener, | ||||
|     SetTrackReadingDatesDialog.Listener { | ||||
|     SetTrackScoreDialog.Listener { | ||||
|  | ||||
|     private lateinit var binding: TrackControllerBinding | ||||
|  | ||||
| @@ -63,7 +69,7 @@ class TrackSheet( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onLogoClick(position: Int) { | ||||
|     override fun onOpenInBrowserClick(position: Int) { | ||||
|         val track = adapter.getItem(position)?.track ?: return | ||||
|  | ||||
|         if (track.tracking_url.isNotBlank()) { | ||||
| @@ -81,7 +87,7 @@ class TrackSheet( | ||||
|             } | ||||
|  | ||||
|             if (!item.service.accept(sourceManager.getOrStub(manga.source))) { | ||||
|                 controller.presenter.view?.applicationContext?.toast(string.source_unsupported) | ||||
|                 controller.presenter.view?.applicationContext?.toast(R.string.source_unsupported) | ||||
|                 return | ||||
|             } | ||||
|  | ||||
| @@ -90,9 +96,9 @@ class TrackSheet( | ||||
|                     item.service.match(manga)?.let { track -> | ||||
|                         controller.presenter.registerTracking(track, item.service) | ||||
|                     } | ||||
|                         ?: withUIContext { controller.presenter.view?.applicationContext?.toast(string.error_no_match) } | ||||
|                         ?: withUIContext { controller.presenter.view?.applicationContext?.toast(R.string.error_no_match) } | ||||
|                 } catch (e: Exception) { | ||||
|                     withUIContext { controller.presenter.view?.applicationContext?.toast(string.error_no_match) } | ||||
|                     withUIContext { controller.presenter.view?.applicationContext?.toast(R.string.error_no_match) } | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
| @@ -128,18 +134,74 @@ class TrackSheet( | ||||
|         SetTrackScoreDialog(controller, this, item).showDialog(controller.router) | ||||
|     } | ||||
|  | ||||
|     override fun onStartDateClick(position: Int) { | ||||
|     override fun onStartDateEditClick(position: Int) { | ||||
|         val item = adapter.getItem(position) ?: return | ||||
|         if (item.track == null) return | ||||
|  | ||||
|         SetTrackReadingDatesDialog(controller, this, SetTrackReadingDatesDialog.ReadingDate.Start, item).showDialog(controller.router) | ||||
|         val selection = item.track.started_reading_date.toUtcCalendar()?.timeInMillis | ||||
|             ?: MaterialDatePicker.todayInUtcMilliseconds() | ||||
|  | ||||
|         // No time travellers allowed | ||||
|         val constraints = CalendarConstraints.Builder().apply { | ||||
|             val finishedMillis = item.track.finished_reading_date.toUtcCalendar()?.timeInMillis | ||||
|             if (finishedMillis != null) { | ||||
|                 setValidator(DateValidatorPointBackward.before(finishedMillis)) | ||||
|             } | ||||
|         }.build() | ||||
|  | ||||
|         val picker = MaterialDatePicker.Builder.datePicker() | ||||
|             .setTitleText(R.string.track_started_reading_date) | ||||
|             .setSelection(selection) | ||||
|             .setCalendarConstraints(constraints) | ||||
|             .build() | ||||
|         picker.addOnPositiveButtonClickListener { | ||||
|             controller.presenter.setTrackerStartDate(item, it) | ||||
|         } | ||||
|         picker.show(fragmentManager, null) | ||||
|     } | ||||
|  | ||||
|     override fun onFinishDateClick(position: Int) { | ||||
|     override fun onFinishDateEditClick(position: Int) { | ||||
|         val item = adapter.getItem(position) ?: return | ||||
|         if (item.track == null) return | ||||
|  | ||||
|         SetTrackReadingDatesDialog(controller, this, SetTrackReadingDatesDialog.ReadingDate.Finish, item).showDialog(controller.router) | ||||
|         val selection = item.track.finished_reading_date.toUtcCalendar()?.timeInMillis | ||||
|             ?: MaterialDatePicker.todayInUtcMilliseconds() | ||||
|  | ||||
|         // No time travellers allowed | ||||
|         val constraints = CalendarConstraints.Builder().apply { | ||||
|             val startMillis = item.track.started_reading_date.toUtcCalendar()?.timeInMillis | ||||
|             if (startMillis != null) { | ||||
|                 setValidator(DateValidatorPointForward.from(item.track.started_reading_date)) | ||||
|             } | ||||
|         }.build() | ||||
|  | ||||
|         val picker = MaterialDatePicker.Builder.datePicker() | ||||
|             .setTitleText(R.string.track_finished_reading_date) | ||||
|             .setSelection(selection) | ||||
|             .setCalendarConstraints(constraints) | ||||
|             .build() | ||||
|         picker.addOnPositiveButtonClickListener { | ||||
|             controller.presenter.setTrackerFinishDate(item, it) | ||||
|         } | ||||
|         picker.show(fragmentManager, null) | ||||
|     } | ||||
|  | ||||
|     override fun onStartDateRemoveClick(position: Int) { | ||||
|         val item = adapter.getItem(position) ?: return | ||||
|         if (item.track == null) return | ||||
|         controller.presenter.setTrackerStartDate(item, 0) | ||||
|     } | ||||
|  | ||||
|     override fun onFinishDateRemoveClick(position: Int) { | ||||
|         val item = adapter.getItem(position) ?: return | ||||
|         if (item.track == null) return | ||||
|         controller.presenter.setTrackerFinishDate(item, 0) | ||||
|     } | ||||
|  | ||||
|     override fun onRemoveItemClick(position: Int) { | ||||
|         val item = adapter.getItem(position) ?: return | ||||
|         if (item.track == null) return | ||||
|         controller.presenter.unregisterTracking(item.service) | ||||
|     } | ||||
|  | ||||
|     override fun setStatus(item: TrackItem, selection: Int) { | ||||
| @@ -154,13 +216,6 @@ class TrackSheet( | ||||
|         controller.presenter.setTrackerScore(item, score) | ||||
|     } | ||||
|  | ||||
|     override fun setReadingDate(item: TrackItem, type: SetTrackReadingDatesDialog.ReadingDate, date: Long) { | ||||
|         when (type) { | ||||
|             SetTrackReadingDatesDialog.ReadingDate.Start -> controller.presenter.setTrackerStartDate(item, date) | ||||
|             SetTrackReadingDatesDialog.ReadingDate.Finish -> controller.presenter.setTrackerFinishDate(item, date) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun getSearchDialog(): TrackSearchDialog? { | ||||
|         return controller.router.getControllerWithTag(TAG_SEARCH_CONTROLLER) as? TrackSearchDialog | ||||
|     } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import androidx.preference.PreferenceScreen | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import com.mikepenz.aboutlibraries.LibsBuilder | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.R | ||||
| @@ -133,10 +133,10 @@ class AboutController : SettingsController(), NoToolbarElevationController { | ||||
|         ) | ||||
|  | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .title(res = R.string.update_check_notification_update_available) | ||||
|                 .message(text = args.getString(BODY_KEY) ?: "") | ||||
|                 .positiveButton(R.string.update_check_confirm) { | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setTitle(R.string.update_check_notification_update_available) | ||||
|                 .setMessage(args.getString(BODY_KEY) ?: "") | ||||
|                 .setPositiveButton(R.string.update_check_confirm) { _, _ -> | ||||
|                     val appContext = applicationContext | ||||
|                     if (appContext != null) { | ||||
|                         // Start download | ||||
| @@ -144,7 +144,8 @@ class AboutController : SettingsController(), NoToolbarElevationController { | ||||
|                         UpdaterService.start(appContext, url) | ||||
|                     } | ||||
|                 } | ||||
|                 .negativeButton(R.string.update_check_ignore) | ||||
|                 .setNegativeButton(R.string.update_check_ignore, null) | ||||
|                 .create() | ||||
|         } | ||||
|  | ||||
|         private companion object { | ||||
|   | ||||
| @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.reader | ||||
|  | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.databinding.ReaderPageSheetBinding | ||||
| import eu.kanade.tachiyomi.source.model.Page | ||||
| @@ -35,13 +35,12 @@ class ReaderPageSheet( | ||||
|     private fun setAsCover() { | ||||
|         if (page.status != Page.READY) return | ||||
|  | ||||
|         MaterialDialog(activity) | ||||
|             .message(R.string.confirm_set_image_as_cover) | ||||
|             .positiveButton(android.R.string.ok) { | ||||
|         MaterialAlertDialogBuilder(activity) | ||||
|             .setMessage(R.string.confirm_set_image_as_cover) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 activity.setAsCover(page) | ||||
|                 dismiss() | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .show() | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import android.view.MenuItem | ||||
| import android.view.View | ||||
| import androidx.appcompat.widget.SearchView | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.R | ||||
| @@ -221,12 +221,13 @@ class HistoryController : | ||||
|  | ||||
|     class ClearHistoryDialogController : DialogController() { | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .message(R.string.clear_history_confirmation) | ||||
|                 .positiveButton(android.R.string.ok) { | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setMessage(R.string.clear_history_confirmation) | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                     (targetController as? HistoryController)?.clearHistory() | ||||
|                 } | ||||
|                 .negativeButton(android.R.string.cancel) | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.recent.history | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.History | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| @@ -33,11 +32,12 @@ class RemoveHistoryDialog<T>(bundle: Bundle? = null) : DialogController(bundle) | ||||
|             setOptionDescription(R.string.dialog_with_checkbox_reset) | ||||
|         } | ||||
|  | ||||
|         return MaterialDialog(activity) | ||||
|             .title(R.string.action_remove) | ||||
|             .customView(view = dialogCheckboxView, horizontalPadding = true) | ||||
|             .positiveButton(R.string.action_remove) { onPositive(dialogCheckboxView.isChecked()) } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|         return MaterialAlertDialogBuilder(activity) | ||||
|             .setTitle(R.string.action_remove) | ||||
|             .setView(dialogCheckboxView) | ||||
|             .setPositiveButton(R.string.action_remove) { _, _ -> onPositive(dialogCheckboxView.isChecked()) } | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     private fun onPositive(checked: Boolean) { | ||||
|   | ||||
| @@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.recent.updates | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
|  | ||||
| @@ -18,12 +18,13 @@ class ConfirmDeleteChaptersDialog<T>(bundle: Bundle? = null) : DialogController( | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         return MaterialDialog(activity!!) | ||||
|             .message(R.string.confirm_delete_chapters) | ||||
|             .positiveButton(android.R.string.ok) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setMessage(R.string.confirm_delete_chapters) | ||||
|             .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                 (targetController as? Listener)?.deleteChapters(chaptersToDelete) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import android.os.Bundle | ||||
| import android.provider.Settings | ||||
| import androidx.core.net.toUri | ||||
| import androidx.preference.PreferenceScreen | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.cache.ChapterCache | ||||
| @@ -184,12 +184,13 @@ class SettingsAdvancedController : SettingsController() { | ||||
|  | ||||
|     class ClearDatabaseDialogController : DialogController() { | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .message(R.string.clear_database_confirmation) | ||||
|                 .positiveButton(android.R.string.ok) { | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setMessage(R.string.clear_database_confirmation) | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                     (targetController as? SettingsAdvancedController)?.clearDatabase() | ||||
|                 } | ||||
|                 .negativeButton(android.R.string.cancel) | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -9,12 +9,12 @@ import android.net.Uri | ||||
| import android.os.Bundle | ||||
| import android.view.View | ||||
| import android.widget.Toast | ||||
| import androidx.appcompat.app.AlertDialog | ||||
| import androidx.core.net.toUri | ||||
| import androidx.core.os.bundleOf | ||||
| import androidx.documentfile.provider.DocumentFile | ||||
| import androidx.preference.PreferenceScreen | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsMultiChoice | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import com.hippo.unifile.UniFile | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.backup.BackupConst | ||||
| @@ -246,29 +246,34 @@ class SettingsBackupController : SettingsController() { | ||||
|                 R.string.history | ||||
|             ) | ||||
|                 .map { activity.getString(it) } | ||||
|             val selected = options.map { true }.toBooleanArray() | ||||
|  | ||||
|             return MaterialDialog(activity) | ||||
|                 .title(R.string.pref_create_backup) | ||||
|                 .message(R.string.backup_choice) | ||||
|                 .listItemsMultiChoice( | ||||
|                     items = options, | ||||
|                     disabledIndices = intArrayOf(0), | ||||
|                     initialSelection = intArrayOf(0, 1, 2, 3, 4) | ||||
|                 ) { _, positions, _ -> | ||||
|             return MaterialAlertDialogBuilder(activity) | ||||
|                 .setTitle(R.string.backup_choice) | ||||
|                 .setMultiChoiceItems(options.toTypedArray(), selected) { dialog, which, checked -> | ||||
|                     if (which == 0) { | ||||
|                         (dialog as AlertDialog).listView.setItemChecked(which, true) | ||||
|                     } else { | ||||
|                         selected[which] = checked | ||||
|                     } | ||||
|                 } | ||||
|                 .setPositiveButton(R.string.action_create) { _, _ -> | ||||
|                     var flags = 0 | ||||
|                     for (i in 1 until positions.size) { | ||||
|                         when (positions[i]) { | ||||
|                             1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY | ||||
|                             2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER | ||||
|                             3 -> flags = flags or BackupCreateService.BACKUP_TRACK | ||||
|                             4 -> flags = flags or BackupCreateService.BACKUP_HISTORY | ||||
|                     selected.forEachIndexed { i, checked -> | ||||
|                         if (checked) { | ||||
|                             when (i) { | ||||
|                                 1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY | ||||
|                                 2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER | ||||
|                                 3 -> flags = flags or BackupCreateService.BACKUP_TRACK | ||||
|                                 4 -> flags = flags or BackupCreateService.BACKUP_HISTORY | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     (targetController as? SettingsBackupController)?.createBackup(flags) | ||||
|                 } | ||||
|                 .positiveButton(R.string.action_create) | ||||
|                 .negativeButton(android.R.string.cancel) | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -306,17 +311,19 @@ class SettingsBackupController : SettingsController() { | ||||
|                     message += "\n\n${activity.getString(R.string.backup_restore_missing_trackers)}\n${results.missingTrackers.joinToString("\n") { "- $it" }}" | ||||
|                 } | ||||
|  | ||||
|                 MaterialDialog(activity) | ||||
|                     .title(R.string.pref_restore_backup) | ||||
|                     .message(text = message) | ||||
|                     .positiveButton(R.string.action_restore) { | ||||
|                 MaterialAlertDialogBuilder(activity) | ||||
|                     .setTitle(R.string.pref_restore_backup) | ||||
|                     .setMessage(message) | ||||
|                     .setPositiveButton(R.string.action_restore) { _, _ -> | ||||
|                         BackupRestoreService.start(activity, uri, type) | ||||
|                     } | ||||
|                     .create() | ||||
|             } catch (e: Exception) { | ||||
|                 MaterialDialog(activity) | ||||
|                     .title(R.string.invalid_backup_file) | ||||
|                     .message(text = e.message) | ||||
|                     .positiveButton(android.R.string.cancel) | ||||
|                 MaterialAlertDialogBuilder(activity) | ||||
|                     .setTitle(R.string.invalid_backup_file) | ||||
|                     .setMessage(e.message) | ||||
|                     .setPositiveButton(android.R.string.cancel, null) | ||||
|                     .create() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,7 @@ import androidx.core.content.ContextCompat | ||||
| import androidx.core.net.toUri | ||||
| import androidx.core.text.buildSpannedString | ||||
| import androidx.preference.PreferenceScreen | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsSingleChoice | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import com.hippo.unifile.UniFile | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| @@ -28,8 +27,8 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory | ||||
| import eu.kanade.tachiyomi.util.preference.switchPreference | ||||
| import eu.kanade.tachiyomi.util.preference.titleRes | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateCheckBox | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.listItemsQuadStateMultiChoice | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.setQuadStateMultiChoiceItems | ||||
| import kotlinx.coroutines.flow.launchIn | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| import uy.kohesive.injekt.Injekt | ||||
| @@ -194,20 +193,22 @@ class SettingsDownloadController : SettingsController() { | ||||
|             val activity = activity!! | ||||
|             val currentDir = preferences.downloadsDirectory().get() | ||||
|             val externalDirs = (getExternalDirs() + File(activity.getString(R.string.custom_dir))).map(File::toString) | ||||
|             val selectedIndex = externalDirs.indexOfFirst { it in currentDir } | ||||
|             var selectedIndex = externalDirs.indexOfFirst { it in currentDir } | ||||
|  | ||||
|             return MaterialDialog(activity) | ||||
|                 .listItemsSingleChoice( | ||||
|                     items = externalDirs, | ||||
|                     initialSelection = selectedIndex | ||||
|                 ) { _, position, text -> | ||||
|             return MaterialAlertDialogBuilder(activity) | ||||
|                 .setTitle(R.string.pref_download_directory) | ||||
|                 .setSingleChoiceItems(externalDirs.toTypedArray(), selectedIndex) { _, which -> | ||||
|                     selectedIndex = which | ||||
|                 } | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                     val target = targetController as? SettingsDownloadController | ||||
|                     if (position == externalDirs.lastIndex) { | ||||
|                     if (selectedIndex == externalDirs.lastIndex) { | ||||
|                         target?.customDirectorySelected() | ||||
|                     } else { | ||||
|                         target?.predefinedDirectorySelected(text.toString()) | ||||
|                         target?.predefinedDirectorySelected(externalDirs[selectedIndex]) | ||||
|                     } | ||||
|                 } | ||||
|                 .create() | ||||
|         } | ||||
|  | ||||
|         private fun getExternalDirs(): List<File> { | ||||
| @@ -230,30 +231,33 @@ class SettingsDownloadController : SettingsController() { | ||||
|             val categories = listOf(Category.createDefault()) + dbCategories | ||||
|  | ||||
|             val items = categories.map { it.name } | ||||
|             val preselected = categories | ||||
|             var selected = categories | ||||
|                 .map { | ||||
|                     when (it.id.toString()) { | ||||
|                         in preferences.downloadNewCategories().get() -> QuadStateCheckBox.State.CHECKED.ordinal | ||||
|                         in preferences.downloadNewCategoriesExclude().get() -> QuadStateCheckBox.State.INVERSED.ordinal | ||||
|                         else -> QuadStateCheckBox.State.UNCHECKED.ordinal | ||||
|                         in preferences.downloadNewCategories().get() -> QuadStateTextView.State.CHECKED.ordinal | ||||
|                         in preferences.downloadNewCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal | ||||
|                         else -> QuadStateTextView.State.UNCHECKED.ordinal | ||||
|                     } | ||||
|                 } | ||||
|                 .toIntArray() | ||||
|  | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .title(R.string.categories) | ||||
|                 .message(R.string.pref_download_new_categories_details) | ||||
|                 .listItemsQuadStateMultiChoice( | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setTitle(R.string.categories) | ||||
|                 .setMessage(R.string.pref_download_new_categories_details) | ||||
|                 .setQuadStateMultiChoiceItems( | ||||
|                     items = items, | ||||
|                     initialSelected = preselected | ||||
|                     initialSelected = selected | ||||
|                 ) { selections -> | ||||
|                     val included = selections | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateCheckBox.State.CHECKED.ordinal) index else null } | ||||
|                     selected = selections | ||||
|                 } | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                     val included = selected | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateTextView.State.CHECKED.ordinal) index else null } | ||||
|                         .filterNotNull() | ||||
|                         .map { categories[it].id.toString() } | ||||
|                         .toSet() | ||||
|                     val excluded = selections | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateCheckBox.State.INVERSED.ordinal) index else null } | ||||
|                     val excluded = selected | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateTextView.State.INVERSED.ordinal) index else null } | ||||
|                         .filterNotNull() | ||||
|                         .map { categories[it].id.toString() } | ||||
|                         .toSet() | ||||
| @@ -261,8 +265,8 @@ class SettingsDownloadController : SettingsController() { | ||||
|                     preferences.downloadNewCategories().set(included) | ||||
|                     preferences.downloadNewCategoriesExclude().set(excluded) | ||||
|                 } | ||||
|                 .positiveButton(android.R.string.ok) | ||||
|                 .negativeButton(android.R.string.cancel) | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,12 +2,11 @@ package eu.kanade.tachiyomi.ui.setting | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import android.view.View | ||||
| import android.view.LayoutInflater | ||||
| import androidx.core.content.ContextCompat | ||||
| import androidx.core.text.buildSpannedString | ||||
| import androidx.preference.PreferenceScreen | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| @@ -17,6 +16,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.UNMETERED_NETWORK | ||||
| import eu.kanade.tachiyomi.data.preference.asImmediateFlow | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction | ||||
| import eu.kanade.tachiyomi.ui.category.CategoryController | ||||
| @@ -32,9 +32,8 @@ import eu.kanade.tachiyomi.util.preference.summaryRes | ||||
| import eu.kanade.tachiyomi.util.preference.switchPreference | ||||
| import eu.kanade.tachiyomi.util.preference.titleRes | ||||
| import eu.kanade.tachiyomi.util.system.isTablet | ||||
| import eu.kanade.tachiyomi.widget.MinMaxNumberPicker | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateCheckBox | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.listItemsQuadStateMultiChoice | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.setQuadStateMultiChoiceItems | ||||
| import kotlinx.coroutines.flow.combine | ||||
| import kotlinx.coroutines.flow.launchIn | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| @@ -299,21 +298,21 @@ class SettingsLibraryController : SettingsController() { | ||||
|         private var landscape = preferences.landscapeColumns().get() | ||||
|  | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             val dialog = MaterialDialog(activity!!) | ||||
|                 .title(R.string.pref_library_columns) | ||||
|                 .customView(R.layout.pref_library_columns, horizontalPadding = true) | ||||
|                 .positiveButton(android.R.string.ok) { | ||||
|             val binding = PrefLibraryColumnsBinding.inflate(LayoutInflater.from(activity!!)) | ||||
|             onViewCreated(binding) | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setTitle(R.string.pref_library_columns) | ||||
|                 .setView(binding.root) | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                     preferences.portraitColumns().set(portrait) | ||||
|                     preferences.landscapeColumns().set(landscape) | ||||
|                 } | ||||
|                 .negativeButton(android.R.string.cancel) | ||||
|  | ||||
|             onViewCreated(dialog.view) | ||||
|             return dialog | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|  | ||||
|         fun onViewCreated(view: View) { | ||||
|             with(view.findViewById(R.id.portrait_columns) as MinMaxNumberPicker) { | ||||
|         fun onViewCreated(binding: PrefLibraryColumnsBinding) { | ||||
|             with(binding.portraitColumns) { | ||||
|                 displayedValues = arrayOf(context.getString(R.string.default_columns)) + | ||||
|                     IntRange(1, 10).map(Int::toString) | ||||
|                 value = portrait | ||||
| @@ -322,7 +321,7 @@ class SettingsLibraryController : SettingsController() { | ||||
|                     portrait = newValue | ||||
|                 } | ||||
|             } | ||||
|             with(view.findViewById(R.id.landscape_columns) as MinMaxNumberPicker) { | ||||
|             with(binding.landscapeColumns) { | ||||
|                 displayedValues = arrayOf(context.getString(R.string.default_columns)) + | ||||
|                     IntRange(1, 10).map(Int::toString) | ||||
|                 value = landscape | ||||
| @@ -344,30 +343,30 @@ class SettingsLibraryController : SettingsController() { | ||||
|             val categories = listOf(Category.createDefault()) + dbCategories | ||||
|  | ||||
|             val items = categories.map { it.name } | ||||
|             val preselected = categories | ||||
|             var selected = categories | ||||
|                 .map { | ||||
|                     when (it.id.toString()) { | ||||
|                         in preferences.libraryUpdateCategories().get() -> QuadStateCheckBox.State.CHECKED.ordinal | ||||
|                         in preferences.libraryUpdateCategoriesExclude().get() -> QuadStateCheckBox.State.INVERSED.ordinal | ||||
|                         else -> QuadStateCheckBox.State.UNCHECKED.ordinal | ||||
|                         in preferences.libraryUpdateCategories().get() -> QuadStateTextView.State.CHECKED.ordinal | ||||
|                         in preferences.libraryUpdateCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal | ||||
|                         else -> QuadStateTextView.State.UNCHECKED.ordinal | ||||
|                     } | ||||
|                 } | ||||
|                 .toIntArray() | ||||
|  | ||||
|             return MaterialDialog(activity!!) | ||||
|                 .title(R.string.categories) | ||||
|                 .message(R.string.pref_library_update_categories_details) | ||||
|                 .listItemsQuadStateMultiChoice( | ||||
|                     items = items, | ||||
|                     initialSelected = preselected | ||||
|                 ) { selections -> | ||||
|                     val included = selections | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateCheckBox.State.CHECKED.ordinal) index else null } | ||||
|             return MaterialAlertDialogBuilder(activity!!) | ||||
|                 .setTitle(R.string.categories) | ||||
|                 .setMessage(R.string.pref_library_update_categories_details) | ||||
|                 .setQuadStateMultiChoiceItems(items = items, initialSelected = selected) { selections -> | ||||
|                     selected = selections | ||||
|                 } | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                     val included = selected | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateTextView.State.CHECKED.ordinal) index else null } | ||||
|                         .filterNotNull() | ||||
|                         .map { categories[it].id.toString() } | ||||
|                         .toSet() | ||||
|                     val excluded = selections | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateCheckBox.State.INVERSED.ordinal) index else null } | ||||
|                     val excluded = selected | ||||
|                         .mapIndexed { index, value -> if (value == QuadStateTextView.State.INVERSED.ordinal) index else null } | ||||
|                         .filterNotNull() | ||||
|                         .map { categories[it].id.toString() } | ||||
|                         .toSet() | ||||
| @@ -375,8 +374,8 @@ class SettingsLibraryController : SettingsController() { | ||||
|                     preferences.libraryUpdateCategories().set(included) | ||||
|                     preferences.libraryUpdateCategoriesExclude().set(excluded) | ||||
|                 } | ||||
|                 .positiveButton(android.R.string.ok) | ||||
|                 .negativeButton(android.R.string.cancel) | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .create() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.setting.track | ||||
| import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import androidx.core.os.bundleOf | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.data.track.TrackService | ||||
| @@ -20,14 +20,15 @@ class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) { | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         val serviceName = activity!!.getString(service.nameRes()) | ||||
|         return MaterialDialog(activity!!) | ||||
|             .title(text = activity!!.getString(R.string.logout_title, serviceName)) | ||||
|             .positiveButton(R.string.logout) { | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(activity!!.getString(R.string.logout_title, serviceName)) | ||||
|             .setPositiveButton(R.string.logout) { _, _ -> | ||||
|                 service.logout() | ||||
|                 (targetController as? Listener)?.trackLogoutDialogClosed(service) | ||||
|                 activity?.toast(R.string.logout_success) | ||||
|             } | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     interface Listener { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.util.lang | ||||
| import java.text.DateFormat | ||||
| import java.util.Calendar | ||||
| import java.util.Date | ||||
| import java.util.TimeZone | ||||
|  | ||||
| fun Date.toDateTimestampString(dateFormatter: DateFormat): String { | ||||
|     val date = dateFormatter.format(this) | ||||
| @@ -43,3 +44,28 @@ fun Long.toCalendar(): Calendar? { | ||||
|     cal.timeInMillis = this | ||||
|     return cal | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Convert epoch long to Calendar instance in UTC | ||||
|  * | ||||
|  * @return UTC Calendar instance at supplied epoch time. Null if epoch was 0. | ||||
|  */ | ||||
| fun Long.toUtcCalendar(): Calendar? { | ||||
|     if (this == 0L) { | ||||
|         return null | ||||
|     } | ||||
|     val rawCalendar = Calendar.getInstance().apply { | ||||
|         timeInMillis = this@toUtcCalendar | ||||
|     } | ||||
|     return Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { | ||||
|         clear() | ||||
|         set( | ||||
|             rawCalendar.get(Calendar.YEAR), | ||||
|             rawCalendar.get(Calendar.MONTH), | ||||
|             rawCalendar.get(Calendar.DAY_OF_MONTH), | ||||
|             rawCalendar.get(Calendar.HOUR_OF_DAY), | ||||
|             rawCalendar.get(Calendar.MINUTE), | ||||
|             rawCalendar.get(Calendar.SECOND) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,54 @@ | ||||
| package eu.kanade.tachiyomi.widget.materialdialogs | ||||
|  | ||||
| import android.view.LayoutInflater | ||||
| import android.view.inputmethod.InputMethodManager | ||||
| import android.widget.TextView | ||||
| import androidx.core.content.getSystemService | ||||
| import androidx.core.widget.doAfterTextChanged | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.databinding.DialogStubQuadstatemultichoiceBinding | ||||
| import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding | ||||
|  | ||||
| fun MaterialAlertDialogBuilder.setTextInput( | ||||
|     hint: String? = null, | ||||
|     prefill: String? = null, | ||||
|     onTextChanged: (String) -> Unit | ||||
| ): MaterialAlertDialogBuilder { | ||||
|     val binding = DialogStubTextinputBinding.inflate(LayoutInflater.from(context)) | ||||
|     binding.textField.hint = hint | ||||
|     binding.textField.editText?.apply { | ||||
|         setText(prefill, TextView.BufferType.EDITABLE) | ||||
|         doAfterTextChanged { | ||||
|             onTextChanged(it?.toString() ?: "") | ||||
|         } | ||||
|         post { | ||||
|             requestFocusFromTouch() | ||||
|             context.getSystemService<InputMethodManager>()?.showSoftInput(this, 0) | ||||
|         } | ||||
|     } | ||||
|     return setView(binding.root) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Sets a list of items with checkboxes that supports 4 states. | ||||
|  * | ||||
|  * @see eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView | ||||
|  */ | ||||
| fun MaterialAlertDialogBuilder.setQuadStateMultiChoiceItems( | ||||
|     items: List<CharSequence>, | ||||
|     initialSelected: IntArray, | ||||
|     disabledIndices: IntArray? = null, | ||||
|     selection: QuadStateMultiChoiceListener | ||||
| ): MaterialAlertDialogBuilder { | ||||
|     val binding = DialogStubQuadstatemultichoiceBinding.inflate(LayoutInflater.from(context)) | ||||
|     binding.list.layoutManager = LinearLayoutManager(context) | ||||
|     binding.list.adapter = QuadStateMultiChoiceDialogAdapter( | ||||
|         items = items, | ||||
|         disabledItems = disabledIndices, | ||||
|         initialSelected = initialSelected, | ||||
|         listener = selection | ||||
|     ) | ||||
|     setView(binding.root) | ||||
|     return this | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.widget.materialdialogs | ||||
|  | ||||
| import androidx.annotation.CheckResult | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.customListAdapter | ||||
|  | ||||
| /** | ||||
|  * A variant of listItemsMultiChoice that allows for checkboxes that supports 4 states instead. | ||||
|  */ | ||||
| @CheckResult | ||||
| fun MaterialDialog.listItemsQuadStateMultiChoice( | ||||
|     items: List<CharSequence>, | ||||
|     disabledIndices: IntArray? = null, | ||||
|     initialSelected: IntArray = IntArray(items.size), | ||||
|     selection: QuadStateMultiChoiceListener | ||||
| ): MaterialDialog { | ||||
|     return customListAdapter( | ||||
|         QuadStateMultiChoiceDialogAdapter( | ||||
|             dialog = this, | ||||
|             items = items, | ||||
|             disabledItems = disabledIndices, | ||||
|             initialSelected = initialSelected, | ||||
|             selection = selection | ||||
|         ) | ||||
|     ) | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.widget.materialdialogs | ||||
|  | ||||
| import android.content.Context | ||||
| import android.util.AttributeSet | ||||
| import androidx.appcompat.widget.AppCompatImageView | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.util.view.setVectorCompat | ||||
|  | ||||
| class QuadStateCheckBox @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : | ||||
|     AppCompatImageView(context, attrs) { | ||||
|  | ||||
|     var state: State = State.UNCHECKED | ||||
|         set(value) { | ||||
|             field = value | ||||
|             updateDrawable() | ||||
|         } | ||||
|  | ||||
|     private fun updateDrawable() { | ||||
|         when (state) { | ||||
|             State.UNCHECKED -> setVectorCompat(R.drawable.ic_check_box_outline_blank_24dp, R.attr.colorControlNormal) | ||||
|             State.INDETERMINATE -> setVectorCompat(R.drawable.ic_indeterminate_check_box_24dp, R.attr.colorAccent) | ||||
|             State.CHECKED -> setVectorCompat(R.drawable.ic_check_box_24dp, R.attr.colorAccent) | ||||
|             State.INVERSED -> setVectorCompat(R.drawable.ic_check_box_x_24dp, R.attr.colorAccent) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     enum class State { | ||||
|         UNCHECKED, | ||||
|         INDETERMINATE, | ||||
|         CHECKED, | ||||
|         INVERSED, | ||||
|         ; | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +1,9 @@ | ||||
| package eu.kanade.tachiyomi.widget.materialdialogs | ||||
|  | ||||
| import android.view.View | ||||
| import android.view.LayoutInflater | ||||
| import android.view.ViewGroup | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.internal.list.DialogAdapter | ||||
| import com.afollestad.materialdialogs.list.getItemSelector | ||||
| import com.afollestad.materialdialogs.utils.MDUtil.inflate | ||||
| import com.afollestad.materialdialogs.utils.MDUtil.maybeSetTextColor | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.databinding.DialogQuadstatemultichoiceItemBinding | ||||
|  | ||||
| private object CheckPayload | ||||
| private object InverseCheckPayload | ||||
| @@ -17,15 +12,13 @@ private object UncheckPayload | ||||
| typealias QuadStateMultiChoiceListener = (indices: IntArray) -> Unit | ||||
|  | ||||
| internal class QuadStateMultiChoiceDialogAdapter( | ||||
|     private var dialog: MaterialDialog, | ||||
|     internal var items: List<CharSequence>, | ||||
|     disabledItems: IntArray?, | ||||
|     initialSelected: IntArray, | ||||
|     internal var selection: QuadStateMultiChoiceListener | ||||
| ) : RecyclerView.Adapter<QuadStateMultiChoiceViewHolder>(), | ||||
|     DialogAdapter<CharSequence, QuadStateMultiChoiceListener> { | ||||
|     internal var listener: QuadStateMultiChoiceListener | ||||
| ) : RecyclerView.Adapter<QuadStateMultiChoiceViewHolder>() { | ||||
|  | ||||
|     private val states = QuadStateCheckBox.State.values() | ||||
|     private val states = QuadStateTextView.State.values() | ||||
|  | ||||
|     private var currentSelection: IntArray = initialSelected | ||||
|         set(value) { | ||||
| @@ -34,15 +27,15 @@ internal class QuadStateMultiChoiceDialogAdapter( | ||||
|             previousSelection.forEachIndexed { index, previous -> | ||||
|                 val current = value[index] | ||||
|                 when { | ||||
|                     current == QuadStateCheckBox.State.CHECKED.ordinal && previous != QuadStateCheckBox.State.CHECKED.ordinal -> { | ||||
|                     current == QuadStateTextView.State.CHECKED.ordinal && previous != QuadStateTextView.State.CHECKED.ordinal -> { | ||||
|                         // This value was selected | ||||
|                         notifyItemChanged(index, CheckPayload) | ||||
|                     } | ||||
|                     current == QuadStateCheckBox.State.INVERSED.ordinal && previous != QuadStateCheckBox.State.INVERSED.ordinal -> { | ||||
|                     current == QuadStateTextView.State.INVERSED.ordinal && previous != QuadStateTextView.State.INVERSED.ordinal -> { | ||||
|                         // This value was inverse selected | ||||
|                         notifyItemChanged(index, InverseCheckPayload) | ||||
|                     } | ||||
|                     current == QuadStateCheckBox.State.UNCHECKED.ordinal && previous != QuadStateCheckBox.State.UNCHECKED.ordinal -> { | ||||
|                     current == QuadStateTextView.State.UNCHECKED.ordinal && previous != QuadStateTextView.State.UNCHECKED.ordinal -> { | ||||
|                         // This value was unselected | ||||
|                         notifyItemChanged(index, UncheckPayload) | ||||
|                     } | ||||
| @@ -54,26 +47,24 @@ internal class QuadStateMultiChoiceDialogAdapter( | ||||
|     internal fun itemClicked(index: Int) { | ||||
|         val newSelection = this.currentSelection.toMutableList() | ||||
|         newSelection[index] = when (currentSelection[index]) { | ||||
|             QuadStateCheckBox.State.CHECKED.ordinal -> QuadStateCheckBox.State.INVERSED.ordinal | ||||
|             QuadStateCheckBox.State.INVERSED.ordinal -> QuadStateCheckBox.State.UNCHECKED.ordinal | ||||
|             QuadStateTextView.State.CHECKED.ordinal -> QuadStateTextView.State.INVERSED.ordinal | ||||
|             QuadStateTextView.State.INVERSED.ordinal -> QuadStateTextView.State.UNCHECKED.ordinal | ||||
|             // INDETERMINATE or UNCHECKED | ||||
|             else -> QuadStateCheckBox.State.CHECKED.ordinal | ||||
|             else -> QuadStateTextView.State.CHECKED.ordinal | ||||
|         } | ||||
|         this.currentSelection = newSelection.toIntArray() | ||||
|         listener(currentSelection) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateViewHolder( | ||||
|         parent: ViewGroup, | ||||
|         viewType: Int | ||||
|     ): QuadStateMultiChoiceViewHolder { | ||||
|         val listItemView: View = parent.inflate(dialog.windowContext, R.layout.md_listitem_quadstatemultichoice) | ||||
|         val viewHolder = QuadStateMultiChoiceViewHolder( | ||||
|             itemView = listItemView, | ||||
|         return QuadStateMultiChoiceViewHolder( | ||||
|             itemBinding = DialogQuadstatemultichoiceItemBinding | ||||
|                 .inflate(LayoutInflater.from(parent.context), parent, false), | ||||
|             adapter = this | ||||
|         ) | ||||
|         viewHolder.titleView.maybeSetTextColor(dialog.windowContext, R.attr.md_color_content) | ||||
|  | ||||
|         return viewHolder | ||||
|     } | ||||
|  | ||||
|     override fun getItemCount() = items.size | ||||
| @@ -83,14 +74,8 @@ internal class QuadStateMultiChoiceDialogAdapter( | ||||
|         position: Int | ||||
|     ) { | ||||
|         holder.isEnabled = !disabledIndices.contains(position) | ||||
|  | ||||
|         holder.controlView.state = states[currentSelection[position]] | ||||
|         holder.titleView.text = items[position] | ||||
|         holder.itemView.background = dialog.getItemSelector() | ||||
|  | ||||
|         if (dialog.bodyFont != null) { | ||||
|             holder.titleView.typeface = dialog.bodyFont | ||||
|         } | ||||
|         holder.controlView.text = items[position] | ||||
|     } | ||||
|  | ||||
|     override fun onBindViewHolder( | ||||
| @@ -100,88 +85,18 @@ internal class QuadStateMultiChoiceDialogAdapter( | ||||
|     ) { | ||||
|         when (payloads.firstOrNull()) { | ||||
|             CheckPayload -> { | ||||
|                 holder.controlView.state = QuadStateCheckBox.State.CHECKED | ||||
|                 holder.controlView.state = QuadStateTextView.State.CHECKED | ||||
|                 return | ||||
|             } | ||||
|             InverseCheckPayload -> { | ||||
|                 holder.controlView.state = QuadStateCheckBox.State.INVERSED | ||||
|                 holder.controlView.state = QuadStateTextView.State.INVERSED | ||||
|                 return | ||||
|             } | ||||
|             UncheckPayload -> { | ||||
|                 holder.controlView.state = QuadStateCheckBox.State.UNCHECKED | ||||
|                 holder.controlView.state = QuadStateTextView.State.UNCHECKED | ||||
|                 return | ||||
|             } | ||||
|         } | ||||
|         super.onBindViewHolder(holder, position, payloads) | ||||
|     } | ||||
|  | ||||
|     override fun positiveButtonClicked() { | ||||
|         selection.invoke(currentSelection) | ||||
|     } | ||||
|  | ||||
|     override fun replaceItems( | ||||
|         items: List<CharSequence>, | ||||
|         listener: QuadStateMultiChoiceListener? | ||||
|     ) { | ||||
|         this.items = items | ||||
|         if (listener != null) { | ||||
|             this.selection = listener | ||||
|         } | ||||
|         this.notifyDataSetChanged() | ||||
|     } | ||||
|  | ||||
|     override fun disableItems(indices: IntArray) { | ||||
|         this.disabledIndices = indices | ||||
|         notifyDataSetChanged() | ||||
|     } | ||||
|  | ||||
|     override fun checkItems(indices: IntArray) { | ||||
|         val newSelection = this.currentSelection.toMutableList() | ||||
|         for (index in indices) { | ||||
|             newSelection[index] = QuadStateCheckBox.State.CHECKED.ordinal | ||||
|         } | ||||
|         this.currentSelection = newSelection.toIntArray() | ||||
|     } | ||||
|  | ||||
|     override fun uncheckItems(indices: IntArray) { | ||||
|         val newSelection = this.currentSelection.toMutableList() | ||||
|         for (index in indices) { | ||||
|             newSelection[index] = QuadStateCheckBox.State.UNCHECKED.ordinal | ||||
|         } | ||||
|         this.currentSelection = newSelection.toIntArray() | ||||
|     } | ||||
|  | ||||
|     override fun toggleItems(indices: IntArray) { | ||||
|         val newSelection = this.currentSelection.toMutableList() | ||||
|         for (index in indices) { | ||||
|             if (this.disabledIndices.contains(index)) { | ||||
|                 continue | ||||
|             } | ||||
|  | ||||
|             if (this.currentSelection[index] != QuadStateCheckBox.State.CHECKED.ordinal) { | ||||
|                 newSelection[index] = QuadStateCheckBox.State.CHECKED.ordinal | ||||
|             } else { | ||||
|                 newSelection[index] = QuadStateCheckBox.State.UNCHECKED.ordinal | ||||
|             } | ||||
|         } | ||||
|         this.currentSelection = newSelection.toIntArray() | ||||
|     } | ||||
|  | ||||
|     override fun checkAllItems() { | ||||
|         this.currentSelection = IntArray(itemCount) { QuadStateCheckBox.State.CHECKED.ordinal } | ||||
|     } | ||||
|  | ||||
|     override fun uncheckAllItems() { | ||||
|         this.currentSelection = IntArray(itemCount) { QuadStateCheckBox.State.UNCHECKED.ordinal } | ||||
|     } | ||||
|  | ||||
|     override fun toggleAllChecked() { | ||||
|         if (this.currentSelection.any { it != QuadStateCheckBox.State.CHECKED.ordinal }) { | ||||
|             checkAllItems() | ||||
|         } else { | ||||
|             uncheckAllItems() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun isItemChecked(index: Int) = this.currentSelection[index] == QuadStateCheckBox.State.CHECKED.ordinal | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,24 @@ | ||||
| package eu.kanade.tachiyomi.widget.materialdialogs | ||||
|  | ||||
| import android.view.View | ||||
| import android.widget.TextView | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.databinding.DialogQuadstatemultichoiceItemBinding | ||||
|  | ||||
| internal class QuadStateMultiChoiceViewHolder( | ||||
|     itemView: View, | ||||
|     itemBinding: DialogQuadstatemultichoiceItemBinding, | ||||
|     private val adapter: QuadStateMultiChoiceDialogAdapter | ||||
| ) : RecyclerView.ViewHolder(itemView), View.OnClickListener { | ||||
| ) : RecyclerView.ViewHolder(itemBinding.root), View.OnClickListener { | ||||
|     init { | ||||
|         itemView.setOnClickListener(this) | ||||
|     } | ||||
|  | ||||
|     val controlView: QuadStateCheckBox = itemView.findViewById(R.id.md_quad_state_control) | ||||
|     val titleView: TextView = itemView.findViewById(R.id.md_quad_state_title) | ||||
|     val controlView = itemBinding.quadStateControl | ||||
|  | ||||
|     var isEnabled: Boolean | ||||
|         get() = itemView.isEnabled | ||||
|         set(value) { | ||||
|             itemView.isEnabled = value | ||||
|             controlView.isEnabled = value | ||||
|             titleView.isEnabled = value | ||||
|         } | ||||
|  | ||||
|     override fun onClick(view: View) = adapter.itemClicked(bindingAdapterPosition) | ||||
|   | ||||
| @@ -0,0 +1,45 @@ | ||||
| package eu.kanade.tachiyomi.widget.materialdialogs | ||||
|  | ||||
| import android.content.Context | ||||
| import android.content.res.ColorStateList | ||||
| import android.util.AttributeSet | ||||
| import androidx.appcompat.widget.AppCompatTextView | ||||
| import com.mikepenz.aboutlibraries.util.getThemeColor | ||||
| import eu.kanade.tachiyomi.R | ||||
|  | ||||
| class QuadStateTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : | ||||
|     AppCompatTextView(context, attrs) { | ||||
|  | ||||
|     var state: State = State.UNCHECKED | ||||
|         set(value) { | ||||
|             field = value | ||||
|             updateDrawable() | ||||
|         } | ||||
|  | ||||
|     private fun updateDrawable() { | ||||
|         val drawableStartId = when (state) { | ||||
|             State.UNCHECKED -> R.drawable.ic_check_box_outline_blank_24dp | ||||
|             State.INDETERMINATE -> R.drawable.ic_indeterminate_check_box_24dp | ||||
|             State.CHECKED -> R.drawable.ic_check_box_24dp | ||||
|             State.INVERSED -> R.drawable.ic_check_box_x_24dp | ||||
|         } | ||||
|         setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStartId, 0, 0, 0) | ||||
|  | ||||
|         val tint = if (state == State.UNCHECKED) { | ||||
|             context.getThemeColor(R.attr.colorControlNormal) | ||||
|         } else { | ||||
|             context.getThemeColor(R.attr.colorAccent) | ||||
|         } | ||||
|         if (tint != 0) { | ||||
|             compoundDrawableTintList = ColorStateList.valueOf(tint) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     enum class State { | ||||
|         UNCHECKED, | ||||
|         INDETERMINATE, | ||||
|         CHECKED, | ||||
|         INVERSED, | ||||
|         ; | ||||
|     } | ||||
| } | ||||
| @@ -5,11 +5,10 @@ import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import androidx.annotation.StringRes | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.customview.customView | ||||
| import com.bluelinelabs.conductor.ControllerChangeHandler | ||||
| import com.bluelinelabs.conductor.ControllerChangeType | ||||
| import com.dd.processbutton.iml.ActionProcessButton | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.databinding.PrefAccountLoginBinding | ||||
| @@ -28,15 +27,13 @@ abstract class LoginDialogPreference( | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         binding = PrefAccountLoginBinding.inflate(LayoutInflater.from(activity!!)) | ||||
|         onViewCreated(binding!!.root) | ||||
|         val titleName = activity!!.getString(getTitleName()) | ||||
|         val dialog = MaterialDialog(activity!!) | ||||
|             .title(text = activity!!.getString(R.string.login_title, titleName)) | ||||
|             .customView(view = binding!!.root) | ||||
|             .negativeButton(android.R.string.cancel) | ||||
|  | ||||
|         onViewCreated(dialog.view) | ||||
|  | ||||
|         return dialog | ||||
|         return MaterialAlertDialogBuilder(activity!!) | ||||
|             .setTitle(activity!!.getString(R.string.login_title, titleName)) | ||||
|             .setView(binding!!.root) | ||||
|             .setNegativeButton(android.R.string.cancel, null) | ||||
|             .create() | ||||
|     } | ||||
|  | ||||
|     fun onViewCreated(view: View) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user