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

@@ -95,7 +95,7 @@ dependencies {
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
implementation 'org.koin:koin-android:2.2.0-rc-2' implementation 'org.koin:koin-android:2.2.0-rc-2'
implementation 'io.coil-kt:coil:1.0.0-rc3' implementation 'io.coil-kt:coil-base:1.0.0-rc3'
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0' implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'
implementation 'com.tomclaw.cache:cache:1.0' implementation 'com.tomclaw.cache:cache:1.0'

View File

@@ -3,37 +3,25 @@ package org.koitharu.kotatsu
import android.app.Application import android.app.Application
import android.os.StrictMode import android.os.StrictMode
import androidx.appcompat.app.AppCompatDelegate 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.android.get
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin import org.koin.core.context.startKoin
import org.koin.core.logger.Level
import org.koin.dsl.module import org.koin.dsl.module
import org.koitharu.kotatsu.core.db.DatabasePrePopulateCallback import org.koitharu.kotatsu.core.db.databaseModule
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.github.githubModule
import org.koitharu.kotatsu.core.db.migrations.*
import org.koitharu.kotatsu.core.local.CbzFetcher
import org.koitharu.kotatsu.core.local.PagesCache import org.koitharu.kotatsu.core.local.PagesCache
import org.koitharu.kotatsu.core.local.cookies.PersistentCookieJar import org.koitharu.kotatsu.core.network.networkModule
import org.koitharu.kotatsu.core.local.cookies.cache.SetCookieCache
import org.koitharu.kotatsu.core.local.cookies.persistence.SharedPrefsCookiePersistor
import org.koitharu.kotatsu.core.parser.LocalMangaRepository 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.core.prefs.AppSettings
import org.koitharu.kotatsu.domain.MangaDataRepository
import org.koitharu.kotatsu.domain.MangaLoaderContext import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.domain.MangaSearchRepository
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.domain.history.HistoryRepository 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.utils.AppCrashHandler
import org.koitharu.kotatsu.ui.widget.WidgetUpdater import org.koitharu.kotatsu.ui.widget.WidgetUpdater
import org.koitharu.kotatsu.utils.CacheUtils
import java.util.concurrent.TimeUnit
class KotatsuApp : Application() { class KotatsuApp : Application() {
@@ -57,9 +45,8 @@ class KotatsuApp : Application() {
) )
} }
initKoin() initKoin()
initCoil(get())
Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext)) Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext))
AppCompatDelegate.setDefaultNightMode(AppSettings(this).theme) AppCompatDelegate.setDefaultNightMode(get<AppSettings>().theme)
val widgetUpdater = WidgetUpdater(applicationContext) val widgetUpdater = WidgetUpdater(applicationContext)
FavouritesRepository.subscribe(widgetUpdater) FavouritesRepository.subscribe(widgetUpdater)
HistoryRepository.subscribe(widgetUpdater) HistoryRepository.subscribe(widgetUpdater)
@@ -67,66 +54,23 @@ class KotatsuApp : Application() {
private fun initKoin() { private fun initKoin() {
startKoin { startKoin {
androidLogger(Level.ERROR) androidContext(this@KotatsuApp)
androidContext(applicationContext)
modules( modules(
networkModule,
databaseModule,
githubModule,
uiModule,
module { module {
single<CookieJar> { single { FavouritesRepository(get()) }
PersistentCookieJar( single { HistoryRepository(get()) }
SetCookieCache(), single { TrackingRepository(get()) }
SharedPrefsCookiePersistor(applicationContext) single { MangaDataRepository(get()) }
) single { MangaSearchRepository() }
} single { MangaLoaderContext() }
factory { single { AppSettings(get()) }
okHttp(get()) single { PagesCache(get()) }
.cache(CacheUtils.createHttpCache(applicationContext))
.build()
}
single {
mangaDb().build()
}
single {
MangaLoaderContext()
}
single {
AppSettings(applicationContext)
}
single {
PagesCache(applicationContext)
}
} }
) )
} }
} }
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.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import org.koitharu.kotatsu.core.db.dao.*
import org.koitharu.kotatsu.core.db.entity.* import org.koitharu.kotatsu.core.db.entity.*
@Database( @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.Dao
import androidx.room.Insert 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 androidx.room.*
import org.koitharu.kotatsu.core.db.entity.FavouriteEntity 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 androidx.room.*
import org.koitharu.kotatsu.core.db.entity.MangaEntity 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 androidx.room.*
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity 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 androidx.room.*
import org.koitharu.kotatsu.core.db.entity.TagEntity 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 androidx.room.*
import org.koitharu.kotatsu.core.db.entity.TrackLogEntity 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 androidx.room.*
import org.koitharu.kotatsu.core.db.entity.TrackEntity 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.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
object Migration1To2 : Migration(1, 2) { class Migration1To2 : Migration(1, 2) {
/** /**
* Adding foreign keys * Adding foreign keys
*/ */

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.core.db.migrations
import androidx.room.migration.Migration import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
object Migration2To3 : Migration(2, 3) { class Migration2To3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE history ADD COLUMN scroll REAL NOT NULL DEFAULT 0") 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.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
object Migration3To4 : Migration(3, 4) { class Migration3To4 : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) { 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 )") 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.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
object Migration4To5 : Migration(4, 5) { class Migration4To5 : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE favourite_categories ADD COLUMN sort_key INTEGER NOT NULL DEFAULT 0") 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.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
object Migration5To6 : Migration(5, 6) { class Migration5To6 : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) { 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)") 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.OkHttpClient
import okhttp3.Request 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.await
import org.koitharu.kotatsu.utils.ext.parseJson import org.koitharu.kotatsu.utils.ext.parseJson
class GithubRepository : KoinComponent { class GithubRepository(private val okHttp: OkHttpClient) {
private val okHttp by inject<OkHttpClient>()
suspend fun getLatestVersion(): AppVersion { suspend fun getLatestVersion(): AppVersion {
val request = Request.Builder() val request = Request.Builder()

View File

@@ -2,9 +2,12 @@ package org.koitharu.kotatsu.core.local
import java.io.File import java.io.File
import java.io.FilenameFilter import java.io.FilenameFilter
import java.util.*
class CbzFilter : FilenameFilter { class CbzFilter : FilenameFilter {
override fun accept(dir: File, name: String) = override fun accept(dir: File, name: String): Boolean {
name.endsWith(".cbz", ignoreCase = true) || name.endsWith(".zip", ignoreCase = true) 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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.local.cookies package org.koitharu.kotatsu.core.network.cookies
import okhttp3.CookieJar import okhttp3.CookieJar

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.annotation.SuppressLint
import android.content.Context import android.content.Context
@@ -25,7 +25,12 @@ import java.util.*
class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreferences) : class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreferences) :
CookiePersistor { 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> { override fun loadAll(): List<Cookie> {
val cookies: MutableList<Cookie> = ArrayList(sharedPreferences.all.size) 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 package org.koitharu.kotatsu.core.parser
import android.annotation.SuppressLint
import android.os.Build import android.os.Build
import okhttp3.Interceptor import okhttp3.Interceptor
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import java.util.* import java.util.*
@SuppressLint("ConstantLocale") class UserAgentInterceptor : Interceptor {
object UserAgentInterceptor : Interceptor {
private val userAgent = "Kotatsu/%s (Android %s; %s; %s %s; %s)".format( private val userAgent = "Kotatsu/%s (Android %s; %s; %s %s; %s)".format(
BuildConfig.VERSION_NAME, BuildConfig.VERSION_NAME,

View File

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

View File

@@ -34,6 +34,7 @@ object MangaProviderFactory : KoinComponent {
} }
} }
@Deprecated("Use DI")
fun createLocal(): LocalMangaRepository { fun createLocal(): LocalMangaRepository {
var instance = cache[MangaSource.LOCAL]?.get() var instance = cache[MangaSource.LOCAL]?.get()
if (instance == null) { 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 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.Manga
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.SortOrder import org.koitharu.kotatsu.core.model.SortOrder
import java.util.* import java.util.*
class MangaSearchRepository : KoinComponent { class MangaSearchRepository {
fun globalSearch(query: String, batchSize: Int = 4): Flow<List<Manga>> = flow { fun globalSearch(query: String, batchSize: Int = 4): Flow<List<Manga>> = flow {
val sources = MangaProviderFactory.getSources(false) val sources = MangaProviderFactory.getSources(false)

View File

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

View File

@@ -1,8 +1,8 @@
package org.koitharu.kotatsu.domain.favourites package org.koitharu.kotatsu.domain.favourites
interface OnFavouritesChangeListener { fun interface OnFavouritesChangeListener {
fun onFavouritesChanged(mangaId: Long) 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.core.model.MangaHistory
import org.koitharu.kotatsu.domain.tracking.TrackingRepository 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 inject<TrackingRepository>()
private val trackingRepository by lazy(::TrackingRepository)
suspend fun getList(offset: Int, limit: Int = 20): List<Manga> { suspend fun getList(offset: Int, limit: Int = 20): List<Manga> {
val entities = db.historyDao.findAll(offset, limit) val entities = db.historyDao.findAll(offset, limit)

View File

@@ -1,8 +1,6 @@
package org.koitharu.kotatsu.domain.tracking package org.koitharu.kotatsu.domain.tracking
import androidx.room.withTransaction 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.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.TrackEntity import org.koitharu.kotatsu.core.db.entity.TrackEntity
import org.koitharu.kotatsu.core.db.entity.TrackLogEntity 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 org.koitharu.kotatsu.domain.MangaProviderFactory
import java.util.* import java.util.*
class TrackingRepository : KoinComponent { class TrackingRepository(private val db: MangaDatabase) {
private val db: MangaDatabase by inject()
suspend fun getNewChaptersCount(mangaId: Long): Int { suspend fun getNewChaptersCount(mangaId: Long): Int {
val entity = db.tracksDao.find(mangaId) ?: return 0 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.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import moxy.MvpAppCompatDialogFragment 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 private var rootView: View? = null
@@ -24,12 +27,13 @@ abstract class AlertDialogFragment(@LayoutRes private val layoutResId: Int) : Mv
.create() .create()
} }
@CallSuper
override fun onDestroyView() { override fun onDestroyView() {
rootView = null rootView = null
super.onDestroyView() super.onDestroyView()
} }
override fun getView(): View? { final override fun getView(): View? {
return rootView 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.MenuItem
import android.view.View 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.app.Dialog
import android.os.Bundle import android.os.Bundle
@@ -13,7 +13,7 @@ import org.koitharu.kotatsu.utils.UiUtils
abstract class BaseBottomSheet(@LayoutRes private val layoutResId: Int) : abstract class BaseBottomSheet(@LayoutRes private val layoutResId: Int) :
MvpBottomSheetDialogFragment() { MvpBottomSheetDialogFragment() {
override fun onCreateView( final override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? 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.content.Context
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import coil.ImageLoader
import moxy.MvpAppCompatFragment import moxy.MvpAppCompatFragment
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.utils.delegates.ParcelableArgumentDelegate import org.koitharu.kotatsu.utils.delegates.ParcelableArgumentDelegate
import org.koitharu.kotatsu.utils.delegates.StringArgumentDelegate import org.koitharu.kotatsu.utils.delegates.StringArgumentDelegate
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : abstract class BaseFragment(
MvpAppCompatFragment(contentLayoutId) { @LayoutRes contentLayoutId: Int
) : MvpAppCompatFragment(contentLayoutId) {
protected val coil by inject<ImageLoader>()
fun stringArg(name: String) = StringArgumentDelegate(name) 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.graphics.Color
import android.os.Build import android.os.Build
@@ -12,11 +12,11 @@ abstract class BaseFullscreenActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
with(window) { with(window) {
// addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
statusBarColor = Color.TRANSPARENT statusBarColor = Color.TRANSPARENT
navigationBarColor = Color.TRANSPARENT navigationBarColor = Color.TRANSPARENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 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() showSystemUI()

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.ui.common package org.koitharu.kotatsu.ui.base
import moxy.MvpView import moxy.MvpView
import moxy.viewstate.strategy.alias.AddToEndSingle 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.annotation.StringRes
import androidx.preference.Preference 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 kotlinx.coroutines.*
import moxy.MvpPresenter 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.app.Service
import android.content.Intent import android.content.Intent
@@ -7,18 +7,16 @@ import androidx.annotation.CallSuper
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob 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() @Suppress("MemberVisibilityCanBePrivate")
val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
final override val coroutineContext: CoroutineContext
get() = Dispatchers.Main.immediate + job
@CallSuper @CallSuper
override fun onDestroy() { override fun onDestroy() {
job.cancel() serviceScope.cancel()
super.onDestroy() 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.content.Context
import android.view.View import android.view.View
@@ -8,8 +8,10 @@ import org.koitharu.kotatsu.utils.ext.getThemeColor
class ChipsFactory(val context: Context) { class ChipsFactory(val context: Context) {
fun create(convertView: Chip? = null, text: CharSequence, @DrawableRes iconRes: Int = 0, fun create(
tag: Any? = null, onClickListener: View.OnClickListener? = null): Chip { convertView: Chip? = null, text: CharSequence, @DrawableRes iconRes: Int = 0,
tag: Any? = null, onClickListener: View.OnClickListener? = null
): Chip {
val chip = convertView ?: Chip(context).apply { val chip = convertView ?: Chip(context).apply {
setTextColor(context.getThemeColor(android.R.attr.textColorPrimary)) setTextColor(context.getThemeColor(android.R.attr.textColorPrimary))
isCloseIconVisible = false 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 android.util.ArrayMap
import moxy.MvpPresenter 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.annotation.SuppressLint
import android.content.Context 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.Context
import android.content.DialogInterface 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.annotation.SuppressLint
import android.content.Context import android.content.Context
@@ -11,15 +11,17 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.android.synthetic.main.dialog_input.view.* import kotlinx.android.synthetic.main.dialog_input.view.*
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
class TextInputDialog private constructor(private val delegate: AlertDialog) : class TextInputDialog private constructor(
DialogInterface by delegate { private val delegate: AlertDialog
) : DialogInterface by delegate {
fun show() = delegate.show() fun show() = delegate.show()
class Builder(context: Context) { class Builder(context: Context) {
@SuppressLint("InflateParams") @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) private val delegate = MaterialAlertDialogBuilder(context)
.setView(view) .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.DiffUtil
import androidx.recyclerview.widget.RecyclerView 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 android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import okhttp3.internal.toImmutableList
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koitharu.kotatsu.utils.ext.replaceWith 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 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() 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.View
import android.view.ViewGroup 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.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView 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 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 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 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.View
import android.view.ViewGroup 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.content.Context
import android.graphics.Canvas 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.Canvas
import android.graphics.Rect 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.graphics.Rect
import android.view.View 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.content.Context
import android.util.AttributeSet import android.util.AttributeSet
@@ -61,7 +61,6 @@ class CheckableImageView @JvmOverloads constructor(
private companion object { private companion object {
@JvmStatic
private val CHECKED_STATE_SET = intArrayOf(android.R.attr.state_checked) 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.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.res.use import androidx.core.content.withStyledAttributes
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -15,10 +15,9 @@ class CoverImageView @JvmOverloads constructor(
private var orientation: Int = HORIZONTAL private var orientation: Int = HORIZONTAL
init { init {
context.theme.obtainStyledAttributes(attrs, R.styleable.CoverImageView, defStyleAttr, 0) context.withStyledAttributes(attrs, R.styleable.CoverImageView, defStyleAttr) {
.use { orientation = getInt(R.styleable.CoverImageView_android_orientation, HORIZONTAL)
orientation = it.getInt(R.styleable.CoverImageView_android_orientation, HORIZONTAL) }
}
} }
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 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.content.Context
import android.util.AttributeSet import android.util.AttributeSet

View File

@@ -11,7 +11,7 @@ import android.view.MenuItem
import androidx.core.view.isVisible import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.activity_browser.* import kotlinx.android.synthetic.main.activity_browser.*
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.ui.common.BaseActivity import org.koitharu.kotatsu.ui.base.BaseActivity
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
class BrowserActivity : BaseActivity(), BrowserCallback { 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.R
import org.koitharu.kotatsu.core.model.MangaChapter import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.domain.history.ChapterExtra 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 import org.koitharu.kotatsu.utils.ext.getThemeColor
class ChapterHolder(parent: ViewGroup) : class ChapterHolder(parent: ViewGroup) :

View File

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

View File

@@ -15,8 +15,8 @@ import kotlinx.android.synthetic.main.fragment_chapters.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.ui.common.BaseFragment import org.koitharu.kotatsu.ui.base.BaseFragment
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.download.DownloadService import org.koitharu.kotatsu.ui.download.DownloadService
import org.koitharu.kotatsu.ui.reader.ReaderActivity import org.koitharu.kotatsu.ui.reader.ReaderActivity
import org.koitharu.kotatsu.utils.ext.resolveDp 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.Manga
import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.core.model.MangaSource 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.browser.BrowserActivity
import org.koitharu.kotatsu.ui.common.BaseActivity
import org.koitharu.kotatsu.ui.download.DownloadService import org.koitharu.kotatsu.ui.download.DownloadService
import org.koitharu.kotatsu.utils.MangaShortcut import org.koitharu.kotatsu.utils.MangaShortcut
import org.koitharu.kotatsu.utils.ShareHelper 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.text.parseAsHtml
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import coil.load
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import kotlinx.android.synthetic.main.fragment_details.* import kotlinx.android.synthetic.main.fragment_details.*
import kotlinx.coroutines.Dispatchers 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.FavouriteCategory
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory 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.list.favourites.categories.select.FavouriteCategoriesDialog
import org.koitharu.kotatsu.ui.reader.ReaderActivity import org.koitharu.kotatsu.ui.reader.ReaderActivity
import org.koitharu.kotatsu.ui.search.MangaSearchSheet import org.koitharu.kotatsu.ui.search.MangaSearchSheet
import org.koitharu.kotatsu.utils.FileSizeUtils import org.koitharu.kotatsu.utils.FileSizeUtils
import org.koitharu.kotatsu.utils.ext.addChips import org.koitharu.kotatsu.utils.ext.*
import org.koitharu.kotatsu.utils.ext.showPopupMenu
import org.koitharu.kotatsu.utils.ext.textAndVisible
import org.koitharu.kotatsu.utils.ext.toFileOrNull
import kotlin.math.roundToInt import kotlin.math.roundToInt
class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetailsView, 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) { override fun onMangaUpdated(manga: Manga) {
this.manga = manga this.manga = manga
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) { imageView_cover.newImageRequest(manga.largeCoverUrl ?: manga.coverUrl)
fallback(R.drawable.ic_placeholder) .fallback(R.drawable.ic_placeholder)
crossfade(true) .crossfade(true)
lifecycle(this@MangaDetailsFragment) .lifecycle(this)
} .enqueueWith(coil)
textView_title.text = manga.title textView_title.text = manga.title
textView_subtitle.textAndVisible = manga.altTitle textView_subtitle.textAndVisible = manga.altTitle
textView_description.text = manga.description?.parseAsHtml()?.takeUnless(Spanned::isBlank) textView_description.text = manga.description?.parseAsHtml()?.takeUnless(Spanned::isBlank)
@@ -138,9 +134,11 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
} }
v is Chip -> { v is Chip -> {
when (val tag = v.tag) { when (val tag = v.tag) {
is String -> MangaSearchSheet.show(activity?.supportFragmentManager is String -> MangaSearchSheet.show(
?: childFragmentManager, activity?.supportFragmentManager
manga?.source ?: return, tag) ?: childFragmentManager,
manga?.source ?: return, tag
)
} }
} }
} }

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode 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 { 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" private const val TAG = "ListModeSelectDialog"
fun show(fm: FragmentManager) = ListModeSelectDialog() fun show(fm: FragmentManager) = ListModeSelectDialog()
.show(fm, .show(
fm,
TAG 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.AppSection
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.domain.MangaProviderFactory 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.favourites.FavouritesContainerFragment
import org.koitharu.kotatsu.ui.list.feed.FeedFragment import org.koitharu.kotatsu.ui.list.feed.FeedFragment
import org.koitharu.kotatsu.ui.list.history.HistoryListFragment import org.koitharu.kotatsu.ui.list.history.HistoryListFragment

View File

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

View File

@@ -1,7 +1,7 @@
package org.koitharu.kotatsu.ui.list package org.koitharu.kotatsu.ui.list
import moxy.viewstate.strategy.alias.OneExecution 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 import org.koitharu.kotatsu.ui.reader.ReaderState
interface MainView : BaseMvpView { interface MainView : BaseMvpView {

View File

@@ -1,27 +1,35 @@
package org.koitharu.kotatsu.ui.list package org.koitharu.kotatsu.ui.list
import android.view.ViewGroup import android.view.ViewGroup
import coil.clear import coil.ImageLoader
import coil.load import coil.request.Disposable
import kotlinx.android.synthetic.main.item_manga_grid.* import kotlinx.android.synthetic.main.item_manga_grid.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory 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?) { override fun onBind(data: Manga, extra: MangaHistory?) {
imageView_cover.clear()
textView_title.text = data.title textView_title.text = data.title
imageView_cover.load(data.coverUrl) { imageRequest?.dispose()
placeholder(R.drawable.ic_placeholder) imageRequest = imageView_cover.newImageRequest(data.coverUrl)
fallback(R.drawable.ic_placeholder) .placeholder(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder) .fallback(R.drawable.ic_placeholder)
} .error(R.drawable.ic_placeholder)
.enqueueWith(coil)
} }
override fun onRecycled() { 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.Manga
import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
class MangaListAdapter(onItemClickListener: OnRecyclerItemClickListener<Manga>) : class MangaListAdapter(onItemClickListener: OnRecyclerItemClickListener<Manga>) :
BaseRecyclerAdapter<Manga, MangaHistory?>(onItemClickListener) { BaseRecyclerAdapter<Manga, MangaHistory?>(onItemClickListener) {
var listMode: ListMode = ListMode.LIST var listMode: ListMode = ListMode.LIST
override fun onCreateViewHolder(parent: ViewGroup) = when(listMode) { override fun onCreateViewHolder(parent: ViewGroup) = when (listMode) {
ListMode.LIST -> MangaListHolder(parent) ListMode.LIST -> MangaListHolder(parent)
ListMode.DETAILED_LIST -> MangaListDetailsHolder( ListMode.DETAILED_LIST -> MangaListDetailsHolder(
parent parent

View File

@@ -3,29 +3,37 @@ package org.koitharu.kotatsu.ui.list
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import coil.clear import coil.ImageLoader
import coil.load import coil.request.Disposable
import kotlinx.android.synthetic.main.item_manga_list_details.* import kotlinx.android.synthetic.main.item_manga_list_details.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory 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 org.koitharu.kotatsu.utils.ext.textAndVisible
import kotlin.math.roundToInt 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") @SuppressLint("SetTextI18n")
override fun onBind(data: Manga, extra: MangaHistory?) { override fun onBind(data: Manga, extra: MangaHistory?) {
imageView_cover.clear() imageRequest?.dispose()
textView_title.text = data.title textView_title.text = data.title
textView_subtitle.textAndVisible = data.altTitle textView_subtitle.textAndVisible = data.altTitle
imageView_cover.load(data.coverUrl) { imageView_cover.newImageRequest(data.coverUrl)
placeholder(R.drawable.ic_placeholder) .placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder) .fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder) .error(R.drawable.ic_placeholder)
} .enqueueWith(coil)
if(data.rating == Manga.NO_RATING) { if (data.rating == Manga.NO_RATING) {
textView_rating.isVisible = false textView_rating.isVisible = false
} else { } else {
textView_rating.text = "${(data.rating * 10).roundToInt()}/10" textView_rating.text = "${(data.rating * 10).roundToInt()}/10"
@@ -37,6 +45,7 @@ class MangaListDetailsHolder(parent: ViewGroup) : BaseViewHolder<Manga, MangaHis
} }
override fun onRecycled() { 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.model.SortOrder
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.BaseFragment import org.koitharu.kotatsu.ui.base.BaseFragment
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener import org.koitharu.kotatsu.ui.base.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.common.list.ProgressBarAdapter import org.koitharu.kotatsu.ui.base.list.ProgressBarAdapter
import org.koitharu.kotatsu.ui.common.list.decor.ItemTypeDividerDecoration import org.koitharu.kotatsu.ui.base.list.decor.ItemTypeDividerDecoration
import org.koitharu.kotatsu.ui.common.list.decor.SectionItemDecoration import org.koitharu.kotatsu.ui.base.list.decor.SectionItemDecoration
import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.ui.base.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.ui.list.filter.FilterAdapter import org.koitharu.kotatsu.ui.list.filter.FilterAdapter
import org.koitharu.kotatsu.ui.list.filter.OnFilterChangedListener 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 adapter: MangaListAdapter? = null
private var progressAdapter: ProgressBarAdapter? = null private var progressAdapter: ProgressBarAdapter? = null
private var paginationListener : PaginationScrollListener? = null private var paginationListener: PaginationScrollListener? = null
protected var isSwipeRefreshEnabled = true protected var isSwipeRefreshEnabled = true
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View File

@@ -1,30 +1,38 @@
package org.koitharu.kotatsu.ui.list package org.koitharu.kotatsu.ui.list
import android.view.ViewGroup import android.view.ViewGroup
import coil.clear import coil.ImageLoader
import coil.load import coil.request.Disposable
import kotlinx.android.synthetic.main.item_manga_list.* import kotlinx.android.synthetic.main.item_manga_list.*
import org.koin.core.component.inject
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory 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 org.koitharu.kotatsu.utils.ext.textAndVisible
class MangaListHolder(parent: ViewGroup) : class MangaListHolder(
BaseViewHolder<Manga, MangaHistory?>(parent, R.layout.item_manga_list) { 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?) { override fun onBind(data: Manga, extra: MangaHistory?) {
imageView_cover.clear() imageRequest?.dispose()
textView_title.text = data.title textView_title.text = data.title
textView_subtitle.textAndVisible = data.tags.joinToString(", ") { it.title } textView_subtitle.textAndVisible = data.tags.joinToString(", ") { it.title }
imageView_cover.load(data.coverUrl) { imageRequest = imageView_cover.newImageRequest(data.coverUrl)
placeholder(R.drawable.ic_placeholder) .placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder) .fallback(R.drawable.ic_placeholder)
error(R.drawable.ic_placeholder) .error(R.drawable.ic_placeholder)
} .enqueueWith(coil)
} }
override fun onRecycled() { 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.model.SortOrder
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.BaseBottomSheet import org.koitharu.kotatsu.ui.base.BaseBottomSheet
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener import org.koitharu.kotatsu.ui.base.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.common.list.ProgressBarAdapter import org.koitharu.kotatsu.ui.base.list.ProgressBarAdapter
import org.koitharu.kotatsu.ui.common.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.ui.base.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.utils.UiUtils import org.koitharu.kotatsu.utils.UiUtils
import org.koitharu.kotatsu.utils.ext.* 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.MangaFilter
import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder 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 { 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.core.model.FavouriteCategory
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.domain.favourites.OnFavouritesChangeListener 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.CategoriesActivity
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesPresenter import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesPresenter
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites), FavouriteCategoriesView, class FavouritesContainerFragment : BaseFragment(R.layout.fragment_favourites),
FavouriteCategoriesView,
OnFavouritesChangeListener { OnFavouritesChangeListener {
private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter) private val presenter by moxyPresenter(factory = ::FavouriteCategoriesPresenter)

View File

@@ -1,36 +1,28 @@
package org.koitharu.kotatsu.ui.list.favourites package org.koitharu.kotatsu.ui.list.favourites
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import moxy.InjectViewState import moxy.InjectViewState
import moxy.presenterScope import moxy.presenterScope
import org.koin.core.component.get
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository 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 import org.koitharu.kotatsu.ui.list.MangaListView
@InjectViewState @InjectViewState
class FavouritesListPresenter : BasePresenter<MangaListView<Unit>>() { class FavouritesListPresenter : BasePresenter<MangaListView<Unit>>() {
private lateinit var repository: FavouritesRepository private val repository = get<FavouritesRepository>()
override fun onFirstViewAttach() {
repository = FavouritesRepository()
super.onFirstViewAttach()
}
fun loadList(categoryId: Long, offset: Int) { fun loadList(categoryId: Long, offset: Int) {
presenterScope.launch { presenterScope.launch {
viewState.onLoadingStateChanged(true) viewState.onLoadingStateChanged(true)
try { try {
val list = withContext(Dispatchers.IO) { val list = if (categoryId == 0L) {
if (categoryId == 0L) { repository.getAllManga(offset = offset)
repository.getAllManga(offset = offset) } else {
} else { repository.getManga(categoryId = categoryId, offset = offset)
repository.getManga(categoryId = categoryId, offset = offset)
}
} }
if (offset == 0) { if (offset == 0) {
viewState.onListChanged(list) 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.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import org.koitharu.kotatsu.core.model.FavouriteCategory 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 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>() private val dataSet = ArrayList<FavouriteCategory>()

View File

@@ -17,9 +17,9 @@ import kotlinx.android.synthetic.main.activity_categories.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.BaseActivity import org.koitharu.kotatsu.ui.base.BaseActivity
import org.koitharu.kotatsu.ui.common.dialog.TextInputDialog import org.koitharu.kotatsu.ui.base.dialog.TextInputDialog
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener import org.koitharu.kotatsu.ui.base.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.showPopupMenu 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 { 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 return true
} }

View File

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

View File

@@ -4,7 +4,7 @@ import android.view.ViewGroup
import kotlinx.android.synthetic.main.item_category.* import kotlinx.android.synthetic.main.item_category.*
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory 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) : class CategoryHolder(parent: ViewGroup) :
BaseViewHolder<FavouriteCategory, Unit>(parent, R.layout.item_category) { 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.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import moxy.InjectViewState import moxy.InjectViewState
import org.koin.core.component.get
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.ui.common.BasePresenter import org.koitharu.kotatsu.ui.base.BasePresenter
@InjectViewState @InjectViewState
class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() { class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() {
private lateinit var repository: FavouritesRepository private val repository = get<FavouritesRepository>()
private val reorderMutex by lazy { private val reorderMutex by lazy(LazyThreadSafetyMode.NONE) { Mutex() }
Mutex()
}
override fun onFirstViewAttach() { override fun onFirstViewAttach() {
repository = FavouritesRepository()
super.onFirstViewAttach() super.onFirstViewAttach()
loadAllCategories() loadAllCategories()
} }

View File

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

View File

@@ -5,8 +5,8 @@ import android.view.ViewGroup
import android.widget.Checkable import android.widget.Checkable
import androidx.core.util.set import androidx.core.util.set
import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter import org.koitharu.kotatsu.ui.base.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder import org.koitharu.kotatsu.ui.base.list.BaseViewHolder
class CategoriesSelectAdapter(private val listener: OnCategoryCheckListener) : class CategoriesSelectAdapter(private val listener: OnCategoryCheckListener) :
BaseRecyclerAdapter<FavouriteCategory, Boolean>() { BaseRecyclerAdapter<FavouriteCategory, Boolean>() {

View File

@@ -4,7 +4,7 @@ import android.view.ViewGroup
import kotlinx.android.synthetic.main.item_category_checkable.* import kotlinx.android.synthetic.main.item_category_checkable.*
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory 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) : class CategoryCheckableHolder(parent: ViewGroup) :
BaseViewHolder<FavouriteCategory, Boolean>(parent, R.layout.item_category_checkable) { 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.R
import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.ui.common.BaseBottomSheet import org.koitharu.kotatsu.ui.base.BaseBottomSheet
import org.koitharu.kotatsu.ui.common.dialog.TextInputDialog 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.FavouriteCategoriesPresenter
import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView import org.koitharu.kotatsu.ui.list.favourites.categories.FavouriteCategoriesView
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
@@ -31,7 +31,8 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
adapter = adapter =
CategoriesSelectAdapter( CategoriesSelectAdapter(
this) this
)
recyclerView_categories.adapter = adapter recyclerView_categories.adapter = adapter
textView_add.setOnClickListener { textView_add.setOnClickListener {
createCategory() createCategory()
@@ -86,8 +87,10 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ
fun show(fm: FragmentManager, manga: Manga) = FavouriteCategoriesDialog() fun show(fm: FragmentManager, manga: Manga) = FavouriteCategoriesDialog()
.withArgs(1) { .withArgs(1) {
putParcelable(ARG_MANGA, manga) putParcelable(ARG_MANGA, manga)
}.show(fm, }.show(
TAG) fm,
TAG
)
} }
} }

View File

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

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