diff --git a/.idea/gradle.xml b/.idea/gradle.xml index a0de2a152..6e5389ed9 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -7,7 +7,7 @@ - + diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt index 54cae9713..2fcfeac76 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseActivity.kt @@ -26,7 +26,8 @@ import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.prefs.AppSettings -abstract class BaseActivity : AppCompatActivity(), +abstract class BaseActivity : + AppCompatActivity(), WindowInsetsDelegate.WindowInsetsListener { protected lateinit var binding: B @@ -123,4 +124,4 @@ abstract class BaseActivity : AppCompatActivity(), super.onBackPressed() } } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt index 3c048aa54..58e353ca8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.base.ui.dialog import android.content.Context import android.content.DialogInterface +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter @@ -12,7 +13,6 @@ import kotlinx.coroutines.runBlocking import org.koitharu.kotatsu.R import org.koitharu.kotatsu.databinding.ItemStorageBinding import org.koitharu.kotatsu.local.data.LocalStorageManager -import org.koitharu.kotatsu.utils.ext.inflate import java.io.File class StorageSelectDialog private constructor(private val delegate: AlertDialog) : @@ -66,7 +66,7 @@ class StorageSelectDialog private constructor(private val delegate: AlertDialog) val volumes = getAvailableVolumes(storageManager) override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val view = convertView ?: parent.inflate(R.layout.item_storage) + val view = convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.item_storage, parent, false) val binding = (view.tag as? ItemStorageBinding) ?: ItemStorageBinding.bind(view).also { view.tag = it } diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ListItemTextView.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ListItemTextView.kt index 7004192ad..18d7262dc 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ListItemTextView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ListItemTextView.kt @@ -13,12 +13,12 @@ import android.graphics.drawable.shapes.RectShape import android.util.AttributeSet import androidx.annotation.AttrRes import androidx.appcompat.widget.AppCompatCheckedTextView -import androidx.core.content.res.use import androidx.core.content.withStyledAttributes import com.google.android.material.ripple.RippleUtils import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.ShapeAppearanceModel import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.utils.ext.getThemeColorStateList @SuppressLint("RestrictedApi") class ListItemTextView @JvmOverloads constructor( @@ -119,8 +119,7 @@ class ListItemTextView @JvmOverloads constructor( } private fun getRippleColorFallback(context: Context): ColorStateList { - return context.obtainStyledAttributes(intArrayOf(android.R.attr.colorControlHighlight)).use { - it.getColorStateList(0) - } ?: ColorStateList.valueOf(Color.TRANSPARENT) + return context.getThemeColorStateList(android.R.attr.colorControlHighlight) + ?: ColorStateList.valueOf(Color.TRANSPARENT) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index de191e304..89cbc1aaf 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -11,6 +11,10 @@ import androidx.collection.arraySetOf import androidx.core.content.edit import androidx.preference.PreferenceManager import com.google.android.material.color.DynamicColors +import java.io.File +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.* import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.flow.callbackFlow @@ -19,10 +23,6 @@ import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.ext.getEnumValue import org.koitharu.kotatsu.utils.ext.putEnumValue import org.koitharu.kotatsu.utils.ext.toUriOrNull -import java.io.File -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.* class AppSettings(context: Context) { @@ -281,4 +281,4 @@ class AppSettings(context: Context) { private val isSamsung get() = Build.MANUFACTURER.equals("samsung", ignoreCase = true) } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index ab4ae21e1..df4fc2de9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.text.Spanned import android.text.method.LinkMovementMethod import android.view.* +import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat import androidx.core.graphics.Insets import androidx.core.net.toUri @@ -224,14 +225,16 @@ class DetailsFragment : if (viewModel.readingHistory.value == null) { return false } - v.showPopupMenu(R.menu.popup_read) { - when (it.itemId) { + val menu = PopupMenu(v.context, v) + menu.inflate(R.menu.popup_read) + menu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { R.id.action_read -> { val branch = viewModel.selectedBranchValue startActivity( ReaderActivity.newIntent( - context = context ?: return@showPopupMenu false, - manga = viewModel.manga.value ?: return@showPopupMenu false, + context = context ?: return@setOnMenuItemClickListener false, + manga = viewModel.manga.value ?: return@setOnMenuItemClickListener false, state = viewModel.chapters.value?.firstOrNull { c -> c.chapter.branch == branch }?.let { c -> @@ -244,6 +247,7 @@ class DetailsFragment : else -> false } } + menu.show() return true } else -> return false diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt index 9fc69a228..27ae2696d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.favourites.ui import android.os.Bundle import android.view.* import androidx.appcompat.view.ActionMode +import androidx.appcompat.widget.PopupMenu import androidx.core.graphics.Insets import androidx.core.view.children import androidx.core.view.updateLayoutParams @@ -10,7 +11,6 @@ import androidx.core.view.updatePadding import com.google.android.material.snackbar.Snackbar import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator -import java.util.* import org.koin.androidx.viewmodel.ext.android.viewModel import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment @@ -25,7 +25,7 @@ import org.koitharu.kotatsu.main.ui.AppBarOwner import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.measureHeight -import org.koitharu.kotatsu.utils.ext.showPopupMenu +import java.util.* class FavouritesContainerFragment : BaseFragment(), @@ -123,22 +123,24 @@ class FavouritesContainerFragment : override fun onTabLongClick(tabView: View, category: FavouriteCategory): Boolean { val menuRes = if (category.id == 0L) R.menu.popup_category_empty else R.menu.popup_category - tabView.showPopupMenu(menuRes, { menu -> - createOrderSubmenu(menu, category) - }) { + val menu = PopupMenu(tabView.context, tabView) + menu.inflate(menuRes) + createOrderSubmenu(menu.menu, category) + menu.setOnMenuItemClickListener { when (it.itemId) { R.id.action_remove -> editDelegate.deleteCategory(category) R.id.action_rename -> editDelegate.renameCategory(category) R.id.action_create -> editDelegate.createCategory() - R.id.action_order -> return@showPopupMenu false + R.id.action_order -> return@setOnMenuItemClickListener false else -> { val order = CategoriesActivity.SORT_ORDERS.getOrNull(it.order) - ?: return@showPopupMenu false + ?: return@setOnMenuItemClickListener false viewModel.setCategoryOrder(category.id, order) } } true } + menu.show() return true } diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt index c147351b0..9caeb87c8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt @@ -6,6 +6,7 @@ import android.os.Bundle import android.view.Menu import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.PopupMenu import androidx.core.graphics.Insets import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams @@ -23,11 +24,12 @@ import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.measureHeight -import org.koitharu.kotatsu.utils.ext.showPopupMenu -class CategoriesActivity : BaseActivity(), +class CategoriesActivity : + BaseActivity(), OnListItemClickListener, - View.OnClickListener, CategoriesEditDelegate.CategoriesEditCallback { + View.OnClickListener, + CategoriesEditDelegate.CategoriesEditCallback { private val viewModel by viewModel() @@ -58,26 +60,27 @@ class CategoriesActivity : BaseActivity(), } override fun onItemClick(item: FavouriteCategory, view: View) { - view.showPopupMenu(R.menu.popup_category, { menu -> - createOrderSubmenu(menu, item) - }) { - when (it.itemId) { + val menu = PopupMenu(view.context, view) + menu.inflate(R.menu.popup_category) + createOrderSubmenu(menu.menu, item) + menu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { R.id.action_remove -> editDelegate.deleteCategory(item) R.id.action_rename -> editDelegate.renameCategory(item) - R.id.action_order -> return@showPopupMenu false + R.id.action_order -> return@setOnMenuItemClickListener false else -> { - val order = SORT_ORDERS.getOrNull(it.order) ?: return@showPopupMenu false + val order = SORT_ORDERS.getOrNull(menuItem.order) ?: return@setOnMenuItemClickListener false viewModel.setCategoryOrder(item.id, order) } } true } + menu.show() } override fun onItemLongClick(item: FavouriteCategory, view: View): Boolean { - reorderHelper.startDrag( - binding.recyclerView.findContainingViewHolder(view) ?: return false - ) + val viewHolder = binding.recyclerView.findContainingViewHolder(view) ?: return false + reorderHelper.startDrag(viewHolder) return true } @@ -90,7 +93,7 @@ class CategoriesActivity : BaseActivity(), binding.recyclerView.updatePadding( left = insets.left, right = insets.right, - bottom = 2 * insets.bottom + binding.fabAdd.measureHeight() + bottom = 2 * insets.bottom + binding.fabAdd.measureHeight(), ) } diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt index 46dfaefd5..a7ae219e8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt @@ -43,7 +43,7 @@ class ListModeSelectDialog : AlertDialogFragment(), binding.textViewGridTitle.isVisible = mode == ListMode.GRID binding.sliderGrid.isVisible = mode == ListMode.GRID - binding.sliderGrid.setLabelFormatter(IntPercentLabelFormatter()) + binding.sliderGrid.setLabelFormatter(IntPercentLabelFormatter(view.context)) binding.sliderGrid.setValueRounded(settings.gridSize.toFloat()) binding.sliderGrid.addOnSliderTouchListener(this) diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt index 939d5b256..106d141f4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt @@ -40,7 +40,7 @@ class MangaSelectionDecoration(context: Context) : AbstractSelectionItemDecorati override fun getItemId(parent: RecyclerView, child: View): Long { val holder = parent.getChildViewHolder(child) ?: return NO_ID - val item = holder.getItem() ?: return NO_ID + val item = holder.getItem(MangaItemModel::class.java) ?: return NO_ID return item.id } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index ddaa63b5e..5a9721124 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -14,7 +14,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.utils.ext.doOnCurrentItemChanged import org.koitharu.kotatsu.utils.ext.findCenterViewPosition -import org.koitharu.kotatsu.utils.ext.firstItem +import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition import org.koitharu.kotatsu.utils.ext.viewLifecycleScope class WebtoonReaderFragment : BaseReader() { @@ -52,7 +52,7 @@ class WebtoonReaderFragment : BaseReader() { setItems.await() ?: return@launchWhenCreated if (position != -1) { with(binding.recyclerView) { - firstItem = position + firstVisibleItemPosition = position post { (findViewHolderForAdapterPosition(position) as? WebtoonHolder) ?.restoreScroll(pendingState.scroll) @@ -91,6 +91,6 @@ class WebtoonReaderFragment : BaseReader() { } override fun switchPageTo(position: Int, smooth: Boolean) { - binding.recyclerView.firstItem = position + binding.recyclerView.firstVisibleItemPosition = position } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionItemCallback.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionItemCallback.kt index 64e53dc6b..7c65c7c42 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionItemCallback.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/suggestion/SearchSuggestionItemCallback.kt @@ -31,7 +31,7 @@ class SearchSuggestionItemCallback( ): Boolean = false override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - val item = viewHolder.getItem() ?: return + val item = viewHolder.getItem(SearchSuggestionItem.RecentQuery::class.java) ?: return listener.onRemoveQuery(item.query) } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt index aca880ea1..36031ec21 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/AppearanceSettingsFragment.kt @@ -25,9 +25,10 @@ class AppearanceSettingsFragment : override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_appearance) findPreference(AppSettings.KEY_GRID_SIZE)?.run { - summary = "%d%%".format(value) + val pattern = context.getString(R.string.percent_string_pattern) + summary = pattern.format(value.toString()) setOnPreferenceChangeListener { preference, newValue -> - preference.summary = "%d%%".format(newValue) + preference.summary = pattern.format(newValue.toString()) true } } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsModule.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsModule.kt index 6d9f543c4..e8e7f97ae 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsModule.kt @@ -18,7 +18,7 @@ val settingsModule single { BackupRepository(get()) } single { RestoreRepository(get()) } - single { AppSettings(androidContext()) } + single(createdAtStart = true) { AppSettings(androidContext()) } viewModel { BackupViewModel(get(), androidContext()) } viewModel { params -> diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/BottomSheetToolbarController.kt b/app/src/main/java/org/koitharu/kotatsu/utils/BottomSheetToolbarController.kt index 9a703ffd7..17d62d3a3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/BottomSheetToolbarController.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/BottomSheetToolbarController.kt @@ -2,8 +2,8 @@ package org.koitharu.kotatsu.utils import android.view.View import androidx.appcompat.widget.Toolbar -import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.R as materialR +import com.google.android.material.bottomsheet.BottomSheetBehavior open class BottomSheetToolbarController( protected val toolbar: Toolbar, @@ -17,7 +17,5 @@ open class BottomSheetToolbarController( } } - override fun onSlide(bottomSheet: View, slideOffset: Float) { - - } + override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt b/app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt index f06200dbd..cb558edfe 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/FileSize.kt @@ -32,4 +32,4 @@ enum class FileSize(private val multiplier: Int) { } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/GridTouchHelper.kt b/app/src/main/java/org/koitharu/kotatsu/utils/GridTouchHelper.kt index 86c6cccf0..13ccd3fa7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/GridTouchHelper.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/GridTouchHelper.kt @@ -5,8 +5,10 @@ import android.view.GestureDetector import android.view.MotionEvent import kotlin.math.roundToInt -class GridTouchHelper(context: Context, private val listener: OnGridTouchListener) : - GestureDetector.SimpleOnGestureListener() { +class GridTouchHelper( + context: Context, + private val listener: OnGridTouchListener +) : GestureDetector.SimpleOnGestureListener() { private val detector = GestureDetector(context, this) private val width = context.resources.displayMetrics.widthPixels diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/SelectionController.kt b/app/src/main/java/org/koitharu/kotatsu/utils/SelectionController.kt deleted file mode 100644 index f3274af2e..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/SelectionController.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.koitharu.kotatsu.utils - -import kotlinx.coroutines.flow.MutableStateFlow - -class SelectionController { - - private val state = MutableStateFlow(emptySet()) - - -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/WordSet.kt b/app/src/main/java/org/koitharu/kotatsu/utils/WordSet.kt deleted file mode 100644 index 214c934dd..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/WordSet.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.koitharu.kotatsu.utils - -class WordSet(private vararg val words: String) { - - fun anyWordIn(dateString: String): Boolean = words.any { - dateString.contains(it, ignoreCase = true) - } - -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt index 67ca43114..dc6974749 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt @@ -1,16 +1,14 @@ package org.koitharu.kotatsu.utils.ext import android.content.res.Resources -import android.util.Log -import java.io.FileNotFoundException -import java.net.SocketTimeoutException import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import org.koitharu.kotatsu.core.exceptions.WrongPasswordException import org.koitharu.kotatsu.parsers.exception.AuthRequiredException -import org.koitharu.kotatsu.parsers.util.format +import java.io.FileNotFoundException +import java.net.SocketTimeoutException fun Throwable.getDisplayMessage(resources: Resources) = when (this) { is AuthRequiredException -> resources.getString(R.string.auth_required) @@ -22,12 +20,4 @@ fun Throwable.getDisplayMessage(resources: Resources) = when (this) { is SocketTimeoutException -> resources.getString(R.string.network_error) is WrongPasswordException -> resources.getString(R.string.wrong_password) else -> localizedMessage ?: resources.getString(R.string.error_occurred) -} - -inline fun measured(tag: String, block: () -> T): T { - val time = System.currentTimeMillis() - val res = block() - val spent = System.currentTimeMillis() - time - Log.d("measured", "$tag ${spent.format(1)} ms") - return res } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt index 40f1268b9..412ead77c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt @@ -3,10 +3,8 @@ package org.koitharu.kotatsu.utils.ext import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineExceptionHandler import org.koitharu.kotatsu.BuildConfig -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext val IgnoreErrors get() = CoroutineExceptionHandler { _, e -> diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/DateExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/DateExt.kt index 89a076473..0cc08fd55 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/DateExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/DateExt.kt @@ -15,6 +15,6 @@ fun Date.formatRelative(minResolution: Long): CharSequence = DateUtils.getRelati fun Date.daysDiff(other: Long): Int { val thisDay = time / TimeUnit.DAYS.toMillis(1L) - val otherDay = other/ TimeUnit.DAYS.toMillis(1L) + val otherDay = other / TimeUnit.DAYS.toMillis(1L) return (thisDay - otherDay).toInt() } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt index cae599f8a..d881d3b1d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt @@ -26,11 +26,12 @@ fun Fragment.parcelableArgument(name: String): Lazy { } } -inline fun Fragment.serializableArgument(name: String): Lazy { +fun Fragment.serializableArgument(name: String): Lazy { return lazy(LazyThreadSafetyMode.NONE) { - requireNotNull(arguments?.getSerializable(name) as? T) { + @Suppress("UNCHECKED_CAST") + requireNotNull(arguments?.getSerializable(name)) { "No argument $name passed into ${javaClass.simpleName}" - } + } as T } } diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt index 03123c692..ad1fe8b39 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/LiveDataExt.kt @@ -4,10 +4,10 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.lifecycle.liveData -import kotlinx.coroutines.flow.Flow -import org.koitharu.kotatsu.utils.BufferedObserver import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext +import kotlinx.coroutines.flow.Flow +import org.koitharu.kotatsu.utils.BufferedObserver fun LiveData.observeNotNull(owner: LifecycleOwner, observer: Observer) { this.observe(owner) { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/PreferencesExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/PreferencesExt.kt index 2bbdd6498..d20c1eca6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/PreferencesExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/PreferencesExt.kt @@ -9,17 +9,17 @@ fun ListPreference.setDefaultValueCompat(defaultValue: String) { } } -fun > SharedPreferences.getEnumValue(key: String, enumClass: Class): E? { +fun > SharedPreferences.getEnumValue(key: String, enumClass: Class): E? { val stringValue = getString(key, null) ?: return null return enumClass.enumConstants?.find { it.name == stringValue } } -fun > SharedPreferences.getEnumValue(key: String, defaultValue: E): E { +fun > SharedPreferences.getEnumValue(key: String, defaultValue: E): E { return getEnumValue(key, defaultValue.javaClass) ?: defaultValue } -fun > SharedPreferences.Editor.putEnumValue(key: String, value: E?) { +fun > SharedPreferences.Editor.putEnumValue(key: String, value: E?) { putString(key, value?.name) } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt index 59620f2b0..bca90a845 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt @@ -5,12 +5,11 @@ import android.view.View import android.widget.TextView import androidx.annotation.AttrRes import androidx.annotation.StringRes -import androidx.core.content.res.use import androidx.core.view.isGone var TextView.textAndVisible: CharSequence? - inline get() = text?.takeIf { visibility == View.VISIBLE } - inline set(value) { + get() = text?.takeIf { visibility == View.VISIBLE } + set(value) { text = value isGone = value.isNullOrEmpty() } @@ -40,8 +39,5 @@ fun TextView.setTextAndVisible(@StringRes textResId: Int) { } fun TextView.setTextColorAttr(@AttrRes attrResId: Int) { - val colors = context.obtainStyledAttributes(intArrayOf(attrResId)).use { - it.getColorStateList(0) - } - setTextColor(colors) + setTextColor(context.getThemeColorStateList(attrResId)) } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ThemeExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ThemeExt.kt index 795fd3979..85ee5ea39 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ThemeExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ThemeExt.kt @@ -4,20 +4,24 @@ import android.content.Context import android.graphics.Color import androidx.annotation.AttrRes import androidx.annotation.ColorInt -import androidx.annotation.Px import androidx.core.content.res.use -@Px -fun Context.getThemeDimen(@AttrRes resId: Int) = obtainStyledAttributes(intArrayOf(resId)).use { - it.getDimension(0, 0f) -} - -fun Context.getThemeDrawable(@AttrRes resId: Int) = obtainStyledAttributes(intArrayOf(resId)).use { +fun Context.getThemeDrawable( + @AttrRes resId: Int, +) = obtainStyledAttributes(intArrayOf(resId)).use { it.getDrawable(0) } @ColorInt -fun Context.getThemeColor(@AttrRes resId: Int, @ColorInt default: Int = Color.TRANSPARENT) = - obtainStyledAttributes(intArrayOf(resId)).use { - it.getColor(0, default) - } \ No newline at end of file +fun Context.getThemeColor( + @AttrRes resId: Int, + @ColorInt default: Int = Color.TRANSPARENT +) = obtainStyledAttributes(intArrayOf(resId)).use { + it.getColor(0, default) +} + +fun Context.getThemeColorStateList( + @AttrRes resId: Int, +) = obtainStyledAttributes(intArrayOf(resId)).use { + it.getColorStateList(0) +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt index c52d50290..021c77859 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt @@ -2,20 +2,15 @@ package org.koitharu.kotatsu.utils.ext import android.app.Activity import android.graphics.Rect -import android.view.LayoutInflater -import android.view.Menu import android.view.View -import android.view.ViewGroup import android.view.inputmethod.InputMethodManager -import androidx.annotation.LayoutRes -import androidx.annotation.MenuRes -import androidx.appcompat.widget.PopupMenu import androidx.core.view.children import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.slider.Slider import com.hannesdorfmann.adapterdelegates4.dsl.AdapterDelegateViewBindingViewHolder +import com.hannesdorfmann.adapterdelegates4.dsl.AdapterDelegateViewHolder import kotlin.math.roundToInt fun View.hideKeyboard() { @@ -28,19 +23,15 @@ fun View.showKeyboard() { imm.showSoftInput(this, 0) } -inline fun ViewGroup.inflate(@LayoutRes resId: Int) = - LayoutInflater.from(context).inflate(resId, this, false) as T - -val RecyclerView.hasItems: Boolean - get() = (adapter?.itemCount ?: 0) > 0 - fun RecyclerView.clearItemDecorations() { + suppressLayout(true) while (itemDecorationCount > 0) { removeItemDecorationAt(0) } + suppressLayout(false) } -var RecyclerView.firstItem: Int +var RecyclerView.firstVisibleItemPosition: Int get() = (layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition() ?: RecyclerView.NO_POSITION set(value) { @@ -49,18 +40,6 @@ var RecyclerView.firstItem: Int } } -inline fun View.showPopupMenu( - @MenuRes menuRes: Int, - onPrepare: (Menu) -> Unit = {}, - onItemClick: PopupMenu.OnMenuItemClickListener, -) { - val menu = PopupMenu(context, this) - menu.inflate(menuRes) - menu.setOnMenuItemClickListener(onItemClick) - onPrepare(menu.menu) - menu.show() -} - fun View.hasGlobalPoint(x: Int, y: Int): Boolean { if (visibility != View.VISIBLE) { return false @@ -97,7 +76,7 @@ inline fun ViewPager2.doOnPageChanged(crossinline callback: (Int) -> Unit) { } val ViewPager2.recyclerView: RecyclerView? - inline get() = children.find { it is RecyclerView } as? RecyclerView + get() = children.firstNotNullOfOrNull { it as? RecyclerView } fun View.resetTransformations() { alpha = 1f @@ -106,6 +85,7 @@ fun View.resetTransformations() { translationZ = 0f scaleX = 1f scaleY = 1f + rotation = 0f rotationX = 0f rotationY = 0f } @@ -133,8 +113,17 @@ fun RecyclerView.findCenterViewPosition(): Int { return getChildAdapterPosition(view) } -inline fun RecyclerView.ViewHolder.getItem(): T? { - return ((this as? AdapterDelegateViewBindingViewHolder<*, *>)?.item as? T) +fun RecyclerView.ViewHolder.getItem(clazz: Class): T? { + val rawItem = when (this) { + is AdapterDelegateViewBindingViewHolder<*, *> -> item + is AdapterDelegateViewHolder<*> -> item + else -> null + } ?: return null + return if (clazz.isAssignableFrom(rawItem.javaClass)) { + clazz.cast(rawItem) + } else { + null + } } fun Slider.setValueRounded(newValue: Float) { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/progress/IntPercentLabelFormatter.kt b/app/src/main/java/org/koitharu/kotatsu/utils/progress/IntPercentLabelFormatter.kt index ed9773c99..5456ae5b0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/progress/IntPercentLabelFormatter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/progress/IntPercentLabelFormatter.kt @@ -1,7 +1,12 @@ package org.koitharu.kotatsu.utils.progress +import android.content.Context import com.google.android.material.slider.LabelFormatter +import org.koitharu.kotatsu.R -class IntPercentLabelFormatter : LabelFormatter { - override fun getFormattedValue(value: Float) = "%d%%".format(value.toInt()) +class IntPercentLabelFormatter(context: Context) : LabelFormatter { + + private val pattern = context.getString(R.string.percent_string_pattern) + + override fun getFormattedValue(value: Float) = pattern.format(value.toInt().toString()) } \ No newline at end of file