Got rid of AssistedInject for ViewModels
This commit is contained in:
@@ -3,6 +3,8 @@ package org.koitharu.kotatsu.base.domain
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.utils.ext.getParcelableCompat
|
||||
@@ -20,6 +22,12 @@ class MangaIntent private constructor(
|
||||
uri = intent?.data,
|
||||
)
|
||||
|
||||
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||
manga = savedStateHandle.get<ParcelableManga>(KEY_MANGA)?.manga,
|
||||
mangaId = savedStateHandle[KEY_ID] ?: ID_NONE,
|
||||
uri = savedStateHandle[BaseActivity.EXTRA_DATA],
|
||||
)
|
||||
|
||||
constructor(args: Bundle?) : this(
|
||||
manga = args?.getParcelableCompat<ParcelableManga>(KEY_MANGA)?.manga,
|
||||
mangaId = args?.getLong(KEY_ID, ID_NONE) ?: ID_NONE,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -59,6 +60,12 @@ abstract class BaseActivity<B : ViewBinding> :
|
||||
super.onCreate(savedInstanceState)
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
insetsDelegate.handleImeInsets = true
|
||||
putDataToExtras(intent)
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
putDataToExtras(intent)
|
||||
super.onNewIntent(intent)
|
||||
}
|
||||
|
||||
@Deprecated("Use ViewBinding", level = DeprecationLevel.ERROR)
|
||||
@@ -144,4 +151,13 @@ abstract class BaseActivity<B : ViewBinding> :
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun putDataToExtras(intent: Intent?) {
|
||||
intent?.putExtra(EXTRA_DATA, intent.data)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val EXTRA_DATA = "data"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.koitharu.kotatsu.base.ui.util
|
||||
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
|
||||
interface DefaultTextWatcher : TextWatcher {
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
|
||||
|
||||
override fun afterTextChanged(s: Editable?) = Unit
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import androidx.annotation.AnyThread
|
||||
import org.koitharu.kotatsu.core.cache.ContentCache
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
@@ -42,6 +43,7 @@ interface MangaRepository {
|
||||
|
||||
private val cache = EnumMap<MangaSource, WeakReference<RemoteMangaRepository>>(MangaSource::class.java)
|
||||
|
||||
@AnyThread
|
||||
fun create(source: MangaSource): MangaRepository {
|
||||
if (source == MangaSource.LOCAL) {
|
||||
return localMangaRepository
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isGone
|
||||
@@ -42,7 +43,6 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
import org.koitharu.kotatsu.utils.ViewBadge
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.setNavigationBarTransparentCompat
|
||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||
@@ -58,17 +58,12 @@ class DetailsActivity :
|
||||
override val bsHeader: BottomSheetHeaderBar?
|
||||
get() = binding.headerChapters
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: DetailsViewModel.Factory
|
||||
|
||||
@Inject
|
||||
lateinit var shortcutsUpdater: ShortcutsUpdater
|
||||
|
||||
private lateinit var viewBadge: ViewBadge
|
||||
|
||||
private val viewModel: DetailsViewModel by assistedViewModels {
|
||||
viewModelFactory.create(MangaIntent(intent))
|
||||
}
|
||||
private val viewModel: DetailsViewModel by viewModels()
|
||||
private lateinit var chaptersMenuProvider: ChaptersMenuProvider
|
||||
|
||||
private val downloadReceiver = object : BroadcastReceiver() {
|
||||
|
||||
@@ -7,12 +7,11 @@ import android.text.style.ForegroundColorSpan
|
||||
import androidx.core.text.getSpans
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -55,9 +54,11 @@ import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class DetailsViewModel @AssistedInject constructor(
|
||||
@Assisted intent: MangaIntent,
|
||||
@HiltViewModel
|
||||
class DetailsViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val historyRepository: HistoryRepository,
|
||||
favouritesRepository: FavouritesRepository,
|
||||
private val localMangaRepository: LocalMangaRepository,
|
||||
@@ -71,7 +72,7 @@ class DetailsViewModel @AssistedInject constructor(
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val delegate = MangaDetailsDelegate(
|
||||
intent = intent,
|
||||
intent = MangaIntent(savedStateHandle),
|
||||
mangaDataRepository = mangaDataRepository,
|
||||
historyRepository = historyRepository,
|
||||
localMangaRepository = localMangaRepository,
|
||||
@@ -321,10 +322,4 @@ class DetailsViewModel @AssistedInject constructor(
|
||||
}
|
||||
return scrobbler
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(intent: MangaIntent): DetailsViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,43 +4,37 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Filter
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import com.google.android.material.R as materialR
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.util.DefaultTextWatcher
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.ui.titleRes
|
||||
import org.koitharu.kotatsu.databinding.ActivityCategoryEditBinding
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.getSerializableCompat
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FavouritesCategoryEditActivity :
|
||||
BaseActivity<ActivityCategoryEditBinding>(),
|
||||
AdapterView.OnItemClickListener,
|
||||
View.OnClickListener,
|
||||
TextWatcher {
|
||||
DefaultTextWatcher {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: FavouritesCategoryEditViewModel.Factory
|
||||
|
||||
private val viewModel by assistedViewModels<FavouritesCategoryEditViewModel> {
|
||||
viewModelFactory.create(intent.getLongExtra(EXTRA_ID, NO_ID))
|
||||
}
|
||||
private val viewModel by viewModels<FavouritesCategoryEditViewModel>()
|
||||
private var selectedSortOrder: SortOrder? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -87,10 +81,6 @@ class FavouritesCategoryEditActivity :
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
binding.buttonDone.isEnabled = !s.isNullOrBlank()
|
||||
}
|
||||
@@ -167,9 +157,9 @@ class FavouritesCategoryEditActivity :
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_ID = "id"
|
||||
const val EXTRA_ID = "id"
|
||||
const val NO_ID = -1L
|
||||
private const val KEY_SORT_ORDER = "sort"
|
||||
private const val NO_ID = -1L
|
||||
|
||||
fun newIntent(context: Context, id: Long = NO_ID): Intent {
|
||||
return Intent(context, FavouritesCategoryEditActivity::class.java)
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.edit
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity.Companion.EXTRA_ID
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity.Companion.NO_ID
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val NO_ID = -1L
|
||||
|
||||
class FavouritesCategoryEditViewModel @AssistedInject constructor(
|
||||
@Assisted private val categoryId: Long,
|
||||
@HiltViewModel
|
||||
class FavouritesCategoryEditViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val repository: FavouritesRepository,
|
||||
private val settings: AppSettings,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val categoryId = savedStateHandle[EXTRA_ID] ?: NO_ID
|
||||
|
||||
val onSaved = SingleLiveEvent<Unit>()
|
||||
val category = MutableLiveData<FavouriteCategory?>()
|
||||
|
||||
@@ -30,12 +33,14 @@ class FavouritesCategoryEditViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
init {
|
||||
launchLoadingJob {
|
||||
category.value = if (categoryId != NO_ID) {
|
||||
repository.getCategory(categoryId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
category.postValue(
|
||||
if (categoryId != NO_ID) {
|
||||
repository.getCategory(categoryId)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,20 +49,14 @@ class FavouritesCategoryEditViewModel @AssistedInject constructor(
|
||||
sortOrder: SortOrder,
|
||||
isTrackerEnabled: Boolean,
|
||||
) {
|
||||
launchLoadingJob {
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
check(title.isNotEmpty())
|
||||
if (categoryId == NO_ID) {
|
||||
repository.createCategory(title, sortOrder, isTrackerEnabled)
|
||||
} else {
|
||||
repository.updateCategory(categoryId, title, sortOrder, isTrackerEnabled)
|
||||
}
|
||||
onSaved.call(Unit)
|
||||
onSaved.postCall(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(categoryId: Long): FavouritesCategoryEditViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
@@ -19,7 +19,6 @@ import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEdit
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.adapter.MangaCategoriesAdapter
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
@@ -30,14 +29,7 @@ class FavouriteCategoriesBottomSheet :
|
||||
View.OnClickListener,
|
||||
Toolbar.OnMenuItemClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: MangaCategoriesViewModel.Factory
|
||||
|
||||
private val viewModel: MangaCategoriesViewModel by assistedViewModels {
|
||||
viewModelFactory.create(
|
||||
requireNotNull(arguments?.getParcelableArrayList<ParcelableManga>(KEY_MANGA_LIST)).map { it.manga },
|
||||
)
|
||||
}
|
||||
private val viewModel: MangaCategoriesViewModel by viewModels()
|
||||
|
||||
private var adapter: MangaCategoriesAdapter? = null
|
||||
|
||||
@@ -91,7 +83,7 @@ class FavouriteCategoriesBottomSheet :
|
||||
companion object {
|
||||
|
||||
private const val TAG = "FavouriteCategoriesDialog"
|
||||
private const val KEY_MANGA_LIST = "manga_list"
|
||||
const val KEY_MANGA_LIST = "manga_list"
|
||||
|
||||
fun show(fm: FragmentManager, manga: Manga) = Companion.show(fm, listOf(manga))
|
||||
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.ids
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet.Companion.KEY_MANGA_LIST
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import javax.inject.Inject
|
||||
|
||||
class MangaCategoriesViewModel @AssistedInject constructor(
|
||||
@Assisted private val manga: List<Manga>,
|
||||
@HiltViewModel
|
||||
class MangaCategoriesViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val favouritesRepository: FavouritesRepository,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val manga = requireNotNull(savedStateHandle.get<List<ParcelableManga>>(KEY_MANGA_LIST)).map { it.manga }
|
||||
|
||||
val content = combine(
|
||||
favouritesRepository.observeCategories(),
|
||||
observeCategoriesIds(),
|
||||
@@ -61,10 +65,4 @@ class MangaCategoriesViewModel @AssistedInject constructor(
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(manga: List<Manga>): MangaCategoriesViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.ListSelectionController
|
||||
@@ -14,20 +15,12 @@ import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.addMenuProvider
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: FavouritesListViewModel.Factory
|
||||
|
||||
override val viewModel by assistedViewModels { viewModelFactory.create(categoryId) }
|
||||
|
||||
private val categoryId: Long
|
||||
get() = arguments?.getLong(ARG_CATEGORY_ID) ?: NO_ID
|
||||
override val viewModel by viewModels<FavouritesListViewModel>()
|
||||
|
||||
override val isSwipeRefreshEnabled = false
|
||||
|
||||
@@ -83,7 +76,7 @@ class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickLis
|
||||
companion object {
|
||||
|
||||
const val NO_ID = 0L
|
||||
private const val ARG_CATEGORY_ID = "category_id"
|
||||
const val ARG_CATEGORY_ID = "category_id"
|
||||
|
||||
fun newInstance(categoryId: Long) = FavouritesListFragment().withArgs(1) {
|
||||
putLong(ARG_CATEGORY_ID, categoryId)
|
||||
|
||||
@@ -2,10 +2,9 @@ package org.koitharu.kotatsu.favourites.ui.list
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.combine
|
||||
@@ -16,6 +15,7 @@ import org.koitharu.kotatsu.base.ui.util.ReversibleAction
|
||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.ARG_CATEGORY_ID
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
|
||||
@@ -30,9 +30,11 @@ import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||
import org.koitharu.kotatsu.utils.asFlowLiveData
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
|
||||
import javax.inject.Inject
|
||||
|
||||
class FavouritesListViewModel @AssistedInject constructor(
|
||||
@Assisted val categoryId: Long,
|
||||
@HiltViewModel
|
||||
class FavouritesListViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val repository: FavouritesRepository,
|
||||
private val trackingRepository: TrackingRepository,
|
||||
private val historyRepository: HistoryRepository,
|
||||
@@ -40,6 +42,8 @@ class FavouritesListViewModel @AssistedInject constructor(
|
||||
private val tagHighlighter: MangaTagHighlighter,
|
||||
) : MangaListViewModel(settings), ListExtraProvider {
|
||||
|
||||
val categoryId: Long = savedStateHandle[ARG_CATEGORY_ID] ?: NO_ID
|
||||
|
||||
var categoryName: String? = null
|
||||
private set
|
||||
|
||||
@@ -133,10 +137,4 @@ class FavouritesListViewModel @AssistedInject constructor(
|
||||
PROGRESS_NONE
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(categoryId: Long): FavouritesListViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.OnApplyWindowInsetsListener
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
@@ -48,14 +49,11 @@ import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
import org.koitharu.kotatsu.utils.GridTouchHelper
|
||||
import org.koitharu.kotatsu.utils.IdlingDetector
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat
|
||||
import org.koitharu.kotatsu.utils.ext.hasGlobalPoint
|
||||
import org.koitharu.kotatsu.utils.ext.observeWithPrevious
|
||||
import org.koitharu.kotatsu.utils.ext.postDelayed
|
||||
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ReaderActivity :
|
||||
@@ -68,18 +66,9 @@ class ReaderActivity :
|
||||
OnApplyWindowInsetsListener,
|
||||
IdlingDetector.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ReaderViewModel.Factory
|
||||
|
||||
private val idlingDetector = IdlingDetector(TimeUnit.SECONDS.toMillis(10), this)
|
||||
|
||||
val viewModel by assistedViewModels {
|
||||
viewModelFactory.create(
|
||||
intent = MangaIntent(intent),
|
||||
initialState = intent?.getParcelableExtraCompat(EXTRA_STATE),
|
||||
preselectedBranch = intent?.getStringExtra(EXTRA_BRANCH),
|
||||
)
|
||||
}
|
||||
private val viewModel: ReaderViewModel by viewModels()
|
||||
|
||||
override var pageSwitchDelay: Float
|
||||
get() = pageSwitchTimer.delaySec
|
||||
@@ -392,8 +381,8 @@ class ReaderActivity :
|
||||
companion object {
|
||||
|
||||
const val ACTION_MANGA_READ = "${BuildConfig.APPLICATION_ID}.action.READ_MANGA"
|
||||
private const val EXTRA_STATE = "state"
|
||||
private const val EXTRA_BRANCH = "branch"
|
||||
const val EXTRA_STATE = "state"
|
||||
const val EXTRA_BRANCH = "branch"
|
||||
private const val TOAST_DURATION = 1500L
|
||||
|
||||
fun newIntent(context: Context, manga: Manga): Intent {
|
||||
|
||||
@@ -6,10 +6,9 @@ import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -56,15 +55,15 @@ import org.koitharu.kotatsu.utils.ext.processLifecycleScope
|
||||
import org.koitharu.kotatsu.utils.ext.requireValue
|
||||
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
private const val BOUNDS_PAGE_OFFSET = 2
|
||||
private const val PREFETCH_LIMIT = 10
|
||||
|
||||
class ReaderViewModel @AssistedInject constructor(
|
||||
@Assisted private val intent: MangaIntent,
|
||||
@Assisted initialState: ReaderState?,
|
||||
@Assisted private val preselectedBranch: String?,
|
||||
@HiltViewModel
|
||||
class ReaderViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val dataRepository: MangaDataRepository,
|
||||
private val historyRepository: HistoryRepository,
|
||||
@@ -74,10 +73,13 @@ class ReaderViewModel @AssistedInject constructor(
|
||||
pageLoaderFactory: Provider<PageLoader>,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val intent = MangaIntent(savedStateHandle)
|
||||
private val preselectedBranch = savedStateHandle.get<String>(ReaderActivity.EXTRA_BRANCH)
|
||||
|
||||
private var loadingJob: Job? = null
|
||||
private var pageSaveJob: Job? = null
|
||||
private var bookmarkJob: Job? = null
|
||||
private val currentState = MutableStateFlow(initialState)
|
||||
private val currentState = MutableStateFlow<ReaderState?>(savedStateHandle[ReaderActivity.EXTRA_STATE])
|
||||
private val mangaData = MutableStateFlow(intent.manga)
|
||||
private val chapters: LongSparseArray<MangaChapter>
|
||||
get() = chaptersLoader.chapters
|
||||
@@ -393,16 +395,6 @@ class ReaderViewModel @AssistedInject constructor(
|
||||
val ppc = 1f / chaptersCount
|
||||
return ppc * chapterIndex + ppc * pagePercent
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(
|
||||
intent: MangaIntent,
|
||||
initialState: ReaderState?,
|
||||
preselectedBranch: String?,
|
||||
): ReaderViewModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
@@ -25,10 +26,8 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.util.format
|
||||
import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.decodeRegion
|
||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat
|
||||
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
||||
import javax.inject.Inject
|
||||
import com.google.android.material.R as materialR
|
||||
@@ -42,15 +41,7 @@ class ColorFilterConfigActivity :
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ColorFilterConfigViewModel.Factory
|
||||
|
||||
private val viewModel: ColorFilterConfigViewModel by assistedViewModels {
|
||||
viewModelFactory.create(
|
||||
manga = checkNotNull(intent.getParcelableExtraCompat<ParcelableManga>(EXTRA_MANGA)?.manga),
|
||||
page = checkNotNull(intent.getParcelableExtraCompat<ParcelableMangaPages>(EXTRA_PAGES)?.pages?.firstOrNull()),
|
||||
)
|
||||
}
|
||||
private val viewModel: ColorFilterConfigViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -144,8 +135,8 @@ class ColorFilterConfigActivity :
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_PAGES = "pages"
|
||||
private const val EXTRA_MANGA = "manga_id"
|
||||
const val EXTRA_PAGES = "pages"
|
||||
const val EXTRA_MANGA = "manga_id"
|
||||
|
||||
fun newIntent(context: Context, manga: Manga, page: MangaPage) =
|
||||
Intent(context, ColorFilterConfigActivity::class.java)
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
package org.koitharu.kotatsu.reader.ui.colorfilter
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaPages
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
|
||||
import org.koitharu.kotatsu.reader.ui.colorfilter.ColorFilterConfigActivity.Companion.EXTRA_MANGA
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import javax.inject.Inject
|
||||
|
||||
class ColorFilterConfigViewModel @AssistedInject constructor(
|
||||
@Assisted private val manga: Manga,
|
||||
@Assisted page: MangaPage,
|
||||
@HiltViewModel
|
||||
class ColorFilterConfigViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val mangaDataRepository: MangaDataRepository,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val manga = checkNotNull(savedStateHandle.get<ParcelableManga>(EXTRA_MANGA)?.manga)
|
||||
|
||||
private var initialColorFilter: ReaderColorFilter? = null
|
||||
val colorFilter = MutableLiveData<ReaderColorFilter?>(null)
|
||||
val onDismiss = SingleLiveEvent<Unit>()
|
||||
@@ -28,19 +33,24 @@ class ColorFilterConfigViewModel @AssistedInject constructor(
|
||||
get() = colorFilter.value != initialColorFilter
|
||||
|
||||
init {
|
||||
val page = checkNotNull(
|
||||
savedStateHandle.get<ParcelableMangaPages>(ColorFilterConfigActivity.EXTRA_PAGES)?.pages?.firstOrNull(),
|
||||
)
|
||||
launchLoadingJob {
|
||||
initialColorFilter = mangaDataRepository.getColorFilter(manga.id)
|
||||
colorFilter.value = initialColorFilter
|
||||
}
|
||||
launchLoadingJob {
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
val repository = mangaRepositoryFactory.create(page.source)
|
||||
val url = repository.getPageUrl(page)
|
||||
preview.value = MangaPage(
|
||||
id = page.id,
|
||||
url = url,
|
||||
referer = page.referer,
|
||||
preview = page.preview,
|
||||
source = page.source,
|
||||
preview.postValue(
|
||||
MangaPage(
|
||||
id = page.id,
|
||||
url = url,
|
||||
referer = page.referer,
|
||||
preview = page.preview,
|
||||
source = page.source,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -60,15 +70,9 @@ class ColorFilterConfigViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
fun save() {
|
||||
launchLoadingJob {
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
mangaDataRepository.saveColorFilter(manga, colorFilter.value)
|
||||
onDismiss.call(Unit)
|
||||
onDismiss.postCall(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(manga: Manga, page: MangaPage): ColorFilterConfigViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.viewModels
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import coil.ImageLoader
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
@@ -23,10 +22,13 @@ import org.koitharu.kotatsu.list.ui.MangaListSpanResolver
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.reader.domain.PageLoader
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderViewModel
|
||||
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter
|
||||
import org.koitharu.kotatsu.utils.ext.getParcelableCompat
|
||||
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PagesThumbnailsSheet :
|
||||
@@ -117,9 +119,9 @@ class PagesThumbnailsSheet :
|
||||
(parentFragment as? OnPageSelectListener)
|
||||
?: (activity as? OnPageSelectListener)
|
||||
)?.run {
|
||||
onPageSelected(item)
|
||||
dismiss()
|
||||
}
|
||||
onPageSelected(item)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onExpansionStateChanged(headerBar: BottomSheetHeaderBar, isExpanded: Boolean) {
|
||||
@@ -135,7 +137,7 @@ class PagesThumbnailsSheet :
|
||||
}
|
||||
|
||||
private fun getPageLoader(): PageLoader {
|
||||
val viewModel = (activity as? ReaderActivity)?.viewModel
|
||||
val viewModel = (activity as? ReaderActivity)?.viewModels<ReaderViewModel>()?.value
|
||||
return viewModel?.pageLoader ?: pageLoaderProvider.get().also { pageLoader = it }
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import android.view.View
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
@@ -19,21 +19,12 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.search.ui.SearchActivity
|
||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
import org.koitharu.kotatsu.utils.ext.addMenuProvider
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.serializableArgument
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RemoteListFragment : MangaListFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: RemoteListViewModel.Factory
|
||||
|
||||
public override val viewModel by assistedViewModels {
|
||||
viewModelFactory.create(source)
|
||||
}
|
||||
|
||||
private val source by serializableArgument<MangaSource>(ARG_SOURCE)
|
||||
public override val viewModel by viewModels<RemoteListViewModel>()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -74,13 +65,15 @@ class RemoteListFragment : MangaListFragment() {
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
|
||||
R.id.action_source_settings -> {
|
||||
startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), source))
|
||||
startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), viewModel.source))
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_filter -> {
|
||||
onFilterClick(null)
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
@@ -90,7 +83,7 @@ class RemoteListFragment : MangaListFragment() {
|
||||
}
|
||||
val intent = SearchActivity.newIntent(
|
||||
context = this@RemoteListFragment.context ?: return false,
|
||||
source = source,
|
||||
source = viewModel.source,
|
||||
query = query,
|
||||
)
|
||||
startActivity(intent)
|
||||
@@ -113,7 +106,7 @@ class RemoteListFragment : MangaListFragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_SOURCE = "provider"
|
||||
const val ARG_SOURCE = "provider"
|
||||
|
||||
fun newInstance(provider: MangaSource) = RemoteListFragment().withArgs(1) {
|
||||
putSerializable(ARG_SOURCE, provider)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.koitharu.kotatsu.remotelist.ui
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -40,12 +39,15 @@ import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.require
|
||||
import java.util.LinkedList
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val FILTER_MIN_INTERVAL = 250L
|
||||
|
||||
class RemoteListViewModel @AssistedInject constructor(
|
||||
@Assisted source: MangaSource,
|
||||
@HiltViewModel
|
||||
class RemoteListViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val searchRepository: MangaSearchRepository,
|
||||
settings: AppSettings,
|
||||
@@ -53,6 +55,7 @@ class RemoteListViewModel @AssistedInject constructor(
|
||||
private val tagHighlighter: MangaTagHighlighter,
|
||||
) : MangaListViewModel(settings), OnFilterChangedListener {
|
||||
|
||||
val source = savedStateHandle.require<MangaSource>(RemoteListFragment.ARG_SOURCE)
|
||||
private val repository = mangaRepositoryFactory.create(source) as RemoteMangaRepository
|
||||
private val filter = FilterCoordinator(repository, dataRepository, viewModelScope)
|
||||
private val mangaList = MutableStateFlow<List<Manga>?>(null)
|
||||
@@ -218,10 +221,4 @@ class RemoteListViewModel @AssistedInject constructor(
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(source: MangaSource): RemoteListViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
@@ -22,7 +23,6 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.config.adapter.ScrobblingMangaAdapter
|
||||
import org.koitharu.kotatsu.tracker.ui.feed.adapter.FeedAdapter
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.disposeImageRequest
|
||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.utils.ext.hideCompat
|
||||
@@ -34,15 +34,10 @@ import javax.inject.Inject
|
||||
class ScrobblerConfigActivity : BaseActivity<ActivityScrobblerConfigBinding>(),
|
||||
OnListItemClickListener<ScrobblingInfo>, View.OnClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ScrobblerConfigViewModel.Factory
|
||||
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
private val viewModel: ScrobblerConfigViewModel by assistedViewModels {
|
||||
viewModelFactory.create(requireNotNull(getScrobblerService(intent)))
|
||||
}
|
||||
private val viewModel: ScrobblerConfigViewModel by viewModels()
|
||||
|
||||
private var paddingVertical = 0
|
||||
private var paddingHorizontal = 0
|
||||
@@ -150,30 +145,14 @@ class ScrobblerConfigActivity : BaseActivity<ActivityScrobblerConfigBinding>(),
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_SERVICE_ID = "service"
|
||||
const val EXTRA_SERVICE_ID = "service"
|
||||
|
||||
private const val HOST_SHIKIMORI_AUTH = "shikimori-auth"
|
||||
private const val HOST_ANILIST_AUTH = "anilist-auth"
|
||||
private const val HOST_MAL_AUTH = "mal-auth"
|
||||
const val HOST_SHIKIMORI_AUTH = "shikimori-auth"
|
||||
const val HOST_ANILIST_AUTH = "anilist-auth"
|
||||
const val HOST_MAL_AUTH = "mal-auth"
|
||||
|
||||
fun newIntent(context: Context, service: ScrobblerService) =
|
||||
Intent(context, ScrobblerConfigActivity::class.java)
|
||||
.putExtra(EXTRA_SERVICE_ID, service.id)
|
||||
|
||||
private fun getScrobblerService(
|
||||
intent: Intent
|
||||
): ScrobblerService? {
|
||||
val serviceId = intent.getIntExtra(EXTRA_SERVICE_ID, 0)
|
||||
if (serviceId != 0) {
|
||||
return enumValues<ScrobblerService>().first { it.id == serviceId }
|
||||
}
|
||||
val uri = intent.data ?: return null
|
||||
return when (uri.host) {
|
||||
HOST_SHIKIMORI_AUTH -> ScrobblerService.SHIKIMORI
|
||||
HOST_ANILIST_AUTH -> ScrobblerService.ANILIST
|
||||
HOST_MAL_AUTH -> ScrobblerService.MAL
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.scrobbling.common.ui.config
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
@@ -24,12 +25,16 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.asFlowLiveData
|
||||
import org.koitharu.kotatsu.utils.ext.onFirst
|
||||
import org.koitharu.kotatsu.utils.ext.require
|
||||
import javax.inject.Inject
|
||||
|
||||
class ScrobblerConfigViewModel @AssistedInject constructor(
|
||||
@Assisted scrobblerService: ScrobblerService,
|
||||
@HiltViewModel
|
||||
class ScrobblerConfigViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val scrobblerService = getScrobblerService(savedStateHandle)
|
||||
private val scrobbler = scrobblers.first { it.scrobblerService == scrobblerService }
|
||||
|
||||
val titleResId = scrobbler.scrobblerService.titleResId
|
||||
@@ -90,9 +95,19 @@ class ScrobblerConfigViewModel @AssistedInject constructor(
|
||||
return result
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(service: ScrobblerService): ScrobblerConfigViewModel
|
||||
private fun getScrobblerService(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
): ScrobblerService {
|
||||
val serviceId = savedStateHandle.get<Int>(ScrobblerConfigActivity.EXTRA_SERVICE_ID) ?: 0
|
||||
if (serviceId != 0) {
|
||||
return enumValues<ScrobblerService>().first { it.id == serviceId }
|
||||
}
|
||||
val uri = savedStateHandle.require<Uri>(BaseActivity.EXTRA_DATA)
|
||||
return when (uri.host) {
|
||||
ScrobblerConfigActivity.HOST_SHIKIMORI_AUTH -> ScrobblerService.SHIKIMORI
|
||||
ScrobblerConfigActivity.HOST_ANILIST_AUTH -> ScrobblerService.ANILIST
|
||||
ScrobblerConfigActivity.HOST_MAL_AUTH -> ScrobblerService.MAL
|
||||
else -> error("Wrong scrobbler uri: $uri")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.widget.Toast
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.viewModels
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
@@ -26,10 +27,8 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerMangaSelectionDecoration
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerSelectorAdapter
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.requireParcelable
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -44,19 +43,12 @@ class ScrobblingSelectorBottomSheet :
|
||||
TabLayout.OnTabSelectedListener,
|
||||
ListStateHolderListener {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ScrobblingSelectorViewModel.Factory
|
||||
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
private var collapsibleActionViewCallback: CollapseActionViewCallback? = null
|
||||
|
||||
private val viewModel by assistedViewModels {
|
||||
viewModelFactory.create(
|
||||
requireArguments().requireParcelable<ParcelableManga>(MangaIntent.KEY_MANGA).manga,
|
||||
)
|
||||
}
|
||||
private val viewModel by viewModels<ScrobblingSelectorViewModel>()
|
||||
|
||||
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): SheetScrobblingSelectorBinding {
|
||||
return SheetScrobblingSelectorBinding.inflate(inflater, container, false)
|
||||
|
||||
@@ -2,21 +2,21 @@ package org.koitharu.kotatsu.scrobbling.common.ui.selector
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.recyclerview.widget.RecyclerView.NO_ID
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
|
||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
||||
@@ -24,13 +24,18 @@ import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.require
|
||||
import org.koitharu.kotatsu.utils.ext.requireValue
|
||||
import javax.inject.Inject
|
||||
|
||||
class ScrobblingSelectorViewModel @AssistedInject constructor(
|
||||
@Assisted val manga: Manga,
|
||||
@HiltViewModel
|
||||
class ScrobblingSelectorViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val manga = savedStateHandle.require<ParcelableManga>(MangaIntent.KEY_MANGA).manga
|
||||
|
||||
val availableScrobblers = scrobblers.filter { it.isAvailable }
|
||||
|
||||
val selectedScrobblerIndex = MutableLiveData(0)
|
||||
@@ -172,10 +177,4 @@ class ScrobblingSelectorViewModel @AssistedInject constructor(
|
||||
textSecondary = 0,
|
||||
actionStringRes = R.string.try_again,
|
||||
)
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(manga: Manga): ScrobblingSelectorViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,29 +2,18 @@ package org.koitharu.kotatsu.search.ui
|
||||
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.serializableArgument
|
||||
import org.koitharu.kotatsu.utils.ext.stringArgument
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SearchFragment : MangaListFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: SearchViewModel.Factory
|
||||
|
||||
override val viewModel by assistedViewModels {
|
||||
viewModelFactory.create(source, query.orEmpty())
|
||||
}
|
||||
|
||||
private val query by stringArgument(ARG_QUERY)
|
||||
private val source by serializableArgument<MangaSource>(ARG_SOURCE)
|
||||
override val viewModel by viewModels<SearchViewModel>()
|
||||
|
||||
override fun onScrolledToEnd() {
|
||||
viewModel.loadNextPage()
|
||||
@@ -37,8 +26,8 @@ class SearchFragment : MangaListFragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_QUERY = "query"
|
||||
private const val ARG_SOURCE = "source"
|
||||
const val ARG_QUERY = "query"
|
||||
const val ARG_SOURCE = "source"
|
||||
|
||||
fun newInstance(source: MangaSource, query: String) = SearchFragment().withArgs(2) {
|
||||
putSerializable(ARG_SOURCE, source)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package org.koitharu.kotatsu.search.ui
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -22,18 +21,20 @@ import org.koitharu.kotatsu.list.ui.model.toErrorFooter
|
||||
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
||||
import org.koitharu.kotatsu.list.ui.model.toUi
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.require
|
||||
import javax.inject.Inject
|
||||
|
||||
class SearchViewModel @AssistedInject constructor(
|
||||
@Assisted source: MangaSource,
|
||||
@Assisted private val query: String,
|
||||
@HiltViewModel
|
||||
class SearchViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
repositoryFactory: MangaRepository.Factory,
|
||||
settings: AppSettings,
|
||||
private val tagHighlighter: MangaTagHighlighter,
|
||||
) : MangaListViewModel(settings) {
|
||||
|
||||
private val repository = repositoryFactory.create(source)
|
||||
private val query = savedStateHandle.require<String>(SearchFragment.ARG_QUERY)
|
||||
private val repository = repositoryFactory.create(savedStateHandle.require(SearchFragment.ARG_SOURCE))
|
||||
private val mangaList = MutableStateFlow<List<Manga>?>(null)
|
||||
private val hasNextPage = MutableStateFlow(false)
|
||||
private val listError = MutableStateFlow<Throwable?>(null)
|
||||
@@ -111,10 +112,4 @@ class SearchViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(source: MangaSource, query: String): SearchViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.Insets
|
||||
@@ -31,7 +32,6 @@ import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||
import org.koitharu.kotatsu.search.ui.SearchActivity
|
||||
import org.koitharu.kotatsu.search.ui.multi.adapter.MultiSearchAdapter
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.invalidateNestedItemDecorations
|
||||
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
|
||||
import javax.inject.Inject
|
||||
@@ -40,17 +40,12 @@ import javax.inject.Inject
|
||||
class MultiSearchActivity :
|
||||
BaseActivity<ActivitySearchMultiBinding>(),
|
||||
MangaListListener,
|
||||
ListSelectionController.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: MultiSearchViewModel.Factory
|
||||
ListSelectionController.Callback2 {
|
||||
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
private val viewModel by assistedViewModels<MultiSearchViewModel> {
|
||||
viewModelFactory.create(intent.getStringExtra(EXTRA_QUERY).orEmpty())
|
||||
}
|
||||
private val viewModel by viewModels<MultiSearchViewModel>()
|
||||
private lateinit var adapter: MultiSearchAdapter
|
||||
private lateinit var selectionController: ListSelectionController
|
||||
|
||||
@@ -139,17 +134,16 @@ class MultiSearchActivity :
|
||||
|
||||
override fun onListHeaderClick(item: ListHeader, view: View) = Unit
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
|
||||
binding.recyclerView.invalidateNestedItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_remote, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.title = selectionController.count.toString()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_share -> {
|
||||
ShareHelper(this).shareMangaLinks(collectSelectedItems())
|
||||
@@ -173,17 +167,13 @@ class MultiSearchActivity :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSelectionChanged(count: Int) {
|
||||
binding.recyclerView.invalidateNestedItemDecorations()
|
||||
}
|
||||
|
||||
private fun collectSelectedItems(): Set<Manga> {
|
||||
return viewModel.getItems(selectionController.peekCheckedIds())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_QUERY = "query"
|
||||
const val EXTRA_QUERY = "query"
|
||||
|
||||
fun newIntent(context: Context, query: String) =
|
||||
Intent(context, MultiSearchActivity::class.java)
|
||||
|
||||
@@ -2,10 +2,9 @@ package org.koitharu.kotatsu.search.ui.multi
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -31,12 +30,14 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val MAX_PARALLELISM = 4
|
||||
private const val MIN_HAS_MORE_ITEMS = 8
|
||||
|
||||
class MultiSearchViewModel @AssistedInject constructor(
|
||||
@Assisted initialQuery: String,
|
||||
@HiltViewModel
|
||||
class MultiSearchViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val settings: AppSettings,
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
) : BaseViewModel() {
|
||||
@@ -46,7 +47,7 @@ class MultiSearchViewModel @AssistedInject constructor(
|
||||
private val loadingData = MutableStateFlow(false)
|
||||
private var listError = MutableStateFlow<Throwable?>(null)
|
||||
|
||||
val query = MutableLiveData(initialQuery)
|
||||
val query = MutableLiveData(savedStateHandle.get<String>(MultiSearchActivity.EXTRA_QUERY).orEmpty())
|
||||
val list: LiveData<List<ListModel>> = combine(
|
||||
listData,
|
||||
loadingData,
|
||||
@@ -72,7 +73,7 @@ class MultiSearchViewModel @AssistedInject constructor(
|
||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))
|
||||
|
||||
init {
|
||||
doSearch(initialQuery)
|
||||
doSearch(query.value.orEmpty())
|
||||
}
|
||||
|
||||
fun getItems(ids: Set<Long>): Set<Manga> {
|
||||
@@ -145,10 +146,4 @@ class MultiSearchViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(initialQuery: String): MultiSearchViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,28 +6,21 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||
import org.koitharu.kotatsu.core.backup.CompositeResult
|
||||
import org.koitharu.kotatsu.databinding.DialogProgressBinding
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.toUriOrNull
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
import org.koitharu.kotatsu.utils.progress.Progress
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RestoreDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: RestoreViewModel.Factory
|
||||
|
||||
private val viewModel by assistedViewModels {
|
||||
viewModelFactory.create(arguments?.getString(ARG_FILE)?.toUriOrNull())
|
||||
}
|
||||
private val viewModel: RestoreViewModel by viewModels()
|
||||
|
||||
override fun onInflateView(
|
||||
inflater: LayoutInflater,
|
||||
@@ -74,12 +67,14 @@ class RestoreDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
|
||||
when {
|
||||
result.isAllSuccess -> builder.setTitle(R.string.data_restored)
|
||||
.setMessage(R.string.data_restored_success)
|
||||
|
||||
result.isAllFailed -> builder.setTitle(R.string.error)
|
||||
.setMessage(
|
||||
result.failures.map {
|
||||
it.getDisplayMessage(resources)
|
||||
}.distinct().joinToString("\n"),
|
||||
)
|
||||
|
||||
else -> builder.setTitle(R.string.data_restored)
|
||||
.setMessage(R.string.data_restored_with_errors)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
package org.koitharu.kotatsu.settings.backup
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
@@ -18,10 +13,15 @@ import org.koitharu.kotatsu.core.backup.BackupRepository
|
||||
import org.koitharu.kotatsu.core.backup.BackupZipInput
|
||||
import org.koitharu.kotatsu.core.backup.CompositeResult
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.toUriOrNull
|
||||
import org.koitharu.kotatsu.utils.progress.Progress
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import javax.inject.Inject
|
||||
|
||||
class RestoreViewModel @AssistedInject constructor(
|
||||
@Assisted uri: Uri?,
|
||||
@HiltViewModel
|
||||
class RestoreViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val repository: BackupRepository,
|
||||
@ApplicationContext context: Context,
|
||||
) : BaseViewModel() {
|
||||
@@ -31,9 +31,8 @@ class RestoreViewModel @AssistedInject constructor(
|
||||
|
||||
init {
|
||||
launchLoadingJob {
|
||||
if (uri == null) {
|
||||
throw FileNotFoundException()
|
||||
}
|
||||
val uri = savedStateHandle.get<String>(RestoreDialogFragment.ARG_FILE)
|
||||
?.toUriOrNull() ?: throw FileNotFoundException()
|
||||
val contentResolver = context.contentResolver
|
||||
|
||||
val backup = runInterruptible(Dispatchers.IO) {
|
||||
@@ -65,10 +64,4 @@ class RestoreViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
fun create(uri: Uri?): RestoreViewModel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaTags
|
||||
import java.io.Serializable
|
||||
|
||||
@@ -47,3 +48,9 @@ inline fun <reified T : Parcelable> Bundle.requireParcelable(key: String): T {
|
||||
"Parcelable of type \"${T::class.java.name}\" not found at \"$key\""
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> SavedStateHandle.require(key: String): T {
|
||||
return checkNotNull(get(key)) {
|
||||
"Value $key not found in SavedStateHandle or has a wrong type"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
|
||||
val Fragment.viewLifecycleScope
|
||||
inline get() = viewLifecycleOwner.lifecycle.coroutineScope
|
||||
|
||||
@Deprecated("")
|
||||
fun <T : Serializable> Fragment.serializableArgument(name: String): Lazy<T> {
|
||||
return lazy(LazyThreadSafetyMode.NONE) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -32,6 +33,7 @@ fun <T : Serializable> Fragment.serializableArgument(name: String): Lazy<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("")
|
||||
fun Fragment.stringArgument(name: String) = lazy(LazyThreadSafetyMode.NONE) {
|
||||
arguments?.getString(name)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,12 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.createViewModelLazy
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.AbstractSavedStateViewModelFactory
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.CreationExtras
|
||||
|
||||
@Deprecated("Migrate to SavedStateHandle in vm")
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> ComponentActivity.assistedViewModels(
|
||||
noinline viewModelProducer: (SavedStateHandle) -> VM,
|
||||
): Lazy<VM> = viewModels {
|
||||
object : AbstractSavedStateViewModelFactory(this@assistedViewModels, intent.extras) {
|
||||
override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
|
||||
return requireNotNull(modelClass.cast(viewModelProducer(handle)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Migrate to SavedStateHandle in vm")
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> Fragment.assistedViewModels(
|
||||
noinline viewModelProducer: (SavedStateHandle) -> VM,
|
||||
): Lazy<VM> = viewModels {
|
||||
object : AbstractSavedStateViewModelFactory(this@assistedViewModels, arguments) {
|
||||
override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
|
||||
return requireNotNull(modelClass.cast(viewModelProducer(handle)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> Fragment.parentFragmentViewModels(
|
||||
noinline extrasProducer: (() -> CreationExtras)? = null,
|
||||
|
||||
Reference in New Issue
Block a user