DI refactoring

This commit is contained in:
Koitharu
2020-10-18 19:05:15 +03:00
parent fb60b26f08
commit 56e145420c
164 changed files with 735 additions and 637 deletions

View File

@@ -3,37 +3,25 @@ package org.koitharu.kotatsu
import android.app.Application
import android.os.StrictMode
import androidx.appcompat.app.AppCompatDelegate
import androidx.room.Room
import coil.Coil
import coil.ComponentRegistry
import coil.ImageLoader
import coil.util.CoilUtils
import okhttp3.CookieJar
import okhttp3.OkHttpClient
import org.koin.android.ext.android.get
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.core.logger.Level
import org.koin.dsl.module
import org.koitharu.kotatsu.core.db.DatabasePrePopulateCallback
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.migrations.*
import org.koitharu.kotatsu.core.local.CbzFetcher
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.local.cookies.PersistentCookieJar
import org.koitharu.kotatsu.core.local.cookies.cache.SetCookieCache
import org.koitharu.kotatsu.core.local.cookies.persistence.SharedPrefsCookiePersistor
import org.koitharu.kotatsu.core.network.networkModule
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
import org.koitharu.kotatsu.core.parser.UserAgentInterceptor
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.utils.CacheUtils
import java.util.concurrent.TimeUnit
class KotatsuApp : Application() {
@@ -57,9 +45,8 @@ class KotatsuApp : Application() {
)
}
initKoin()
initCoil(get())
Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext))
AppCompatDelegate.setDefaultNightMode(AppSettings(this).theme)
AppCompatDelegate.setDefaultNightMode(get<AppSettings>().theme)
val widgetUpdater = WidgetUpdater(applicationContext)
FavouritesRepository.subscribe(widgetUpdater)
HistoryRepository.subscribe(widgetUpdater)
@@ -67,66 +54,23 @@ class KotatsuApp : Application() {
private fun initKoin() {
startKoin {
androidLogger(Level.ERROR)
androidContext(applicationContext)
androidContext(this@KotatsuApp)
modules(
networkModule,
databaseModule,
githubModule,
uiModule,
module {
single<CookieJar> {
PersistentCookieJar(
SetCookieCache(),
SharedPrefsCookiePersistor(applicationContext)
)
}
factory {
okHttp(get())
.cache(CacheUtils.createHttpCache(applicationContext))
.build()
}
single {
mangaDb().build()
}
single {
MangaLoaderContext()
}
single {
AppSettings(applicationContext)
}
single {
PagesCache(applicationContext)
}
single { FavouritesRepository(get()) }
single { HistoryRepository(get()) }
single { TrackingRepository(get()) }
single { MangaDataRepository(get()) }
single { MangaSearchRepository() }
single { MangaLoaderContext() }
single { AppSettings(get()) }
single { PagesCache(get()) }
}
)
}
}
private fun initCoil(cookieJar: CookieJar) {
Coil.setImageLoader(
ImageLoader.Builder(applicationContext)
.okHttpClient(
okHttp(cookieJar)
.cache(CoilUtils.createDefaultCache(applicationContext))
.build()
).componentRegistry(
ComponentRegistry.Builder()
.add(CbzFetcher())
.build()
)
.build()
)
}
private fun okHttp(cookieJar: CookieJar) = OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS)
cookieJar(cookieJar)
addInterceptor(UserAgentInterceptor)
}
private fun mangaDb() = Room.databaseBuilder(
applicationContext,
MangaDatabase::class.java,
"kotatsu-db"
).addMigrations(Migration1To2, Migration2To3, Migration3To4, Migration4To5, Migration5To6)
.addCallback(DatabasePrePopulateCallback(resources))
}

View File

@@ -0,0 +1,25 @@
package org.koitharu.kotatsu.core.db
import androidx.room.Room
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
import org.koitharu.kotatsu.core.db.migrations.*
val databaseModule
get() = module {
single {
Room.databaseBuilder(
androidContext(),
MangaDatabase::class.java,
"kotatsu-db"
).addMigrations(
Migration1To2(),
Migration2To3(),
Migration3To4(),
Migration4To5(),
Migration5To6()
).addCallback(
DatabasePrePopulateCallback(androidContext().resources)
).build()
}
}

View File

@@ -1,47 +0,0 @@
package org.koitharu.kotatsu.core.db
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
import org.koitharu.kotatsu.core.db.entity.MangaEntity
@Dao
abstract class HistoryDao {
/**
* @hide
*/
@Transaction
@Query("SELECT * FROM history ORDER BY updated_at DESC LIMIT :limit OFFSET :offset")
abstract suspend fun findAll(offset: Int, limit: Int): List<HistoryWithManga>
@Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM history)")
abstract suspend fun findAllManga(): List<MangaEntity>
@Query("SELECT * FROM history WHERE manga_id = :id")
abstract suspend fun find(id: Long): HistoryEntity?
@Query("DELETE FROM history")
abstract suspend fun clear()
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract suspend fun insert(entity: HistoryEntity): Long
@Query("UPDATE history SET page = :page, chapter_id = :chapterId, scroll = :scroll, updated_at = :updatedAt WHERE manga_id = :mangaId")
abstract suspend fun update(mangaId: Long, page: Int, chapterId: Long, scroll: Float, updatedAt: Long): Int
@Query("DELETE FROM history WHERE manga_id = :mangaId")
abstract suspend fun delete(mangaId: Long)
suspend fun update(entity: HistoryEntity) = update(entity.mangaId, entity.page, entity.chapterId, entity.scroll, entity.updatedAt)
@Transaction
open suspend fun upsert(entity: HistoryEntity): Boolean {
return if (update(entity) == 0) {
insert(entity)
true
} else false
}
}

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.db
import androidx.room.Database
import androidx.room.RoomDatabase
import org.koitharu.kotatsu.core.db.dao.*
import org.koitharu.kotatsu.core.db.entity.*
@Database(

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.Dao
import androidx.room.Insert

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.FavouriteEntity

View File

@@ -0,0 +1,54 @@
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
import org.koitharu.kotatsu.core.db.entity.MangaEntity
@Dao
abstract class HistoryDao {
/**
* @hide
*/
@Transaction
@Query("SELECT * FROM history ORDER BY updated_at DESC LIMIT :limit OFFSET :offset")
abstract suspend fun findAll(offset: Int, limit: Int): List<HistoryWithManga>
@Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM history)")
abstract suspend fun findAllManga(): List<MangaEntity>
@Query("SELECT * FROM history WHERE manga_id = :id")
abstract suspend fun find(id: Long): HistoryEntity?
@Query("DELETE FROM history")
abstract suspend fun clear()
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract suspend fun insert(entity: HistoryEntity): Long
@Query("UPDATE history SET page = :page, chapter_id = :chapterId, scroll = :scroll, updated_at = :updatedAt WHERE manga_id = :mangaId")
abstract suspend fun update(
mangaId: Long,
page: Int,
chapterId: Long,
scroll: Float,
updatedAt: Long
): Int
@Query("DELETE FROM history WHERE manga_id = :mangaId")
abstract suspend fun delete(mangaId: Long)
suspend fun update(entity: HistoryEntity) =
update(entity.mangaId, entity.page, entity.chapterId, entity.scroll, entity.updatedAt)
@Transaction
open suspend fun upsert(entity: HistoryEntity): Boolean {
return if (update(entity) == 0) {
insert(entity)
true
} else false
}
}

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.MangaEntity

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.TagEntity

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.TrackLogEntity

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.db
package org.koitharu.kotatsu.core.db.dao
import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.TrackEntity

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
object Migration1To2 : Migration(1, 2) {
class Migration1To2 : Migration(1, 2) {
/**
* Adding foreign keys
*/

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
object Migration2To3 : Migration(2, 3) {
class Migration2To3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE history ADD COLUMN scroll REAL NOT NULL DEFAULT 0")

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
object Migration3To4 : Migration(3, 4) {
class Migration3To4 : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS tracks (manga_id INTEGER NOT NULL, chapters_total INTEGER NOT NULL, last_chapter_id INTEGER NOT NULL, chapters_new INTEGER NOT NULL, last_check INTEGER NOT NULL, last_notified_id INTEGER NOT NULL, PRIMARY KEY(manga_id), FOREIGN KEY(manga_id) REFERENCES manga(manga_id) ON UPDATE NO ACTION ON DELETE CASCADE )")

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
object Migration4To5 : Migration(4, 5) {
class Migration4To5 : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE favourite_categories ADD COLUMN sort_key INTEGER NOT NULL DEFAULT 0")

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
object Migration5To6 : Migration(5, 6) {
class Migration5To6 : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS track_logs (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, manga_id INTEGER NOT NULL, chapters TEXT NOT NULL, created_at INTEGER NOT NULL, FOREIGN KEY(manga_id) REFERENCES manga(manga_id) ON UPDATE NO ACTION ON DELETE CASCADE)")

View File

@@ -0,0 +1,10 @@
package org.koitharu.kotatsu.core.github
import org.koin.dsl.module
val githubModule
get() = module {
single {
GithubRepository(get())
}
}

View File

@@ -2,14 +2,10 @@ package org.koitharu.kotatsu.core.github
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koitharu.kotatsu.utils.ext.await
import org.koitharu.kotatsu.utils.ext.parseJson
class GithubRepository : KoinComponent {
private val okHttp by inject<OkHttpClient>()
class GithubRepository(private val okHttp: OkHttpClient) {
suspend fun getLatestVersion(): AppVersion {
val request = Request.Builder()

View File

@@ -2,9 +2,12 @@ package org.koitharu.kotatsu.core.local
import java.io.File
import java.io.FilenameFilter
import java.util.*
class CbzFilter : FilenameFilter {
override fun accept(dir: File, name: String) =
name.endsWith(".cbz", ignoreCase = true) || name.endsWith(".zip", ignoreCase = true)
override fun accept(dir: File, name: String): Boolean {
val ext = name.substringAfterLast('.', "").toLowerCase(Locale.ROOT)
return ext == "cbz" || ext == "zip"
}
}

View File

@@ -0,0 +1,32 @@
package org.koitharu.kotatsu.core.network
import okhttp3.CookieJar
import okhttp3.OkHttpClient
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
import org.koitharu.kotatsu.core.network.cookies.PersistentCookieJar
import org.koitharu.kotatsu.core.network.cookies.cache.SetCookieCache
import org.koitharu.kotatsu.core.network.cookies.persistence.SharedPrefsCookiePersistor
import org.koitharu.kotatsu.core.parser.UserAgentInterceptor
import org.koitharu.kotatsu.utils.CacheUtils
import java.util.concurrent.TimeUnit
val networkModule
get() = module {
single<CookieJar> {
PersistentCookieJar(
SetCookieCache(),
SharedPrefsCookiePersistor(androidContext())
)
}
single {
OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS)
cookieJar(get())
cache(CacheUtils.createHttpCache(androidContext()))
addInterceptor(UserAgentInterceptor())
}.build()
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies
package org.koitharu.kotatsu.core.network.cookies
import okhttp3.CookieJar

View File

@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies
package org.koitharu.kotatsu.core.network.cookies
import okhttp3.Cookie
import okhttp3.HttpUrl
import org.koitharu.kotatsu.core.local.cookies.cache.CookieCache
import org.koitharu.kotatsu.core.local.cookies.persistence.CookiePersistor
import org.koitharu.kotatsu.core.network.cookies.cache.CookieCache
import org.koitharu.kotatsu.core.network.cookies.persistence.CookiePersistor
import java.util.*
class PersistentCookieJar(

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies.cache
package org.koitharu.kotatsu.core.network.cookies.cache
import okhttp3.Cookie

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies.cache
package org.koitharu.kotatsu.core.network.cookies.cache
import okhttp3.Cookie
import java.util.*

View File

@@ -13,16 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies.cache
package org.koitharu.kotatsu.core.network.cookies.cache
import okhttp3.Cookie
import org.koitharu.kotatsu.core.local.cookies.cache.IdentifiableCookie.Companion.decorateAll
import org.koitharu.kotatsu.core.network.cookies.cache.IdentifiableCookie.Companion.decorateAll
import java.util.*
import java.util.concurrent.ConcurrentHashMap
class SetCookieCache : CookieCache {
private val cookies: MutableSet<IdentifiableCookie> = Collections.newSetFromMap(ConcurrentHashMap())
private val cookies: MutableSet<IdentifiableCookie> =
Collections.newSetFromMap(ConcurrentHashMap())
override fun addAll(newCookies: Collection<Cookie>) {
for (cookie in decorateAll(newCookies)) {

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies.persistence
package org.koitharu.kotatsu.core.network.cookies.persistence
import okhttp3.Cookie
@@ -23,6 +23,7 @@ import okhttp3.Cookie
interface CookiePersistor {
fun loadAll(): List<Cookie>
/**
* Persist all cookies, existing cookies will be overwritten.
*

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies.persistence
package org.koitharu.kotatsu.core.network.cookies.persistence
import android.util.Log
import okhttp3.Cookie
@@ -49,7 +49,8 @@ class SerializableCookie : Serializable {
fun decode(encodedCookie: String): Cookie? {
val bytes = hexStringToByteArray(encodedCookie)
val byteArrayInputStream = ByteArrayInputStream(
bytes)
bytes
)
var cookie: Cookie? = null
var objectInputStream: ObjectInputStream? = null
try {
@@ -107,6 +108,7 @@ class SerializableCookie : Serializable {
const val serialVersionUID = -8594045714036645534L
private const val NON_VALID_EXPIRES_AT = -1L
/**
* Using some super basic byte array &lt;-&gt; hex conversions so we don't
* have to rely on any large Base64 libraries. Can be overridden if you
@@ -141,7 +143,7 @@ class SerializableCookie : Serializable {
var i = 0
while (i < len) {
data[i / 2] = ((Character.digit(hexString[i], 16) shl 4) + Character
.digit(hexString[i + 1], 16)).toByte()
.digit(hexString[i + 1], 16)).toByte()
i += 2
}
return data

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.koitharu.kotatsu.core.local.cookies.persistence
package org.koitharu.kotatsu.core.network.cookies.persistence
import android.annotation.SuppressLint
import android.content.Context
@@ -25,7 +25,12 @@ import java.util.*
class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreferences) :
CookiePersistor {
constructor(context: Context) : this(context.getSharedPreferences("cookies", Context.MODE_PRIVATE))
constructor(context: Context) : this(
context.getSharedPreferences(
"cookies",
Context.MODE_PRIVATE
)
)
override fun loadAll(): List<Cookie> {
val cookies: MutableList<Cookie> = ArrayList(sharedPreferences.all.size)

View File

@@ -0,0 +1,9 @@
package org.koitharu.kotatsu.core.parser
import org.koin.dsl.bind
import org.koin.dsl.module
val parserModule
get() = module {
single { LocalMangaRepository() } bind MangaRepository::class
}

View File

@@ -1,13 +1,11 @@
package org.koitharu.kotatsu.core.parser
import android.annotation.SuppressLint
import android.os.Build
import okhttp3.Interceptor
import org.koitharu.kotatsu.BuildConfig
import java.util.*
@SuppressLint("ConstantLocale")
object UserAgentInterceptor : Interceptor {
class UserAgentInterceptor : Interceptor {
private val userAgent = "Kotatsu/%s (Android %s; %s; %s %s; %s)".format(
BuildConfig.VERSION_NAME,

View File

@@ -1,8 +1,6 @@
package org.koitharu.kotatsu.domain
import androidx.room.withTransaction
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.MangaEntity
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity
@@ -10,9 +8,7 @@ import org.koitharu.kotatsu.core.db.entity.TagEntity
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.prefs.ReaderMode
class MangaDataRepository : KoinComponent {
private val db: MangaDatabase by inject()
class MangaDataRepository(private val db: MangaDatabase) {
suspend fun savePreferences(manga: Manga, mode: ReaderMode) {
val tags = manga.tags.map(TagEntity.Companion::fromMangaTag)

View File

@@ -34,6 +34,7 @@ object MangaProviderFactory : KoinComponent {
}
}
@Deprecated("Use DI")
fun createLocal(): LocalMangaRepository {
var instance = cache[MangaSource.LOCAL]?.get()
if (instance == null) {

View File

@@ -2,13 +2,12 @@ package org.koitharu.kotatsu.domain
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import org.koin.core.component.KoinComponent
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.SortOrder
import java.util.*
class MangaSearchRepository : KoinComponent {
class MangaSearchRepository {
fun globalSearch(query: String, batchSize: Int = 4): Flow<List<Manga>> = flow {
val sources = MangaProviderFactory.getSources(false)

View File

@@ -4,8 +4,6 @@ import androidx.collection.ArraySet
import androidx.room.withTransaction
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.FavouriteCategoryEntity
import org.koitharu.kotatsu.core.db.entity.FavouriteEntity
@@ -14,9 +12,7 @@ import org.koitharu.kotatsu.core.db.entity.TagEntity
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.model.Manga
class FavouritesRepository : KoinComponent {
private val db: MangaDatabase by inject()
class FavouritesRepository(private val db: MangaDatabase) {
suspend fun getAllManga(): List<Manga> {
val entities = db.favouritesDao.findAll()

View File

@@ -1,8 +1,8 @@
package org.koitharu.kotatsu.domain.favourites
interface OnFavouritesChangeListener {
fun interface OnFavouritesChangeListener {
fun onFavouritesChanged(mangaId: Long)
fun onCategoriesChanged()
fun onCategoriesChanged() = Unit
}

View File

@@ -14,10 +14,9 @@ import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.domain.tracking.TrackingRepository
class HistoryRepository : KoinComponent {
class HistoryRepository(private val db: MangaDatabase) : KoinComponent {
private val db: MangaDatabase by inject()
private val trackingRepository by lazy(::TrackingRepository)
private val trackingRepository by inject<TrackingRepository>()
suspend fun getList(offset: Int, limit: Int = 20): List<Manga> {
val entities = db.historyDao.findAll(offset, limit)

View File

@@ -1,8 +1,6 @@
package org.koitharu.kotatsu.domain.tracking
import androidx.room.withTransaction
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.TrackEntity
import org.koitharu.kotatsu.core.db.entity.TrackLogEntity
@@ -10,9 +8,7 @@ import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.domain.MangaProviderFactory
import java.util.*
class TrackingRepository : KoinComponent {
private val db: MangaDatabase by inject()
class TrackingRepository(private val db: MangaDatabase) {
suspend fun getNewChaptersCount(mangaId: Long): Int {
val entity = db.tracksDao.find(mangaId) ?: return 0

View File

@@ -1,14 +1,17 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.app.Dialog
import android.os.Bundle
import android.view.View
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import moxy.MvpAppCompatDialogFragment
abstract class AlertDialogFragment(@LayoutRes private val layoutResId: Int) : MvpAppCompatDialogFragment() {
abstract class AlertDialogFragment(
@LayoutRes private val layoutResId: Int
) : MvpAppCompatDialogFragment() {
private var rootView: View? = null
@@ -24,12 +27,13 @@ abstract class AlertDialogFragment(@LayoutRes private val layoutResId: Int) : Mv
.create()
}
@CallSuper
override fun onDestroyView() {
rootView = null
super.onDestroyView()
}
override fun getView(): View? {
final override fun getView(): View? {
return rootView
}

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.view.MenuItem
import android.view.View

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.app.Dialog
import android.os.Bundle
@@ -13,7 +13,7 @@ import org.koitharu.kotatsu.utils.UiUtils
abstract class BaseBottomSheet(@LayoutRes private val layoutResId: Int) :
MvpBottomSheetDialogFragment() {
override fun onCreateView(
final override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?

View File

@@ -1,14 +1,19 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.content.Context
import android.os.Parcelable
import androidx.annotation.LayoutRes
import coil.ImageLoader
import moxy.MvpAppCompatFragment
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.utils.delegates.ParcelableArgumentDelegate
import org.koitharu.kotatsu.utils.delegates.StringArgumentDelegate
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) :
MvpAppCompatFragment(contentLayoutId) {
abstract class BaseFragment(
@LayoutRes contentLayoutId: Int
) : MvpAppCompatFragment(contentLayoutId) {
protected val coil by inject<ImageLoader>()
fun stringArg(name: String) = StringArgumentDelegate(name)

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.graphics.Color
import android.os.Build
@@ -12,11 +12,11 @@ abstract class BaseFullscreenActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
with(window) {
// addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
statusBarColor = Color.TRANSPARENT
navigationBarColor = Color.TRANSPARENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
attributes.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
}
showSystemUI()

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import moxy.MvpView
import moxy.viewstate.strategy.alias.AddToEndSingle

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import androidx.annotation.StringRes
import androidx.preference.Preference

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import kotlinx.coroutines.*
import moxy.MvpPresenter

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.app.Service
import android.content.Intent
@@ -7,18 +7,16 @@ import androidx.annotation.CallSuper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.cancel
abstract class BaseService : Service(), CoroutineScope {
abstract class BaseService : Service() {
private val job = SupervisorJob()
final override val coroutineContext: CoroutineContext
get() = Dispatchers.Main.immediate + job
@Suppress("MemberVisibilityCanBePrivate")
val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
@CallSuper
override fun onDestroy() {
job.cancel()
serviceScope.cancel()
super.onDestroy()
}

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.content.Context
import android.view.View
@@ -8,8 +8,10 @@ import org.koitharu.kotatsu.utils.ext.getThemeColor
class ChipsFactory(val context: Context) {
fun create(convertView: Chip? = null, text: CharSequence, @DrawableRes iconRes: Int = 0,
tag: Any? = null, onClickListener: View.OnClickListener? = null): Chip {
fun create(
convertView: Chip? = null, text: CharSequence, @DrawableRes iconRes: Int = 0,
tag: Any? = null, onClickListener: View.OnClickListener? = null
): Chip {
val chip = convertView ?: Chip(context).apply {
setTextColor(context.getThemeColor(android.R.attr.textColorPrimary))
isCloseIconVisible = false

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common
package org.koitharu.kotatsu.ui.base
import android.util.ArrayMap
import moxy.MvpPresenter

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.dialog
package org.koitharu.kotatsu.ui.base.dialog
import android.annotation.SuppressLint
import android.content.Context

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.dialog
package org.koitharu.kotatsu.ui.base.dialog
import android.content.Context
import android.content.DialogInterface

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.dialog
package org.koitharu.kotatsu.ui.base.dialog
import android.annotation.SuppressLint
import android.content.Context
@@ -11,15 +11,17 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.android.synthetic.main.dialog_input.view.*
import org.koitharu.kotatsu.R
class TextInputDialog private constructor(private val delegate: AlertDialog) :
DialogInterface by delegate {
class TextInputDialog private constructor(
private val delegate: AlertDialog
) : DialogInterface by delegate {
fun show() = delegate.show()
class Builder(context: Context) {
@SuppressLint("InflateParams")
private val view = LayoutInflater.from(context).inflate(R.layout.dialog_input, null, false)
private val view = LayoutInflater.from(context)
.inflate(R.layout.dialog_input, null, false)
private val delegate = MaterialAlertDialogBuilder(context)
.setView(view)

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView

View File

@@ -1,8 +1,7 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import okhttp3.internal.toImmutableList
import org.koin.core.component.KoinComponent
import org.koitharu.kotatsu.utils.ext.replaceWith
@@ -12,7 +11,7 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
protected val dataSet = ArrayList<T>() //TODO make private
val items get() = dataSet.toImmutableList()
val items get() = dataSet as List<T>
val hasItems get() = dataSet.isNotEmpty()

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import android.view.View
import android.view.ViewGroup

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import android.view.View

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import androidx.recyclerview.widget.RecyclerView

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import android.view.ViewGroup

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list
package org.koitharu.kotatsu.ui.base.list
import android.view.View
import android.view.ViewGroup

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list.decor
package org.koitharu.kotatsu.ui.base.list.decor
import android.content.Context
import android.graphics.Canvas

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list.decor
package org.koitharu.kotatsu.ui.base.list.decor
import android.graphics.Canvas
import android.graphics.Rect

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.list.decor
package org.koitharu.kotatsu.ui.base.list.decor
import android.graphics.Rect
import android.view.View

View File

@@ -0,0 +1,21 @@
package org.koitharu.kotatsu.ui.base
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
val uiModule
get() = module {
single {
ImageLoader.Builder(androidContext())
.okHttpClient(get<OkHttpClient>())
.componentRegistry(
ComponentRegistry.Builder()
.add(CbzFetcher())
.build()
).build()
}
}

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.widgets
package org.koitharu.kotatsu.ui.base.widgets
import android.content.Context
import android.util.AttributeSet
@@ -61,7 +61,6 @@ class CheckableImageView @JvmOverloads constructor(
private companion object {
@JvmStatic
private val CHECKED_STATE_SET = intArrayOf(android.R.attr.state_checked)
}
}

View File

@@ -1,10 +1,10 @@
package org.koitharu.kotatsu.ui.common.widgets
package org.koitharu.kotatsu.ui.base.widgets
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.res.use
import androidx.core.content.withStyledAttributes
import org.koitharu.kotatsu.R
@@ -15,10 +15,9 @@ class CoverImageView @JvmOverloads constructor(
private var orientation: Int = HORIZONTAL
init {
context.theme.obtainStyledAttributes(attrs, R.styleable.CoverImageView, defStyleAttr, 0)
.use {
orientation = it.getInt(R.styleable.CoverImageView_android_orientation, HORIZONTAL)
}
context.withStyledAttributes(attrs, R.styleable.CoverImageView, defStyleAttr) {
orientation = getInt(R.styleable.CoverImageView_android_orientation, HORIZONTAL)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common.widgets
package org.koitharu.kotatsu.ui.base.widgets
import android.content.Context
import android.util.AttributeSet

View File

@@ -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.common.BaseActivity
import org.koitharu.kotatsu.ui.base.BaseActivity
@SuppressLint("SetJavaScriptEnabled")
class BrowserActivity : BaseActivity(), BrowserCallback {

View File

@@ -7,7 +7,7 @@ import kotlinx.android.synthetic.main.item_chapter.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.domain.history.ChapterExtra
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.utils.ext.getThemeColor
class ChapterHolder(parent: ViewGroup) :

View File

@@ -4,8 +4,8 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.domain.history.ChapterExtra
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
class ChaptersAdapter(onItemClickListener: OnRecyclerItemClickListener<MangaChapter>) :
BaseRecyclerAdapter<MangaChapter, ChapterExtra>(onItemClickListener) {

View File

@@ -15,8 +15,8 @@ import kotlinx.android.synthetic.main.fragment_chapters.*
import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.ui.common.BaseFragment
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
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.utils.ext.resolveDp

View File

@@ -26,8 +26,8 @@ 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.core.model.MangaSource
import org.koitharu.kotatsu.ui.base.BaseActivity
import org.koitharu.kotatsu.ui.browser.BrowserActivity
import org.koitharu.kotatsu.ui.common.BaseActivity
import org.koitharu.kotatsu.ui.download.DownloadService
import org.koitharu.kotatsu.utils.MangaShortcut
import org.koitharu.kotatsu.utils.ShareHelper

View File

@@ -6,7 +6,6 @@ import androidx.core.net.toUri
import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import coil.load
import com.google.android.material.chip.Chip
import kotlinx.android.synthetic.main.fragment_details.*
import kotlinx.coroutines.Dispatchers
@@ -17,15 +16,12 @@ import org.koitharu.kotatsu.R
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.common.BaseFragment
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.utils.FileSizeUtils
import org.koitharu.kotatsu.utils.ext.addChips
import org.koitharu.kotatsu.utils.ext.showPopupMenu
import org.koitharu.kotatsu.utils.ext.textAndVisible
import org.koitharu.kotatsu.utils.ext.toFileOrNull
import org.koitharu.kotatsu.utils.ext.*
import kotlin.math.roundToInt
class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetailsView,
@@ -42,11 +38,11 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
override fun onMangaUpdated(manga: Manga) {
this.manga = manga
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) {
fallback(R.drawable.ic_placeholder)
crossfade(true)
lifecycle(this@MangaDetailsFragment)
}
imageView_cover.newImageRequest(manga.largeCoverUrl ?: manga.coverUrl)
.fallback(R.drawable.ic_placeholder)
.crossfade(true)
.lifecycle(this)
.enqueueWith(coil)
textView_title.text = manga.title
textView_subtitle.textAndVisible = manga.altTitle
textView_description.text = manga.description?.parseAsHtml()?.takeUnless(Spanned::isBlank)
@@ -138,9 +134,11 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
}
v is Chip -> {
when (val tag = v.tag) {
is String -> MangaSearchSheet.show(activity?.supportFragmentManager
?: childFragmentManager,
manga?.source ?: return, tag)
is String -> MangaSearchSheet.show(
activity?.supportFragmentManager
?: childFragmentManager,
manga?.source ?: return, tag
)
}
}
}

View File

@@ -7,6 +7,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import moxy.InjectViewState
import moxy.presenterScope
import org.koin.core.component.inject
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
import org.koitharu.kotatsu.core.model.Manga
@@ -20,8 +21,8 @@ import org.koitharu.kotatsu.domain.favourites.OnFavouritesChangeListener
import org.koitharu.kotatsu.domain.history.HistoryRepository
import org.koitharu.kotatsu.domain.history.OnHistoryChangeListener
import org.koitharu.kotatsu.domain.tracking.TrackingRepository
import org.koitharu.kotatsu.ui.common.BasePresenter
import org.koitharu.kotatsu.ui.common.SharedPresenterHolder
import org.koitharu.kotatsu.ui.base.BasePresenter
import org.koitharu.kotatsu.ui.base.SharedPresenterHolder
import org.koitharu.kotatsu.utils.ext.safe
import java.io.IOException
@@ -29,18 +30,15 @@ import java.io.IOException
class MangaDetailsPresenter private constructor(private val key: Int) :
BasePresenter<MangaDetailsView>(), OnHistoryChangeListener, OnFavouritesChangeListener {
private lateinit var historyRepository: HistoryRepository
private lateinit var favouritesRepository: FavouritesRepository
private lateinit var trackingRepository: TrackingRepository
private lateinit var searchRepository: MangaSearchRepository
private val historyRepository by inject<HistoryRepository>()
private val favouritesRepository by inject<FavouritesRepository>()
private val trackingRepository by inject<TrackingRepository>()
private val searchRepository by inject<MangaSearchRepository>()
private val mangaDataRepository by inject<MangaDataRepository>()
private var manga: Manga? = null
override fun onFirstViewAttach() {
historyRepository = HistoryRepository()
favouritesRepository = FavouritesRepository()
trackingRepository = TrackingRepository()
searchRepository = MangaSearchRepository()
super.onFirstViewAttach()
HistoryRepository.subscribe(this)
FavouritesRepository.subscribe(this)
@@ -51,7 +49,7 @@ class MangaDetailsPresenter private constructor(private val key: Int) :
viewState.onLoadingStateChanged(true)
try {
val manga = withContext(Dispatchers.IO) {
MangaDataRepository().findMangaById(id)
mangaDataRepository.findMangaById(id)
} ?: throw MangaNotFoundException("Cannot find manga by id")
viewState.onMangaUpdated(manga)
loadDetails(manga, true)
@@ -105,7 +103,7 @@ class MangaDetailsPresenter private constructor(private val key: Int) :
val original = repository.getRemoteManga(manga)
repository.delete(manga) || throw IOException("Unable to delete file")
safe {
HistoryRepository().deleteOrSwap(manga, original)
historyRepository.deleteOrSwap(manga, original)
}
}
viewState.onMangaRemoved(manga)
@@ -193,8 +191,6 @@ class MangaDetailsPresenter private constructor(private val key: Int) :
}
}
override fun onCategoriesChanged() = Unit
override fun onDestroy() {
HistoryRepository.unsubscribe(this)
FavouritesRepository.unsubscribe(this)

View File

@@ -8,7 +8,7 @@ import moxy.viewstate.strategy.alias.SingleState
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.common.BaseMvpView
import org.koitharu.kotatsu.ui.base.BaseMvpView
interface MangaDetailsView : BaseMvpView {

View File

@@ -7,7 +7,7 @@ import android.os.PowerManager
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.core.content.ContextCompat
import coil.Coil
import coil.ImageLoader
import coil.request.ImageRequest
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
@@ -22,8 +22,8 @@ import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.domain.local.MangaZip
import org.koitharu.kotatsu.ui.common.BaseService
import org.koitharu.kotatsu.ui.common.dialog.CheckBoxAlertDialog
import org.koitharu.kotatsu.ui.base.BaseService
import org.koitharu.kotatsu.ui.base.dialog.CheckBoxAlertDialog
import org.koitharu.kotatsu.utils.CacheUtils
import org.koitharu.kotatsu.utils.ext.*
import java.io.File
@@ -40,6 +40,7 @@ class DownloadService : BaseService() {
private val okHttp by inject<OkHttpClient>()
private val cache by inject<PagesCache>()
private val settings by inject<AppSettings>()
private val imageLoader by inject<ImageLoader>()
private val jobs = HashMap<Int, Job>()
private val mutex = Mutex()
@@ -74,7 +75,7 @@ class DownloadService : BaseService() {
}
private fun downloadManga(manga: Manga, chaptersIds: Set<Long>?, startId: Int): Job {
return launch(Dispatchers.Default) {
return serviceScope.launch(Dispatchers.Default) {
mutex.lock()
wakeLock.acquire(TimeUnit.HOURS.toMillis(1))
notification.fillFrom(manga)
@@ -88,7 +89,7 @@ class DownloadService : BaseService() {
try {
val repo = MangaProviderFactory.create(manga.source)
val cover = safe {
Coil.execute(
imageLoader.execute(
ImageRequest.Builder(this@DownloadService)
.data(manga.coverUrl)
.build()

View File

@@ -9,7 +9,7 @@ import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.AlertDialogFragment
import org.koitharu.kotatsu.ui.base.AlertDialogFragment
class ListModeSelectDialog : AlertDialogFragment(R.layout.dialog_list_mode), View.OnClickListener {
@@ -56,7 +56,8 @@ class ListModeSelectDialog : AlertDialogFragment(R.layout.dialog_list_mode), Vie
private const val TAG = "ListModeSelectDialog"
fun show(fm: FragmentManager) = ListModeSelectDialog()
.show(fm,
.show(
fm,
TAG
)
}

View File

@@ -24,7 +24,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.AppSection
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.ui.common.BaseActivity
import org.koitharu.kotatsu.ui.base.BaseActivity
import org.koitharu.kotatsu.ui.list.favourites.FavouritesContainerFragment
import org.koitharu.kotatsu.ui.list.feed.FeedFragment
import org.koitharu.kotatsu.ui.list.history.HistoryListFragment

View File

@@ -1,18 +1,20 @@
package org.koitharu.kotatsu.ui.list
import moxy.InjectViewState
import org.koin.core.component.inject
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.domain.history.HistoryRepository
import org.koitharu.kotatsu.ui.common.BasePresenter
import org.koitharu.kotatsu.ui.base.BasePresenter
import org.koitharu.kotatsu.ui.reader.ReaderState
@InjectViewState
class MainPresenter : BasePresenter<MainView>() {
private val historyRepository by inject<HistoryRepository>()
fun openLastReader() {
launchLoadingJob {
val historyRepository = HistoryRepository()
val manga = historyRepository.getList(0, 1).firstOrNull()
?: throw EmptyHistoryException()
val history = historyRepository.getOne(manga) ?: throw EmptyHistoryException()

View File

@@ -1,7 +1,7 @@
package org.koitharu.kotatsu.ui.list
import moxy.viewstate.strategy.alias.OneExecution
import org.koitharu.kotatsu.ui.common.BaseMvpView
import org.koitharu.kotatsu.ui.base.BaseMvpView
import org.koitharu.kotatsu.ui.reader.ReaderState
interface MainView : BaseMvpView {

View File

@@ -1,27 +1,35 @@
package org.koitharu.kotatsu.ui.list
import android.view.ViewGroup
import coil.clear
import coil.load
import coil.ImageLoader
import coil.request.Disposable
import kotlinx.android.synthetic.main.item_manga_grid.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
class MangaGridHolder(parent: ViewGroup) : BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_grid) {
class MangaGridHolder(parent: ViewGroup) :
BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_grid) {
private val coil by inject<ImageLoader>()
private var imageRequest: Disposable? = null
override fun onBind(data: Manga, extra: MangaHistory?) {
imageView_cover.clear()
textView_title.text = data.title
imageView_cover.load(data.coverUrl) {
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder)
}
imageRequest?.dispose()
imageRequest = imageView_cover.newImageRequest(data.coverUrl)
.placeholder(R.drawable.ic_placeholder)
.fallback(R.drawable.ic_placeholder)
.error(R.drawable.ic_placeholder)
.enqueueWith(coil)
}
override fun onRecycled() {
imageView_cover.clear()
imageRequest?.dispose()
imageView_cover.setImageDrawable(null)
}
}

View File

@@ -4,15 +4,15 @@ import android.view.ViewGroup
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
class MangaListAdapter(onItemClickListener: OnRecyclerItemClickListener<Manga>) :
BaseRecyclerAdapter<Manga, MangaHistory?>(onItemClickListener) {
var listMode: ListMode = ListMode.LIST
override fun onCreateViewHolder(parent: ViewGroup) = when(listMode) {
override fun onCreateViewHolder(parent: ViewGroup) = when (listMode) {
ListMode.LIST -> MangaListHolder(parent)
ListMode.DETAILED_LIST -> MangaListDetailsHolder(
parent

View File

@@ -3,29 +3,37 @@ package org.koitharu.kotatsu.ui.list
import android.annotation.SuppressLint
import android.view.ViewGroup
import androidx.core.view.isVisible
import coil.clear
import coil.load
import coil.ImageLoader
import coil.request.Disposable
import kotlinx.android.synthetic.main.item_manga_list_details.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
import org.koitharu.kotatsu.utils.ext.textAndVisible
import kotlin.math.roundToInt
class MangaListDetailsHolder(parent: ViewGroup) : BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list_details) {
class MangaListDetailsHolder(
parent: ViewGroup
) : BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list_details) {
private val coil by inject<ImageLoader>()
private var imageRequest: Disposable? = null
@SuppressLint("SetTextI18n")
override fun onBind(data: Manga, extra: MangaHistory?) {
imageView_cover.clear()
imageRequest?.dispose()
textView_title.text = data.title
textView_subtitle.textAndVisible = data.altTitle
imageView_cover.load(data.coverUrl) {
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder)
}
if(data.rating == Manga.NO_RATING) {
imageView_cover.newImageRequest(data.coverUrl)
.placeholder(R.drawable.ic_placeholder)
.fallback(R.drawable.ic_placeholder)
.error(R.drawable.ic_placeholder)
.enqueueWith(coil)
if (data.rating == Manga.NO_RATING) {
textView_rating.isVisible = false
} else {
textView_rating.text = "${(data.rating * 10).roundToInt()}/10"
@@ -37,6 +45,7 @@ class MangaListDetailsHolder(parent: ViewGroup) : BaseViewHolder<Manga, MangaHis
}
override fun onRecycled() {
imageView_cover.clear()
imageRequest?.dispose()
imageView_cover.setImageDrawable(null)
}
}

View File

@@ -22,13 +22,13 @@ import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.BaseFragment
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.common.list.ProgressBarAdapter
import org.koitharu.kotatsu.ui.common.list.decor.ItemTypeDividerDecoration
import org.koitharu.kotatsu.ui.common.list.decor.SectionItemDecoration
import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.base.BaseFragment
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.base.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.base.list.ProgressBarAdapter
import org.koitharu.kotatsu.ui.base.list.decor.ItemTypeDividerDecoration
import org.koitharu.kotatsu.ui.base.list.decor.SectionItemDecoration
import org.koitharu.kotatsu.ui.base.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.ui.list.filter.FilterAdapter
import org.koitharu.kotatsu.ui.list.filter.OnFilterChangedListener
@@ -48,7 +48,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list),
private var adapter: MangaListAdapter? = null
private var progressAdapter: ProgressBarAdapter? = null
private var paginationListener : PaginationScrollListener? = null
private var paginationListener: PaginationScrollListener? = null
protected var isSwipeRefreshEnabled = true
override fun onCreate(savedInstanceState: Bundle?) {

View File

@@ -1,30 +1,38 @@
package org.koitharu.kotatsu.ui.list
import android.view.ViewGroup
import coil.clear
import coil.load
import coil.ImageLoader
import coil.request.Disposable
import kotlinx.android.synthetic.main.item_manga_list.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
import org.koitharu.kotatsu.utils.ext.textAndVisible
class MangaListHolder(parent: ViewGroup) :
BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list) {
class MangaListHolder(
parent: ViewGroup
) : BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list) {
private val coil by inject<ImageLoader>()
private var imageRequest: Disposable? = null
override fun onBind(data: Manga, extra: MangaHistory?) {
imageView_cover.clear()
imageRequest?.dispose()
textView_title.text = data.title
textView_subtitle.textAndVisible = data.tags.joinToString(", ") { it.title }
imageView_cover.load(data.coverUrl) {
placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder)
}
imageRequest = imageView_cover.newImageRequest(data.coverUrl)
.placeholder(R.drawable.ic_placeholder)
.fallback(R.drawable.ic_placeholder)
.error(R.drawable.ic_placeholder)
.enqueueWith(coil)
}
override fun onRecycled() {
imageView_cover.clear()
imageRequest?.dispose()
imageView_cover.setImageDrawable(null)
}
}

View File

@@ -21,11 +21,11 @@ import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.BaseBottomSheet
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.common.list.ProgressBarAdapter
import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.base.BaseBottomSheet
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.base.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.base.list.ProgressBarAdapter
import org.koitharu.kotatsu.ui.base.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.utils.UiUtils
import org.koitharu.kotatsu.utils.ext.*

View File

@@ -9,7 +9,7 @@ import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaFilter
import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.ui.common.BaseMvpView
import org.koitharu.kotatsu.ui.base.BaseMvpView
interface MangaListView<E> : BaseMvpView {

View File

@@ -13,14 +13,15 @@ import org.koitharu.kotatsu.R
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.common.BaseFragment
import org.koitharu.kotatsu.ui.base.BaseFragment
import org.koitharu.kotatsu.ui.list.favourites.categories.CategoriesActivity
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesPresenter
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView
import java.util.*
import kotlin.collections.ArrayList
class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites), FavouriteCategoriesView,
class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
FavouriteCategoriesView,
OnFavouritesChangeListener {
private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)

View File

@@ -1,36 +1,28 @@
package org.koitharu.kotatsu.ui.list.favourites
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import moxy.InjectViewState
import moxy.presenterScope
import org.koin.core.component.get
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.ui.common.BasePresenter
import org.koitharu.kotatsu.ui.base.BasePresenter
import org.koitharu.kotatsu.ui.list.MangaListView
@InjectViewState
class FavouritesListPresenter : BasePresenter<MangaListView<Unit>>() {
private lateinit var repository: FavouritesRepository
override fun onFirstViewAttach() {
repository = FavouritesRepository()
super.onFirstViewAttach()
}
private val repository = get<FavouritesRepository>()
fun loadList(categoryId: Long, offset: Int) {
presenterScope.launch {
viewState.onLoadingStateChanged(true)
try {
val list = withContext(Dispatchers.IO) {
if (categoryId == 0L) {
repository.getAllManga(offset = offset)
} else {
repository.getManga(categoryId = categoryId, offset = offset)
}
val list = if (categoryId == 0L) {
repository.getAllManga(offset = offset)
} else {
repository.getManga(categoryId = categoryId, offset = offset)
}
if (offset == 0) {
viewState.onListChanged(list)

View File

@@ -5,10 +5,11 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.list.AdapterUpdater
import org.koitharu.kotatsu.ui.base.list.AdapterUpdater
import org.koitharu.kotatsu.utils.ext.replaceWith
class FavouritesPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment), TabLayoutMediator.TabConfigurationStrategy {
class FavouritesPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment),
TabLayoutMediator.TabConfigurationStrategy {
private val dataSet = ArrayList<FavouriteCategory>()

View File

@@ -17,9 +17,9 @@ import kotlinx.android.synthetic.main.activity_categories.*
import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.BaseActivity
import org.koitharu.kotatsu.ui.common.dialog.TextInputDialog
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.base.BaseActivity
import org.koitharu.kotatsu.ui.base.dialog.TextInputDialog
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.showPopupMenu
@@ -61,7 +61,9 @@ class CategoriesActivity : BaseActivity(), OnRecyclerItemClickListener<Favourite
}
override fun onItemLongClick(item: FavouriteCategory, position: Int, view: View): Boolean {
reorderHelper.startDrag(recyclerView.findViewHolderForAdapterPosition(position) ?: return false)
reorderHelper.startDrag(
recyclerView.findViewHolderForAdapterPosition(position) ?: return false
)
return true
}

View File

@@ -5,9 +5,9 @@ import android.view.MotionEvent
import android.view.ViewGroup
import kotlinx.android.synthetic.main.item_category.*
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
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>() {
@@ -25,7 +25,11 @@ class CategoriesAdapter(private val onItemClickListener: OnRecyclerItemClickList
}
holder.imageView_handle.setOnTouchListener { v, event ->
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
onItemClickListener.onItemLongClick(holder.requireData(), holder.bindingAdapterPosition, v)
onItemClickListener.onItemLongClick(
holder.requireData(),
holder.bindingAdapterPosition,
v
)
} else {
false
}

View File

@@ -4,7 +4,7 @@ import android.view.ViewGroup
import kotlinx.android.synthetic.main.item_category.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
class CategoryHolder(parent: ViewGroup) :
BaseViewHolder<FavouriteCategory, Unit>(parent, R.layout.item_category) {

View File

@@ -3,20 +3,18 @@ package org.koitharu.kotatsu.ui.list.favourites.categories
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import moxy.InjectViewState
import org.koin.core.component.get
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.ui.common.BasePresenter
import org.koitharu.kotatsu.ui.base.BasePresenter
@InjectViewState
class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() {
private lateinit var repository: FavouritesRepository
private val reorderMutex by lazy {
Mutex()
}
private val repository = get<FavouritesRepository>()
private val reorderMutex by lazy(LazyThreadSafetyMode.NONE) { Mutex() }
override fun onFirstViewAttach() {
repository = FavouritesRepository()
super.onFirstViewAttach()
loadAllCategories()
}

View File

@@ -4,7 +4,7 @@ import moxy.viewstate.strategy.AddToEndSingleStrategy
import moxy.viewstate.strategy.StateStrategyType
import moxy.viewstate.strategy.alias.AddToEndSingle
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.BaseMvpView
import org.koitharu.kotatsu.ui.base.BaseMvpView
interface FavouriteCategoriesView : BaseMvpView {

View File

@@ -5,8 +5,8 @@ import android.view.ViewGroup
import android.widget.Checkable
import androidx.core.util.set
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
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>() {

View File

@@ -4,7 +4,7 @@ import android.view.ViewGroup
import kotlinx.android.synthetic.main.item_category_checkable.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
class CategoryCheckableHolder(parent: ViewGroup) :
BaseViewHolder<FavouriteCategory, Boolean>(parent, R.layout.item_category_checkable) {

View File

@@ -10,8 +10,8 @@ import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.ui.common.BaseBottomSheet
import org.koitharu.kotatsu.ui.common.dialog.TextInputDialog
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.utils.ext.getDisplayMessage
@@ -31,7 +31,8 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
super.onViewCreated(view, savedInstanceState)
adapter =
CategoriesSelectAdapter(
this)
this
)
recyclerView_categories.adapter = adapter
textView_add.setOnClickListener {
createCategory()
@@ -86,8 +87,10 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
fun show(fm: FragmentManager, manga: Manga) = FavouriteCategoriesDialog()
.withArgs(1) {
putParcelable(ARG_MANGA, manga)
}.show(fm,
TAG)
putParcelable(ARG_MANGA, manga)
}.show(
fm,
TAG
)
}
}

View File

@@ -2,9 +2,9 @@ package org.koitharu.kotatsu.ui.list.feed
import android.view.ViewGroup
import org.koitharu.kotatsu.core.model.TrackingLogItem
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
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 FeedAdapter(onItemClickListener: OnRecyclerItemClickListener<TrackingLogItem>? = null) :
BaseRecyclerAdapter<TrackingLogItem, Unit>(onItemClickListener) {

View File

@@ -12,10 +12,10 @@ import moxy.MvpDelegate
import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.TrackingLogItem
import org.koitharu.kotatsu.ui.common.BaseFragment
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.base.BaseFragment
import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.base.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.base.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.ui.tracker.TrackWorker
import org.koitharu.kotatsu.utils.ext.callOnScrollListeners
@@ -55,7 +55,7 @@ class FeedFragment : BaseFragment(R.layout.fragment_tracklogs), FeedView,
inflater.inflate(R.menu.opt_feed, menu)
}
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) {
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.action_update -> {
TrackWorker.startNow(requireContext())
Snackbar.make(recyclerView, R.string.feed_will_update_soon, Snackbar.LENGTH_LONG).show()

Some files were not shown because too many files have changed in this diff Show More