Migrate to MVVM
This commit is contained in:
@@ -84,17 +84,12 @@ dependencies {
|
||||
implementation 'androidx.room:room-ktx:2.2.5'
|
||||
kapt 'androidx.room:room-compiler:2.2.5'
|
||||
|
||||
implementation 'com.github.moxy-community:moxy:2.2.0'
|
||||
implementation 'com.github.moxy-community:moxy-androidx:2.2.0'
|
||||
implementation 'com.github.moxy-community:moxy-material:2.2.0'
|
||||
implementation 'com.github.moxy-community:moxy-ktx:2.2.0'
|
||||
kapt 'com.github.moxy-community:moxy-compiler:2.2.0'
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
|
||||
implementation 'com.squareup.okio:okio:2.9.0'
|
||||
implementation 'org.jsoup:jsoup:1.13.1'
|
||||
|
||||
implementation 'org.koin:koin-android:2.2.0'
|
||||
implementation 'org.koin:koin-android-viewmodel:2.2.0'
|
||||
implementation 'io.coil-kt:coil-base:1.0.0'
|
||||
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'
|
||||
implementation 'com.tomclaw.cache:cache:1.0'
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
android:theme="@style/AppTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<activity android:name=".ui.list.MainActivity">
|
||||
<activity android:name="org.koitharu.kotatsu.main.ui.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -32,62 +32,62 @@
|
||||
android:name="android.app.default_searchable"
|
||||
android:value=".ui.search.SearchActivity" />
|
||||
</activity>
|
||||
<activity android:name=".ui.details.MangaDetailsActivity">
|
||||
<activity android:name="org.koitharu.kotatsu.details.ui.DetailsActivity">
|
||||
<intent-filter>
|
||||
<action android:name="${applicationId}.action.VIEW_MANGA" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.reader.ReaderActivity" />
|
||||
<activity android:name="org.koitharu.kotatsu.reader.ui.ReaderActivity" />
|
||||
<activity
|
||||
android:name=".ui.search.SearchActivity"
|
||||
android:name="org.koitharu.kotatsu.search.ui.SearchActivity"
|
||||
android:label="@string/search" />
|
||||
<activity
|
||||
android:name=".ui.settings.SettingsActivity"
|
||||
android:name="org.koitharu.kotatsu.settings.SettingsActivity"
|
||||
android:label="@string/settings" />
|
||||
<activity
|
||||
android:name=".ui.reader.SimpleSettingsActivity"
|
||||
android:name="org.koitharu.kotatsu.reader.ui.SimpleSettingsActivity"
|
||||
android:label="@string/settings">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.browser.BrowserActivity" />
|
||||
<activity android:name="org.koitharu.kotatsu.browser.BrowserActivity" />
|
||||
<activity
|
||||
android:name=".ui.utils.CrashActivity"
|
||||
android:name="org.koitharu.kotatsu.core.ui.CrashActivity"
|
||||
android:label="@string/error_occurred"
|
||||
android:theme="@android:style/Theme.DeviceDefault"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.ui.list.favourites.categories.CategoriesActivity"
|
||||
android:name="org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity"
|
||||
android:label="@string/favourites_categories"
|
||||
android:windowSoftInputMode="stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".ui.widget.shelf.ShelfConfigActivity"
|
||||
android:name="org.koitharu.kotatsu.widget.shelf.ShelfConfigActivity"
|
||||
android:label="@string/manga_shelf">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.search.global.GlobalSearchActivity"
|
||||
android:name="org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity"
|
||||
android:label="@string/search" />
|
||||
<activity
|
||||
android:name=".ui.utils.protect.ProtectActivity"
|
||||
android:name="org.koitharu.kotatsu.main.ui.protect.ProtectActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<service
|
||||
android:name=".ui.download.DownloadService"
|
||||
android:name="org.koitharu.kotatsu.download.DownloadService"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
<service
|
||||
android:name=".ui.widget.shelf.ShelfWidgetService"
|
||||
android:name="org.koitharu.kotatsu.widget.shelf.ShelfWidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
<service
|
||||
android:name=".ui.widget.recent.RecentWidgetService"
|
||||
android:name="org.koitharu.kotatsu.widget.recent.RecentWidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<provider
|
||||
android:name=".ui.search.MangaSuggestionsProvider"
|
||||
android:name="org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider"
|
||||
android:authorities="${applicationId}.MangaSuggestionsProvider"
|
||||
android:exported="false" />
|
||||
<provider
|
||||
@@ -101,7 +101,7 @@
|
||||
</provider>
|
||||
|
||||
<receiver
|
||||
android:name=".ui.widget.shelf.ShelfWidgetProvider"
|
||||
android:name="org.koitharu.kotatsu.widget.shelf.ShelfWidgetProvider"
|
||||
android:label="@string/manga_shelf">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
@@ -111,7 +111,7 @@
|
||||
android:resource="@xml/widget_shelf" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".ui.widget.recent.RecentWidgetProvider"
|
||||
android:name="org.koitharu.kotatsu.widget.recent.RecentWidgetProvider"
|
||||
android:label="@string/recent_manga">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
|
||||
@@ -6,25 +6,29 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.core.backup.BackupRepository
|
||||
import org.koitharu.kotatsu.core.backup.RestoreRepository
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.db.databaseModule
|
||||
import org.koitharu.kotatsu.core.github.githubModule
|
||||
import org.koitharu.kotatsu.core.local.PagesCache
|
||||
import org.koitharu.kotatsu.core.network.networkModule
|
||||
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.parserModule
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.domain.MangaSearchRepository
|
||||
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
|
||||
import org.koitharu.kotatsu.domain.history.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.tracking.TrackingRepository
|
||||
import org.koitharu.kotatsu.ui.base.uiModule
|
||||
import org.koitharu.kotatsu.ui.utils.AppCrashHandler
|
||||
import org.koitharu.kotatsu.ui.widget.WidgetUpdater
|
||||
import org.koitharu.kotatsu.core.ui.AppCrashHandler
|
||||
import org.koitharu.kotatsu.core.ui.uiModule
|
||||
import org.koitharu.kotatsu.details.detailsModule
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.favouritesModule
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.history.historyModule
|
||||
import org.koitharu.kotatsu.local.data.PagesCache
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.local.localModule
|
||||
import org.koitharu.kotatsu.main.mainModule
|
||||
import org.koitharu.kotatsu.reader.readerModule
|
||||
import org.koitharu.kotatsu.remotelist.remoteListModule
|
||||
import org.koitharu.kotatsu.search.searchModule
|
||||
import org.koitharu.kotatsu.settings.settingsModule
|
||||
import org.koitharu.kotatsu.tracker.trackerModule
|
||||
import org.koitharu.kotatsu.widget.WidgetUpdater
|
||||
|
||||
class KotatsuApp : Application() {
|
||||
|
||||
@@ -62,20 +66,18 @@ class KotatsuApp : Application() {
|
||||
networkModule,
|
||||
databaseModule,
|
||||
githubModule,
|
||||
parserModule,
|
||||
uiModule,
|
||||
module {
|
||||
single { FavouritesRepository(get()) }
|
||||
single { HistoryRepository(get()) }
|
||||
single { TrackingRepository(get(), get()) }
|
||||
single { MangaDataRepository(get()) }
|
||||
single { BackupRepository(get()) }
|
||||
single { RestoreRepository(get()) }
|
||||
single { MangaSearchRepository() }
|
||||
single { MangaLoaderContext() }
|
||||
single { AppSettings(get()) }
|
||||
single { PagesCache(get()) }
|
||||
}
|
||||
parserModule,
|
||||
mainModule,
|
||||
searchModule,
|
||||
localModule,
|
||||
favouritesModule,
|
||||
historyModule,
|
||||
remoteListModule,
|
||||
detailsModule,
|
||||
trackerModule,
|
||||
settingsModule,
|
||||
readerModule
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
package org.koitharu.kotatsu.base.domain
|
||||
|
||||
import androidx.room.withTransaction
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
package org.koitharu.kotatsu.base.domain
|
||||
|
||||
import okhttp3.*
|
||||
import org.koin.core.component.KoinComponent
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
package org.koitharu.kotatsu.base.domain
|
||||
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
package org.koitharu.kotatsu.base.domain
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
@@ -6,11 +6,11 @@ import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import moxy.MvpAppCompatDialogFragment
|
||||
import androidx.fragment.app.DialogFragment
|
||||
|
||||
abstract class AlertDialogFragment(
|
||||
@LayoutRes private val layoutResId: Int
|
||||
) : MvpAppCompatDialogFragment() {
|
||||
) : DialogFragment() {
|
||||
|
||||
private var rootView: View? = null
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import moxy.MvpAppCompatActivity
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
|
||||
abstract class BaseActivity : MvpAppCompatActivity() {
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
if (get<AppSettings>().isAmoledTheme) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
@@ -7,11 +7,11 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.appcompat.app.AppCompatDialog
|
||||
import moxy.MvpBottomSheetDialogFragment
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import org.koitharu.kotatsu.utils.UiUtils
|
||||
|
||||
abstract class BaseBottomSheet(@LayoutRes private val layoutResId: Int) :
|
||||
MvpBottomSheetDialogFragment() {
|
||||
BottomSheetDialogFragment() {
|
||||
|
||||
final override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
@@ -1,14 +1,14 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import coil.ImageLoader
|
||||
import moxy.MvpAppCompatFragment
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
abstract class BaseFragment(
|
||||
@LayoutRes contentLayoutId: Int
|
||||
) : MvpAppCompatFragment(contentLayoutId) {
|
||||
) : Fragment(contentLayoutId) {
|
||||
|
||||
protected val coil by inject<ImageLoader>()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import androidx.lifecycle.LifecycleService
|
||||
|
||||
abstract class BaseService : LifecycleService()
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.*
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
|
||||
abstract class BaseViewModel : ViewModel() {
|
||||
|
||||
val onError = SingleLiveEvent<Throwable>()
|
||||
val isLoading = MutableLiveData(false)
|
||||
|
||||
protected fun launchJob(
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job = viewModelScope.launch(createErrorHandler(), start, block)
|
||||
|
||||
protected fun launchLoadingJob(
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job = viewModelScope.launch(createErrorHandler(), start) {
|
||||
isLoading.value = true
|
||||
try {
|
||||
block()
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun createErrorHandler() = CoroutineExceptionHandler { _, throwable ->
|
||||
if (BuildConfig.DEBUG) {
|
||||
throwable.printStackTrace()
|
||||
}
|
||||
if (throwable !is CancellationException) {
|
||||
onError.call(throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.dialog
|
||||
package org.koitharu.kotatsu.base.ui.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.dialog
|
||||
package org.koitharu.kotatsu.base.ui.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
@@ -10,7 +10,7 @@ import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.android.synthetic.main.item_storage.view.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.utils.ext.getStorageName
|
||||
import org.koitharu.kotatsu.utils.ext.inflate
|
||||
import org.koitharu.kotatsu.utils.ext.longHashCode
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.dialog
|
||||
package org.koitharu.kotatsu.base.ui.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import android.view.View
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import android.view.ViewGroup
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list
|
||||
package org.koitharu.kotatsu.base.ui.list
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list.decor
|
||||
package org.koitharu.kotatsu.base.ui.list.decor
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list.decor
|
||||
package org.koitharu.kotatsu.base.ui.list.decor
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.list.decor
|
||||
package org.koitharu.kotatsu.base.ui.list.decor
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.widgets
|
||||
package org.koitharu.kotatsu.base.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.widgets
|
||||
package org.koitharu.kotatsu.base.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base.widgets
|
||||
package org.koitharu.kotatsu.base.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.browser
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
@@ -11,7 +11,7 @@ import android.view.MenuItem
|
||||
import androidx.core.view.isVisible
|
||||
import kotlinx.android.synthetic.main.activity_browser.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.ui.base.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
class BrowserActivity : BaseActivity(), BrowserCallback {
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.browser
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
interface BrowserCallback {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.browser
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.webkit.WebResourceRequest
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.utils.cloudflare
|
||||
package org.koitharu.kotatsu.browser.cloudflare
|
||||
|
||||
interface CloudFlareCallback {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.utils.cloudflare
|
||||
package org.koitharu.kotatsu.browser.cloudflare
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.webkit.CookieManager
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.utils.cloudflare
|
||||
package org.koitharu.kotatsu.browser.cloudflare
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
@@ -10,8 +10,8 @@ import androidx.core.view.isInvisible
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import kotlinx.android.synthetic.main.fragment_cloudflare.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||
import org.koitharu.kotatsu.core.network.UserAgentInterceptor
|
||||
import org.koitharu.kotatsu.ui.base.AlertDialogFragment
|
||||
import org.koitharu.kotatsu.utils.ext.stringArgument
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
@@ -4,7 +4,11 @@ import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.*
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||
|
||||
class BackupRepository(private val db: MangaDatabase) {
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@ package org.koitharu.kotatsu.core.backup
|
||||
import androidx.room.withTransaction
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.*
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||
import org.koitharu.kotatsu.utils.ext.getStringOrNull
|
||||
import org.koitharu.kotatsu.utils.ext.iterator
|
||||
import org.koitharu.kotatsu.utils.ext.map
|
||||
|
||||
@@ -4,6 +4,12 @@ import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koitharu.kotatsu.core.db.dao.*
|
||||
import org.koitharu.kotatsu.core.db.entity.*
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoriesDao
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouritesDao
|
||||
import org.koitharu.kotatsu.history.data.HistoryDao
|
||||
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
|
||||
@@ -15,7 +15,7 @@ import androidx.room.PrimaryKey
|
||||
)
|
||||
]
|
||||
)
|
||||
data class TrackEntity (
|
||||
data class TrackEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
||||
@ColumnInfo(name = "chapters_total") val totalChapters: Int,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package org.koitharu.kotatsu.core.exceptions
|
||||
|
||||
class ParseException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||
class ParseException(message: String? = null, cause: Throwable? = null) :
|
||||
RuntimeException(message, cause)
|
||||
@@ -4,9 +4,10 @@ import android.os.Parcelable
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import org.koin.core.context.GlobalContext
|
||||
import org.koin.core.error.NoBeanDefFoundException
|
||||
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.site.*
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@Parcelize
|
||||
@@ -30,6 +31,7 @@ enum class MangaSource(
|
||||
// HENTAILIB("HentaiLib", "ru", HentaiLibRepository::class.java)
|
||||
|
||||
@get:Throws(NoBeanDefFoundException::class)
|
||||
@Deprecated("")
|
||||
val repository: MangaRepository
|
||||
get() = GlobalContext.get().get(cls.kotlin)
|
||||
get() = GlobalContext.get().get(named(this))
|
||||
}
|
||||
@@ -5,10 +5,10 @@ import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@Parcelize
|
||||
data class MangaTracking (
|
||||
data class MangaTracking(
|
||||
val manga: Manga,
|
||||
val knownChaptersCount: Int,
|
||||
val lastChapterId: Long,
|
||||
val lastNotifiedChapterId: Long,
|
||||
val lastCheck: Date?
|
||||
): Parcelable
|
||||
) : Parcelable
|
||||
@@ -5,9 +5,9 @@ import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@Parcelize
|
||||
data class TrackingLogItem (
|
||||
data class TrackingLogItem(
|
||||
val id: Long,
|
||||
val manga: Manga,
|
||||
val chapters: List<String>,
|
||||
val createdAt: Date
|
||||
): Parcelable
|
||||
) : Parcelable
|
||||
@@ -6,13 +6,18 @@ interface MangaRepository {
|
||||
|
||||
val sortOrders: Set<SortOrder>
|
||||
|
||||
suspend fun getList(offset: Int, query: String? = null, sortOrder: SortOrder? = null, tag: MangaTag? = null): List<Manga>
|
||||
suspend fun getList(
|
||||
offset: Int,
|
||||
query: String? = null,
|
||||
sortOrder: SortOrder? = null,
|
||||
tag: MangaTag? = null
|
||||
): List<Manga>
|
||||
|
||||
suspend fun getDetails(manga: Manga) : Manga
|
||||
suspend fun getDetails(manga: Manga): Manga
|
||||
|
||||
suspend fun getPages(chapter: MangaChapter) : List<MangaPage>
|
||||
suspend fun getPages(chapter: MangaChapter): List<MangaPage>
|
||||
|
||||
suspend fun getPageFullUrl(page: MangaPage) : String
|
||||
suspend fun getPageFullUrl(page: MangaPage): String
|
||||
|
||||
suspend fun getTags(): Set<MangaTag>
|
||||
}
|
||||
@@ -1,22 +1,25 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.parser.site.*
|
||||
|
||||
val parserModule
|
||||
get() = module {
|
||||
single { LocalMangaRepository(get()) } bind MangaRepository::class
|
||||
|
||||
factory { ReadmangaRepository(get()) } bind MangaRepository::class
|
||||
factory { MintMangaRepository(get()) } bind MangaRepository::class
|
||||
factory { SelfMangaRepository(get()) } bind MangaRepository::class
|
||||
factory { MangaChanRepository(get()) } bind MangaRepository::class
|
||||
factory { DesuMeRepository(get()) } bind MangaRepository::class
|
||||
factory { HenChanRepository(get()) } bind MangaRepository::class
|
||||
factory { YaoiChanRepository(get()) } bind MangaRepository::class
|
||||
factory { MangaTownRepository(get()) } bind MangaRepository::class
|
||||
factory { MangaLibRepository(get()) } bind MangaRepository::class
|
||||
factory { NudeMoonRepository(get()) } bind MangaRepository::class
|
||||
factory { MangareadRepository(get()) } bind MangaRepository::class
|
||||
single { MangaLoaderContext() }
|
||||
|
||||
factory<MangaRepository>(named(MangaSource.READMANGA_RU)) { ReadmangaRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.MINTMANGA)) { MintMangaRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.SELFMANGA)) { SelfMangaRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.MANGACHAN)) { MangaChanRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.DESUME)) { DesuMeRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.HENCHAN)) { HenChanRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.YAOICHAN)) { YaoiChanRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.MANGATOWN)) { MangaTownRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.MANGALIB)) { MangaLibRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.NUDEMOON)) { NudeMoonRepository(get()) }
|
||||
factory<MangaRepository>(named(MangaSource.MANGAREAD)) { MangareadRepository(get()) }
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.MangaTag
|
||||
import org.koitharu.kotatsu.core.model.SortOrder
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
|
||||
abstract class RemoteMangaRepository(
|
||||
protected val loaderContext: MangaLoaderContext
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import androidx.collection.arraySetOf
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import androidx.collection.arraySetOf
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@@ -2,11 +2,11 @@ package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import androidx.collection.arraySetOf
|
||||
import androidx.core.net.toUri
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.longHashCode
|
||||
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||
import org.koitharu.kotatsu.utils.ext.parseHtml
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
|
||||
class MangaChanRepository(loaderContext: MangaLoaderContext) : ChanRepository(loaderContext) {
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import androidx.collection.ArraySet
|
||||
import androidx.collection.arraySetOf
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@@ -2,11 +2,11 @@ package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import androidx.collection.arraySetOf
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import androidx.collection.arraySetOf
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
|
||||
class MintMangaRepository(loaderContext: MangaLoaderContext) : GroupleRepository(loaderContext) {
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import androidx.collection.arraySetOf
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
|
||||
class ReadmangaRepository(loaderContext: MangaLoaderContext) : GroupleRepository(loaderContext) {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
|
||||
class SelfMangaRepository(loaderContext: MangaLoaderContext) : GroupleRepository(loaderContext) {
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.core.parser.site
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.utils.ext.longHashCode
|
||||
import org.koitharu.kotatsu.utils.ext.parseHtml
|
||||
import org.koitharu.kotatsu.utils.ext.withDomain
|
||||
|
||||
@@ -8,7 +8,7 @@ import androidx.collection.arraySetOf
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.koitharu.kotatsu.core.model.ZoomMode
|
||||
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.utils.delegates.prefs.*
|
||||
import java.io.File
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.koitharu.kotatsu.utils.delegates.prefs.LongPreferenceDelegate
|
||||
class AppWidgetConfig private constructor(
|
||||
private val prefs: SharedPreferences,
|
||||
val widgetId: Int
|
||||
) : SharedPreferences by prefs {
|
||||
) : SharedPreferences by prefs {
|
||||
|
||||
var categoryId by LongPreferenceDelegate(CATEGORY_ID, 0L)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.utils
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.utils
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
@@ -10,7 +10,7 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.activity_crash.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.ui.list.MainActivity
|
||||
import org.koitharu.kotatsu.main.ui.MainActivity
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
|
||||
class CrashActivity : Activity(), View.OnClickListener {
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.ui.base
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import coil.ComponentRegistry
|
||||
import coil.ImageLoader
|
||||
import okhttp3.OkHttpClient
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.core.local.CbzFetcher
|
||||
import org.koitharu.kotatsu.local.data.CbzFetcher
|
||||
|
||||
val uiModule
|
||||
get() = module {
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.koitharu.kotatsu.details
|
||||
|
||||
import org.koin.android.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
||||
|
||||
val detailsModule
|
||||
get() = module {
|
||||
|
||||
viewModel { DetailsViewModel(get(), get(), get(), get(), get(), get()) }
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import kotlinx.android.synthetic.main.item_chapter.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.domain.history.ChapterExtra
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
|
||||
class ChapterHolder(parent: ViewGroup) :
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.domain.history.ChapterExtra
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
|
||||
class ChaptersAdapter(onItemClickListener: OnRecyclerItemClickListener<MangaChapter>) :
|
||||
BaseRecyclerAdapter<MangaChapter, ChapterExtra>(onItemClickListener) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.os.Bundle
|
||||
@@ -12,22 +12,22 @@ import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.fragment_chapters.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.viewmodel.ext.android.sharedViewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.ui.base.BaseFragment
|
||||
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.ui.download.DownloadService
|
||||
import org.koitharu.kotatsu.ui.reader.ReaderActivity
|
||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.download.DownloadService
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||
|
||||
class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsView,
|
||||
class ChaptersFragment : BaseFragment(R.layout.fragment_chapters),
|
||||
OnRecyclerItemClickListener<MangaChapter>, ActionMode.Callback {
|
||||
|
||||
@Suppress("unused")
|
||||
private val presenter by moxyPresenter {
|
||||
MangaDetailsPresenter.getInstance(activity.hashCode())
|
||||
}
|
||||
private val viewModel by sharedViewModel<DetailsViewModel>()
|
||||
|
||||
private var manga: Manga? = null
|
||||
|
||||
@@ -45,33 +45,32 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
|
||||
)
|
||||
recyclerView_chapters.setHasFixedSize(true)
|
||||
recyclerView_chapters.adapter = adapter
|
||||
|
||||
viewModel.mangaData.observe(viewLifecycleOwner, this::onMangaUpdated)
|
||||
viewModel.isLoading.observe(viewLifecycleOwner, this::onLoadingStateChanged)
|
||||
viewModel.history.observe(viewLifecycleOwner, this::onHistoryChanged)
|
||||
viewModel.newChapters.observe(viewLifecycleOwner, this::onNewChaptersChanged)
|
||||
}
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
private fun onMangaUpdated(manga: Manga) {
|
||||
this.manga = manga
|
||||
adapter.replaceData(manga.chapters.orEmpty())
|
||||
scrollToCurrent()
|
||||
}
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
progressBar.isVisible = isLoading
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) = Unit //handled in activity
|
||||
|
||||
override fun onMangaRemoved(manga: Manga) = Unit //handled in activity
|
||||
|
||||
override fun onHistoryChanged(history: MangaHistory?) {
|
||||
private fun onHistoryChanged(history: MangaHistory?) {
|
||||
adapter.currentChapterId = history?.chapterId
|
||||
scrollToCurrent()
|
||||
}
|
||||
|
||||
override fun onNewChaptersChanged(newChapters: Int) {
|
||||
private fun onNewChaptersChanged(newChapters: Int) {
|
||||
adapter.newChaptersCount = newChapters
|
||||
}
|
||||
|
||||
override fun onFavouriteChanged(categories: List<FavouriteCategory>) = Unit
|
||||
|
||||
override fun onItemClick(item: MangaChapter, position: Int, view: View) {
|
||||
if (adapter.checkedItemsCount != 0) {
|
||||
adapter.toggleItemChecked(item.id)
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -18,28 +18,22 @@ import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.android.synthetic.main.activity_details.*
|
||||
import kotlinx.coroutines.launch
|
||||
import moxy.MvpDelegate
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.ui.base.BaseActivity
|
||||
import org.koitharu.kotatsu.ui.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.ui.download.DownloadService
|
||||
import org.koitharu.kotatsu.download.DownloadService
|
||||
import org.koitharu.kotatsu.utils.MangaShortcut
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
|
||||
class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
TabLayoutMediator.TabConfigurationStrategy {
|
||||
class DetailsActivity : BaseActivity(), TabLayoutMediator.TabConfigurationStrategy {
|
||||
|
||||
private val presenter by moxyPresenter {
|
||||
MangaDetailsPresenter.getInstance(hashCode())
|
||||
}
|
||||
private val viewModel by viewModel<DetailsViewModel>()
|
||||
|
||||
private var manga: Manga? = null
|
||||
|
||||
@@ -49,28 +43,27 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
pager.adapter = MangaDetailsAdapter(this)
|
||||
TabLayoutMediator(tabs, pager, this).attach()
|
||||
if (savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true) {
|
||||
if (savedInstanceState == null) {
|
||||
intent?.getParcelableExtra<Manga>(EXTRA_MANGA)?.let {
|
||||
presenter.loadDetails(it, true)
|
||||
viewModel.loadDetails(it, true)
|
||||
} ?: intent?.getLongExtra(EXTRA_MANGA_ID, 0)?.takeUnless { it == 0L }?.let {
|
||||
presenter.findMangaById(it)
|
||||
viewModel.findMangaById(it)
|
||||
} ?: finishAfterTransition()
|
||||
}
|
||||
|
||||
viewModel.mangaData.observe(this, ::onMangaUpdated)
|
||||
viewModel.onMangaRemoved.observe(this, ::onMangaRemoved)
|
||||
viewModel.onError.observe(this, ::onError)
|
||||
viewModel.newChapters.observe(this, ::onNewChaptersChanged)
|
||||
}
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
private fun onMangaUpdated(manga: Manga) {
|
||||
this.manga = manga
|
||||
title = manga.title
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
override fun onHistoryChanged(history: MangaHistory?) = Unit
|
||||
|
||||
override fun onFavouriteChanged(categories: List<FavouriteCategory>) = Unit
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
|
||||
|
||||
override fun onMangaRemoved(manga: Manga) {
|
||||
private fun onMangaRemoved(manga: Manga) {
|
||||
Toast.makeText(
|
||||
this, getString(R.string._s_deleted_from_local_storage, manga.title),
|
||||
Toast.LENGTH_SHORT
|
||||
@@ -78,7 +71,7 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
finishAfterTransition()
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
private fun onError(e: Throwable) {
|
||||
if (manga == null) {
|
||||
Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
|
||||
finishAfterTransition()
|
||||
@@ -87,7 +80,7 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewChaptersChanged(newChapters: Int) {
|
||||
private fun onNewChaptersChanged(newChapters: Int) {
|
||||
val tab = tabs.getTabAt(1) ?: return
|
||||
if (newChapters == 0) {
|
||||
tab.removeBadge()
|
||||
@@ -132,7 +125,7 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
.setTitle(R.string.delete_manga)
|
||||
.setMessage(getString(R.string.text_delete_local_manga, m.title))
|
||||
.setPositiveButton(R.string.delete) { _, _ ->
|
||||
presenter.deleteLocal(m)
|
||||
viewModel.deleteLocal(m)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
@@ -174,7 +167,7 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
R.id.action_shortcut -> {
|
||||
manga?.let {
|
||||
lifecycleScope.launch {
|
||||
if (!MangaShortcut(it).requestPinShortcut(this@MangaDetailsActivity)) {
|
||||
if (!MangaShortcut(it).requestPinShortcut(this@DetailsActivity)) {
|
||||
Snackbar.make(
|
||||
pager,
|
||||
R.string.operation_not_supported,
|
||||
@@ -217,11 +210,11 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView,
|
||||
const val ACTION_MANGA_VIEW = "${BuildConfig.APPLICATION_ID}.action.VIEW_MANGA"
|
||||
|
||||
fun newIntent(context: Context, manga: Manga) =
|
||||
Intent(context, MangaDetailsActivity::class.java)
|
||||
Intent(context, DetailsActivity::class.java)
|
||||
.putExtra(EXTRA_MANGA, manga)
|
||||
|
||||
fun newIntent(context: Context, mangaId: Long) =
|
||||
Intent(context, MangaDetailsActivity::class.java)
|
||||
Intent(context, DetailsActivity::class.java)
|
||||
.putExtra(EXTRA_MANGA_ID, mangaId)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Spanned
|
||||
import android.view.View
|
||||
import androidx.core.net.toUri
|
||||
@@ -10,32 +11,36 @@ import kotlinx.android.synthetic.main.fragment_details.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.viewmodel.ext.android.sharedViewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.ui.base.BaseFragment
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.select.FavouriteCategoriesDialog
|
||||
import org.koitharu.kotatsu.ui.reader.ReaderActivity
|
||||
import org.koitharu.kotatsu.ui.search.MangaSearchSheet
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesDialog
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.search.ui.MangaSearchSheet
|
||||
import org.koitharu.kotatsu.utils.FileSizeUtils
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetailsView,
|
||||
View.OnClickListener,
|
||||
class DetailsFragment : BaseFragment(R.layout.fragment_details), View.OnClickListener,
|
||||
View.OnLongClickListener {
|
||||
|
||||
@Suppress("unused")
|
||||
private val presenter by moxyPresenter {
|
||||
MangaDetailsPresenter.getInstance(activity.hashCode())
|
||||
}
|
||||
private val viewModel by sharedViewModel<DetailsViewModel>()
|
||||
|
||||
private var manga: Manga? = null
|
||||
private var history: MangaHistory? = null
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel.mangaData.observe(viewLifecycleOwner, ::onMangaUpdated)
|
||||
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
|
||||
viewModel.favouriteCategories.observe(viewLifecycleOwner, ::onFavouriteChanged)
|
||||
viewModel.history.observe(viewLifecycleOwner, ::onHistoryChanged)
|
||||
}
|
||||
|
||||
private fun onMangaUpdated(manga: Manga) {
|
||||
this.manga = manga
|
||||
imageView_cover.newImageRequest(manga.largeCoverUrl ?: manga.coverUrl)
|
||||
.fallback(R.drawable.ic_placeholder)
|
||||
@@ -59,7 +64,7 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
text = it,
|
||||
iconRes = R.drawable.ic_chip_user,
|
||||
tag = it,
|
||||
onClickListener = this@MangaDetailsFragment
|
||||
onClickListener = this@DetailsFragment
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -68,7 +73,7 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
text = it.title,
|
||||
iconRes = R.drawable.ic_chip_tag,
|
||||
tag = it,
|
||||
onClickListener = this@MangaDetailsFragment
|
||||
onClickListener = this@DetailsFragment
|
||||
)
|
||||
}
|
||||
manga.url.toUri().toFileOrNull()?.let { f ->
|
||||
@@ -81,7 +86,7 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
text = FileSizeUtils.formatBytes(context, size),
|
||||
iconRes = R.drawable.ic_chip_storage,
|
||||
tag = it,
|
||||
onClickListener = this@MangaDetailsFragment
|
||||
onClickListener = this@DetailsFragment
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -92,12 +97,12 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
updateReadButton()
|
||||
}
|
||||
|
||||
override fun onHistoryChanged(history: MangaHistory?) {
|
||||
private fun onHistoryChanged(history: MangaHistory?) {
|
||||
this.history = history
|
||||
updateReadButton()
|
||||
}
|
||||
|
||||
override fun onFavouriteChanged(categories: List<FavouriteCategory>) {
|
||||
private fun onFavouriteChanged(categories: List<FavouriteCategory>) {
|
||||
imageView_favourite.setImageResource(
|
||||
if (categories.isEmpty()) {
|
||||
R.drawable.ic_heart_outline
|
||||
@@ -107,16 +112,10 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
)
|
||||
}
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
progressBar.isVisible = isLoading
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) = Unit //handled in activity
|
||||
|
||||
override fun onMangaRemoved(manga: Manga) = Unit //handled in activity
|
||||
|
||||
override fun onNewChaptersChanged(newChapters: Int) = Unit
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when {
|
||||
v.id == R.id.imageView_favourite -> {
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.domain.OnFavouritesChangeListener
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.history.domain.OnHistoryChangeListener
|
||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.onFirst
|
||||
import org.koitharu.kotatsu.utils.ext.safe
|
||||
import java.io.IOException
|
||||
|
||||
class DetailsViewModel(
|
||||
private val historyRepository: HistoryRepository,
|
||||
private val favouritesRepository: FavouritesRepository,
|
||||
private val localMangaRepository: LocalMangaRepository,
|
||||
private val trackingRepository: TrackingRepository,
|
||||
private val searchRepository: MangaSearchRepository,
|
||||
private val mangaDataRepository: MangaDataRepository
|
||||
) : MangaListViewModel(), OnHistoryChangeListener, OnFavouritesChangeListener {
|
||||
|
||||
val mangaData = MutableLiveData<Manga>()
|
||||
val newChapters = MutableLiveData<Int>(0)
|
||||
val onMangaRemoved = SingleLiveEvent<Manga>()
|
||||
val history = MutableLiveData<MangaHistory?>()
|
||||
val favouriteCategories = MutableLiveData<List<FavouriteCategory>>()
|
||||
|
||||
init {
|
||||
HistoryRepository.subscribe(this)
|
||||
FavouritesRepository.subscribe(this)
|
||||
}
|
||||
|
||||
fun findMangaById(id: Long) {
|
||||
launchLoadingJob {
|
||||
val manga = mangaDataRepository.findMangaById(id)
|
||||
?: throw MangaNotFoundException("Cannot find manga by id")
|
||||
mangaData.value = manga
|
||||
loadDetails(manga, true)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDetails(manga: Manga, force: Boolean = false) {
|
||||
if (!force && mangaData.value == manga) {
|
||||
return
|
||||
}
|
||||
loadHistory(manga)
|
||||
mangaData.value = manga
|
||||
loadFavourite(manga)
|
||||
launchLoadingJob {
|
||||
val data = withContext(Dispatchers.Default) {
|
||||
manga.source.repository.getDetails(manga)
|
||||
}
|
||||
mangaData.value = data
|
||||
newChapters.value = trackingRepository.getNewChaptersCount(manga.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteLocal(manga: Manga) {
|
||||
launchLoadingJob {
|
||||
withContext(Dispatchers.Default) {
|
||||
val original = localMangaRepository.getRemoteManga(manga)
|
||||
localMangaRepository.delete(manga) || throw IOException("Unable to delete file")
|
||||
safe {
|
||||
historyRepository.deleteOrSwap(manga, original)
|
||||
}
|
||||
}
|
||||
onMangaRemoved.call(manga)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadHistory(manga: Manga) {
|
||||
launchJob {
|
||||
history.value = historyRepository.getOne(manga)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadFavourite(manga: Manga) {
|
||||
launchJob {
|
||||
favouriteCategories.value = favouritesRepository.getCategories(manga.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadRelated() {
|
||||
val manga = mangaData.value ?: return
|
||||
searchRepository.globalSearch(manga.title)
|
||||
.map { list ->
|
||||
list.filter { x -> x.id != manga.id }
|
||||
}.filterNot { x -> x.isEmpty() }
|
||||
.flowOn(Dispatchers.IO)
|
||||
.catch { e ->
|
||||
if (e is IOException) {
|
||||
onError.call(e)
|
||||
}
|
||||
}
|
||||
.onEmpty {
|
||||
content.value = emptyList()
|
||||
isLoading.value = false
|
||||
}.onCompletion {
|
||||
// TODO
|
||||
}.onFirst {
|
||||
isLoading.value = false
|
||||
}.onEach {
|
||||
content.value = content.value.orEmpty() + it
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
loadHistory(mangaData.value ?: return)
|
||||
}
|
||||
|
||||
override fun onFavouritesChanged(mangaId: Long) {
|
||||
val manga = mangaData.value ?: return
|
||||
if (mangaId == manga.id) {
|
||||
loadFavourite(manga)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
HistoryRepository.unsubscribe(this)
|
||||
FavouritesRepository.unsubscribe(this)
|
||||
super.onCleared()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
@@ -8,8 +8,8 @@ class MangaDetailsAdapter(activity: FragmentActivity) : FragmentStateAdapter(act
|
||||
|
||||
override fun getItemCount() = 3
|
||||
|
||||
override fun createFragment(position: Int): Fragment = when(position) {
|
||||
0 -> MangaDetailsFragment()
|
||||
override fun createFragment(position: Int): Fragment = when (position) {
|
||||
0 -> DetailsFragment()
|
||||
1 -> ChaptersFragment()
|
||||
2 -> RelatedMangaFragment()
|
||||
else -> throw IndexOutOfBoundsException("No fragment for position $position")
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import org.koin.android.viewmodel.ext.android.sharedViewModel
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
|
||||
class RelatedMangaFragment : MangaListFragment() {
|
||||
|
||||
override val viewModel by sharedViewModel<DetailsViewModel>()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
isSwipeRefreshEnabled = false
|
||||
}
|
||||
|
||||
override fun onRequestMoreItems(offset: Int) {
|
||||
if (offset == 0) {
|
||||
viewModel.loadRelated()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.download
|
||||
package org.koitharu.kotatsu.download
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
@@ -12,7 +12,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -24,7 +24,8 @@ class DownloadNotification(private val context: Context) {
|
||||
|
||||
init {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& manager.getNotificationChannel(CHANNEL_ID) == null) {
|
||||
&& manager.getNotificationChannel(CHANNEL_ID) == null
|
||||
) {
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
context.getString(R.string.downloads),
|
||||
@@ -145,7 +146,7 @@ class DownloadNotification(private val context: Context) {
|
||||
private fun createIntent(context: Context, manga: Manga) = PendingIntent.getActivity(
|
||||
context,
|
||||
manga.hashCode(),
|
||||
MangaDetailsActivity.newIntent(context, manga),
|
||||
DetailsActivity.newIntent(context, manga),
|
||||
PendingIntent.FLAG_CANCEL_CURRENT
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.download
|
||||
package org.koitharu.kotatsu.download
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -7,6 +7,7 @@ import android.os.PowerManager
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import coil.ImageLoader
|
||||
import coil.request.ImageRequest
|
||||
import kotlinx.coroutines.*
|
||||
@@ -19,13 +20,13 @@ import org.koin.android.ext.android.inject
|
||||
import org.koin.core.context.GlobalContext
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.local.PagesCache
|
||||
import org.koitharu.kotatsu.base.ui.BaseService
|
||||
import org.koitharu.kotatsu.base.ui.dialog.CheckBoxAlertDialog
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.domain.local.MangaZip
|
||||
import org.koitharu.kotatsu.ui.base.BaseService
|
||||
import org.koitharu.kotatsu.ui.base.dialog.CheckBoxAlertDialog
|
||||
import org.koitharu.kotatsu.local.data.MangaZip
|
||||
import org.koitharu.kotatsu.local.data.PagesCache
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.utils.CacheUtils
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.io.File
|
||||
@@ -54,8 +55,9 @@ class DownloadService : BaseService() {
|
||||
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "kotatsu:downloading")
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
when (intent?.action) {
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
when (intent.action) {
|
||||
ACTION_DOWNLOAD_START -> {
|
||||
val manga = intent.getParcelableExtra<Manga>(EXTRA_MANGA)
|
||||
val chapters = intent.getLongArrayExtra(EXTRA_CHAPTERS_IDS)?.toArraySet()
|
||||
@@ -77,7 +79,7 @@ class DownloadService : BaseService() {
|
||||
}
|
||||
|
||||
private fun downloadManga(manga: Manga, chaptersIds: Set<Long>?, startId: Int): Job {
|
||||
return serviceScope.launch(Dispatchers.Default) {
|
||||
return lifecycleScope.launch(Dispatchers.Default) {
|
||||
mutex.lock()
|
||||
wakeLock.acquire(TimeUnit.HOURS.toMillis(1))
|
||||
notification.fillFrom(manga)
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.koitharu.kotatsu.favourites
|
||||
|
||||
import org.koin.android.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListViewModel
|
||||
|
||||
val favouritesModule
|
||||
get() = module {
|
||||
|
||||
single { FavouritesRepository(get()) }
|
||||
|
||||
viewModel { (categoryId: Long) ->
|
||||
FavouritesListViewModel(categoryId, get())
|
||||
}
|
||||
viewModel { FavouritesCategoriesViewModel(get()) }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.db.dao
|
||||
package org.koitharu.kotatsu.favourites.data
|
||||
|
||||
import androidx.room.*
|
||||
import org.koitharu.kotatsu.core.db.entity.FavouriteCategoryEntity
|
||||
|
||||
@Dao
|
||||
abstract class FavouriteCategoriesDao {
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
package org.koitharu.kotatsu.favourites.data
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
@@ -1,8 +1,9 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
package org.koitharu.kotatsu.favourites.data
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
|
||||
@Entity(
|
||||
tableName = "favourites", primaryKeys = ["manga_id", "category_id"], foreignKeys = [
|
||||
@@ -1,8 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
package org.koitharu.kotatsu.favourites.data
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Junction
|
||||
import androidx.room.Relation
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaTagsEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
|
||||
data class FavouriteManga(
|
||||
@Embedded val favourite: FavouriteEntity,
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.db.dao
|
||||
package org.koitharu.kotatsu.favourites.data
|
||||
|
||||
import androidx.room.*
|
||||
import org.koitharu.kotatsu.core.db.entity.FavouriteEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.FavouriteManga
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
|
||||
@Dao
|
||||
@@ -1,16 +1,16 @@
|
||||
package org.koitharu.kotatsu.domain.favourites
|
||||
package org.koitharu.kotatsu.favourites.domain
|
||||
|
||||
import androidx.collection.ArraySet
|
||||
import androidx.room.withTransaction
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.FavouriteEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||
|
||||
class FavouritesRepository(private val db: MangaDatabase) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.domain.favourites
|
||||
package org.koitharu.kotatsu.favourites.domain
|
||||
|
||||
fun interface OnFavouritesChangeListener {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites
|
||||
package org.koitharu.kotatsu.favourites.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
@@ -8,25 +8,25 @@ import android.view.View
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.android.synthetic.main.fragment_favourites.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
|
||||
import org.koitharu.kotatsu.domain.favourites.OnFavouritesChangeListener
|
||||
import org.koitharu.kotatsu.ui.base.BaseFragment
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.CategoriesActivity
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.CategoriesEditDelegate
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesPresenter
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.domain.OnFavouritesChangeListener
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.CategoriesEditDelegate
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel
|
||||
import org.koitharu.kotatsu.utils.ext.showPopupMenu
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
|
||||
FavouriteCategoriesView, OnFavouritesChangeListener, FavouritesTabLongClickListener,
|
||||
OnFavouritesChangeListener, FavouritesTabLongClickListener,
|
||||
CategoriesEditDelegate.CategoriesEditCallback {
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)
|
||||
private val viewModel by viewModel<FavouritesCategoriesViewModel>()
|
||||
|
||||
private val editDelegate by lazy(LazyThreadSafetyMode.NONE) {
|
||||
CategoriesEditDelegate(requireContext(), this)
|
||||
}
|
||||
@@ -42,6 +42,9 @@ class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
|
||||
pager.adapter = adapter
|
||||
TabLayoutMediator(tabs, pager, adapter).attach()
|
||||
FavouritesRepository.subscribe(this)
|
||||
|
||||
viewModel.categories.observe(viewLifecycleOwner, ::onCategoriesChanged)
|
||||
viewModel.onError.observe(viewLifecycleOwner, ::onError)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@@ -49,7 +52,7 @@ class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
val data = ArrayList<FavouriteCategory>(categories.size + 1)
|
||||
data += FavouriteCategory(0L, getString(R.string.all_favourites), -1, Date())
|
||||
data += categories
|
||||
@@ -75,16 +78,14 @@ class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
|
||||
return getString(R.string.favourites)
|
||||
}
|
||||
|
||||
override fun onCheckedCategoriesChanged(checkedIds: Set<Int>) = Unit
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
private fun onError(e: Throwable) {
|
||||
Snackbar.make(pager, e.message ?: return, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun onFavouritesChanged(mangaId: Long) = Unit
|
||||
|
||||
override fun onCategoriesChanged() {
|
||||
presenter.loadAllCategories()
|
||||
viewModel.loadAllCategories()
|
||||
}
|
||||
|
||||
override fun onTabLongClick(tabView: View, category: FavouriteCategory): Boolean {
|
||||
@@ -101,15 +102,15 @@ class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
|
||||
}
|
||||
|
||||
override fun onDeleteCategory(category: FavouriteCategory) {
|
||||
presenter.deleteCategory(category.id)
|
||||
viewModel.deleteCategory(category.id)
|
||||
}
|
||||
|
||||
override fun onRenameCategory(category: FavouriteCategory, newName: String) {
|
||||
presenter.renameCategory(category.id, newName)
|
||||
viewModel.renameCategory(category.id, newName)
|
||||
}
|
||||
|
||||
override fun onCreateCategory(name: String) {
|
||||
presenter.createCategory(name)
|
||||
viewModel.createCategory(name)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites
|
||||
package org.koitharu.kotatsu.favourites.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import org.koitharu.kotatsu.base.ui.list.AdapterUpdater
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.list.AdapterUpdater
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
|
||||
import org.koitharu.kotatsu.utils.ext.replaceWith
|
||||
|
||||
class FavouritesPagerAdapter(
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites
|
||||
package org.koitharu.kotatsu.favourites.ui
|
||||
|
||||
import android.view.View
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -12,18 +12,18 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.activity_categories.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.BaseActivity
|
||||
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.showPopupMenu
|
||||
|
||||
class CategoriesActivity : BaseActivity(), OnRecyclerItemClickListener<FavouriteCategory>,
|
||||
FavouriteCategoriesView, View.OnClickListener, CategoriesEditDelegate.CategoriesEditCallback {
|
||||
View.OnClickListener, CategoriesEditDelegate.CategoriesEditCallback {
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)
|
||||
private val viewModel by viewModel<FavouritesCategoriesViewModel>()
|
||||
|
||||
private lateinit var adapter: CategoriesAdapter
|
||||
private lateinit var reorderHelper: ItemTouchHelper
|
||||
@@ -41,6 +41,9 @@ class CategoriesActivity : BaseActivity(), OnRecyclerItemClickListener<Favourite
|
||||
fab_add.setOnClickListener(this)
|
||||
reorderHelper = ItemTouchHelper(ReorderHelperCallback())
|
||||
reorderHelper.attachToRecyclerView(recyclerView)
|
||||
|
||||
viewModel.categories.observe(this, ::onCategoriesChanged)
|
||||
viewModel.onError.observe(this, ::onError)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
@@ -66,28 +69,26 @@ class CategoriesActivity : BaseActivity(), OnRecyclerItemClickListener<Favourite
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
private fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
adapter.replaceData(categories)
|
||||
textView_holder.isVisible = categories.isEmpty()
|
||||
}
|
||||
|
||||
override fun onCheckedCategoriesChanged(checkedIds: Set<Int>) = Unit
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
private fun onError(e: Throwable) {
|
||||
Snackbar.make(recyclerView, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onDeleteCategory(category: FavouriteCategory) {
|
||||
presenter.deleteCategory(category.id)
|
||||
viewModel.deleteCategory(category.id)
|
||||
}
|
||||
|
||||
override fun onRenameCategory(category: FavouriteCategory, newName: String) {
|
||||
presenter.renameCategory(category.id, newName)
|
||||
viewModel.renameCategory(category.id, newName)
|
||||
}
|
||||
|
||||
override fun onCreateCategory(name: String) {
|
||||
presenter.createCategory(name)
|
||||
viewModel.createCategory(name)
|
||||
}
|
||||
|
||||
private inner class ReorderHelperCallback : ItemTouchHelper.SimpleCallback(
|
||||
@@ -102,7 +103,7 @@ class CategoriesActivity : BaseActivity(), OnRecyclerItemClickListener<Favourite
|
||||
val oldPos = viewHolder.bindingAdapterPosition
|
||||
val newPos = target.bindingAdapterPosition
|
||||
adapter.moveItem(oldPos, newPos)
|
||||
presenter.storeCategoriesOrder(adapter.items.map { it.id })
|
||||
viewModel.storeCategoriesOrder(adapter.items.map { it.id })
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.item_category.*
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
|
||||
|
||||
class CategoriesAdapter(private val onItemClickListener: OnRecyclerItemClickListener<FavouriteCategory>) :
|
||||
BaseRecyclerAdapter<FavouriteCategory, Unit>() {
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import android.content.Context
|
||||
import android.text.InputType
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.dialog.TextInputDialog
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.dialog.TextInputDialog
|
||||
|
||||
class CategoriesEditDelegate(
|
||||
private val context: Context,
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.item_category.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
|
||||
|
||||
class CategoryHolder(parent: ViewGroup) :
|
||||
BaseViewHolder<FavouriteCategory, Unit>(parent, R.layout.item_category) {
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import kotlinx.coroutines.Job
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||
|
||||
class FavouritesCategoriesViewModel(
|
||||
private val repository: FavouritesRepository
|
||||
) : BaseViewModel() {
|
||||
|
||||
private var reorderJob: Job? = null
|
||||
|
||||
val categories = MutableLiveData<List<FavouriteCategory>>()
|
||||
val mangaCategories = MutableLiveData<Set<Int>>()
|
||||
|
||||
init {
|
||||
loadAllCategories()
|
||||
}
|
||||
|
||||
fun loadAllCategories() {
|
||||
launchJob {
|
||||
categories.value = repository.getAllCategories()
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMangaCategories(manga: Manga) {
|
||||
launchJob {
|
||||
val categories = repository.getCategories(manga.id)
|
||||
mangaCategories.value = categories.mapToSet { it.id.toInt() }
|
||||
}
|
||||
}
|
||||
|
||||
fun createCategory(name: String) {
|
||||
launchJob {
|
||||
repository.addCategory(name)
|
||||
categories.value = repository.getAllCategories()
|
||||
}
|
||||
}
|
||||
|
||||
fun renameCategory(id: Long, name: String) {
|
||||
launchJob {
|
||||
repository.renameCategory(id, name)
|
||||
categories.value = repository.getAllCategories()
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCategory(id: Long) {
|
||||
launchJob {
|
||||
repository.removeCategory(id)
|
||||
categories.value = repository.getAllCategories()
|
||||
}
|
||||
}
|
||||
|
||||
fun storeCategoriesOrder(orderedIds: List<Long>) {
|
||||
val prevJob = reorderJob
|
||||
reorderJob = launchJob {
|
||||
prevJob?.join()
|
||||
repository.reorderCategories(orderedIds)
|
||||
}
|
||||
}
|
||||
|
||||
fun addToCategory(manga: Manga, categoryId: Long) {
|
||||
launchJob {
|
||||
repository.addToCategory(manga, categoryId)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeFromCategory(manga: Manga, categoryId: Long) {
|
||||
launchJob {
|
||||
repository.removeFromCategory(manga, categoryId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories.select
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select
|
||||
|
||||
import android.util.SparseBooleanArray
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Checkable
|
||||
import androidx.core.util.set
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
|
||||
|
||||
class CategoriesSelectAdapter(private val listener: OnCategoryCheckListener) :
|
||||
BaseRecyclerAdapter<FavouriteCategory, Boolean>() {
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories.select
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select
|
||||
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.item_category_checkable.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
|
||||
|
||||
class CategoryCheckableHolder(parent: ViewGroup) :
|
||||
BaseViewHolder<FavouriteCategory, Boolean>(parent, R.layout.item_category_checkable) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories.select
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
@@ -6,22 +6,20 @@ import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import kotlinx.android.synthetic.main.dialog_favorite_categories.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.base.ui.dialog.TextInputDialog
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.ui.base.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.ui.base.dialog.TextInputDialog
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesPresenter
|
||||
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categories),
|
||||
FavouriteCategoriesView,
|
||||
OnCategoryCheckListener {
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)
|
||||
private val viewModel by viewModel<FavouritesCategoriesViewModel>()
|
||||
|
||||
private val manga get() = arguments?.getParcelable<Manga>(ARG_MANGA)
|
||||
|
||||
@@ -38,8 +36,12 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
|
||||
createCategory()
|
||||
}
|
||||
manga?.let {
|
||||
presenter.loadMangaCategories(it)
|
||||
viewModel.loadMangaCategories(it)
|
||||
}
|
||||
|
||||
viewModel.categories.observe(viewLifecycleOwner, ::onCategoriesChanged)
|
||||
viewModel.mangaCategories.observe(viewLifecycleOwner, ::onCheckedCategoriesChanged)
|
||||
viewModel.onError.observe(viewLifecycleOwner, ::onError)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@@ -47,23 +49,23 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
private fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
adapter?.replaceData(categories)
|
||||
}
|
||||
|
||||
override fun onCheckedCategoriesChanged(checkedIds: Set<Int>) {
|
||||
private fun onCheckedCategoriesChanged(checkedIds: Set<Int>) {
|
||||
adapter?.setCheckedIds(checkedIds)
|
||||
}
|
||||
|
||||
override fun onCategoryChecked(category: FavouriteCategory) {
|
||||
presenter.addToCategory(manga ?: return, category.id)
|
||||
viewModel.addToCategory(manga ?: return, category.id)
|
||||
}
|
||||
|
||||
override fun onCategoryUnchecked(category: FavouriteCategory) {
|
||||
presenter.removeFromCategory(manga ?: return, category.id)
|
||||
viewModel.removeFromCategory(manga ?: return, category.id)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
private fun onError(e: Throwable) {
|
||||
Toast.makeText(context ?: return, e.getDisplayMessage(resources), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
@@ -75,7 +77,7 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
|
||||
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
||||
.setNegativeButton(android.R.string.cancel)
|
||||
.setPositiveButton(R.string.add) { _, name ->
|
||||
presenter.createCategory(name)
|
||||
viewModel.createCategory(name)
|
||||
}.create()
|
||||
.show()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites.categories.select
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select
|
||||
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
package org.koitharu.kotatsu.ui.list.favourites
|
||||
package org.koitharu.kotatsu.favourites.ui.list
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import kotlinx.android.synthetic.main.fragment_list.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.ui.list.MangaListFragment
|
||||
import org.koitharu.kotatsu.ui.list.MangaListView
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class FavouritesListFragment : MangaListFragment<Unit>(), MangaListView<Unit> {
|
||||
class FavouritesListFragment : MangaListFragment() {
|
||||
|
||||
private val presenter by moxyPresenter {
|
||||
FavouritesListPresenter(categoryId, get())
|
||||
override val viewModel by viewModel<FavouritesListViewModel> {
|
||||
parametersOf(categoryId)
|
||||
}
|
||||
|
||||
private val categoryId: Long
|
||||
get() = arguments?.getLong(ARG_CATEGORY_ID) ?: 0L
|
||||
|
||||
override fun onRequestMoreItems(offset: Int) {
|
||||
presenter.loadList(offset)
|
||||
viewModel.loadList(offset)
|
||||
}
|
||||
|
||||
override fun setUpEmptyListHolder() {
|
||||
@@ -41,9 +40,9 @@ class FavouritesListFragment : MangaListFragment<Unit>(), MangaListView<Unit> {
|
||||
inflater.inflate(R.menu.popup_favourites, menu)
|
||||
}
|
||||
|
||||
override fun onPopupMenuItemSelected(item: MenuItem, data: Manga) = when(item.itemId) {
|
||||
override fun onPopupMenuItemSelected(item: MenuItem, data: Manga) = when (item.itemId) {
|
||||
R.id.action_remove -> {
|
||||
presenter.removeFromFavourites(data)
|
||||
viewModel.removeFromFavourites(data)
|
||||
true
|
||||
}
|
||||
else -> super.onPopupMenuItemSelected(item, data)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user