Update database schema: foreign keys and indices
This commit is contained in:
120
.idea/codeStyles
generated
120
.idea/codeStyles
generated
@@ -1,120 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
186
.idea/codeStyles/Project.xml
generated
Executable file
186
.idea/codeStyles/Project.xml
generated
Executable file
@@ -0,0 +1,186 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="OTHER_INDENT_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<AndroidXmlCodeStyleSettings>
|
||||||
|
<option name="LAYOUT_SETTINGS">
|
||||||
|
<value>
|
||||||
|
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="MANIFEST_SETTINGS">
|
||||||
|
<value>
|
||||||
|
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="OTHER_SETTINGS">
|
||||||
|
<value>
|
||||||
|
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</AndroidXmlCodeStyleSettings>
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</JetCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="CMake">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Groovy">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="HTML">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="JAVA">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="JSON">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="ObjectiveC">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Shell Script">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="XML">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
<arrangement>
|
||||||
|
<rules>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:android</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:id</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:name</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>name</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>style</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
</rules>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Executable file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest
|
<manifest
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.koitharu.kotatsu">
|
package="org.koitharu.kotatsu">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
@@ -18,7 +19,8 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true"
|
||||||
|
tools:ignore="UnusedAttribute">
|
||||||
<activity android:name=".ui.main.MainActivity">
|
<activity android:name=".ui.main.MainActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@@ -54,7 +56,9 @@
|
|||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".ui.search.MangaSuggestionsProvider"
|
android:name=".ui.search.MangaSuggestionsProvider"
|
||||||
android:authorities="${applicationId}.MangaSuggestionsProvider" />
|
android:authorities="${applicationId}.MangaSuggestionsProvider"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.files"
|
android:authorities="${applicationId}.files"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.koin.android.ext.koin.androidLogger
|
|||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
|
import org.koitharu.kotatsu.core.db.migrations.Migration1To2
|
||||||
import org.koitharu.kotatsu.core.local.CbzFetcher
|
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.local.cookies.PersistentCookieJar
|
||||||
@@ -109,5 +110,5 @@ class KotatsuApp : Application() {
|
|||||||
applicationContext,
|
applicationContext,
|
||||||
MangaDatabase::class.java,
|
MangaDatabase::class.java,
|
||||||
"kotatsu-db"
|
"kotatsu-db"
|
||||||
)
|
).addMigrations(Migration1To2)
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ import org.koitharu.kotatsu.core.db.entity.*
|
|||||||
entities = [
|
entities = [
|
||||||
MangaEntity::class, TagEntity::class, HistoryEntity::class, MangaTagsEntity::class,
|
MangaEntity::class, TagEntity::class, HistoryEntity::class, MangaTagsEntity::class,
|
||||||
FavouriteCategoryEntity::class, FavouriteEntity::class, MangaPrefsEntity::class
|
FavouriteCategoryEntity::class, FavouriteEntity::class, MangaPrefsEntity::class
|
||||||
], version = 1
|
], version = 2
|
||||||
)
|
)
|
||||||
abstract class MangaDatabase : RoomDatabase() {
|
abstract class MangaDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,26 @@ package org.koitharu.kotatsu.core.db.entity
|
|||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
|
||||||
@Entity(tableName = "favourites", primaryKeys = ["manga_id", "category_id"])
|
@Entity(
|
||||||
|
tableName = "favourites", primaryKeys = ["manga_id", "category_id"], foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = MangaEntity::class,
|
||||||
|
parentColumns = ["manga_id"],
|
||||||
|
childColumns = ["manga_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = FavouriteCategoryEntity::class,
|
||||||
|
parentColumns = ["category_id"],
|
||||||
|
childColumns = ["category_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
data class FavouriteEntity(
|
data class FavouriteEntity(
|
||||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
@ColumnInfo(name = "manga_id", index = true) val mangaId: Long,
|
||||||
@ColumnInfo(name = "category_id") val categoryId: Long,
|
@ColumnInfo(name = "category_id", index = true) val categoryId: Long,
|
||||||
@ColumnInfo(name = "created_at") val createdAt: Long
|
@ColumnInfo(name = "created_at") val createdAt: Long
|
||||||
)
|
)
|
||||||
@@ -2,24 +2,34 @@ package org.koitharu.kotatsu.core.db.entity
|
|||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Entity(tableName = "history")
|
@Entity(
|
||||||
|
tableName = "history", foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = MangaEntity::class,
|
||||||
|
parentColumns = ["manga_id"],
|
||||||
|
childColumns = ["manga_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
data class HistoryEntity(
|
data class HistoryEntity(
|
||||||
@PrimaryKey(autoGenerate = false)
|
@PrimaryKey(autoGenerate = false)
|
||||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
||||||
@ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis(),
|
@ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis(),
|
||||||
@ColumnInfo(name = "updated_at") val updatedAt: Long,
|
@ColumnInfo(name = "updated_at") val updatedAt: Long,
|
||||||
@ColumnInfo(name = "chapter_id") val chapterId: Long,
|
@ColumnInfo(name = "chapter_id") val chapterId: Long,
|
||||||
@ColumnInfo(name = "page") val page: Int
|
@ColumnInfo(name = "page") val page: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun toMangaHistory() = MangaHistory(
|
fun toMangaHistory() = MangaHistory(
|
||||||
createdAt = Date(createdAt),
|
createdAt = Date(createdAt),
|
||||||
updatedAt = Date(updatedAt),
|
updatedAt = Date(updatedAt),
|
||||||
chapterId = chapterId,
|
chapterId = chapterId,
|
||||||
page = page
|
page = page
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,18 @@ package org.koitharu.kotatsu.core.db.entity
|
|||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
@Entity(tableName = "preferences")
|
@Entity(
|
||||||
|
tableName = "preferences", foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = MangaEntity::class,
|
||||||
|
parentColumns = ["manga_id"],
|
||||||
|
childColumns = ["manga_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)]
|
||||||
|
)
|
||||||
data class MangaPrefsEntity(
|
data class MangaPrefsEntity(
|
||||||
@PrimaryKey(autoGenerate = false)
|
@PrimaryKey(autoGenerate = false)
|
||||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
||||||
|
|||||||
@@ -2,9 +2,25 @@ package org.koitharu.kotatsu.core.db.entity
|
|||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
|
||||||
@Entity(tableName = "manga_tags", primaryKeys = ["manga_id", "tag_id"])
|
@Entity(
|
||||||
|
tableName = "manga_tags", primaryKeys = ["manga_id", "tag_id"], foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = MangaEntity::class,
|
||||||
|
parentColumns = ["manga_id"],
|
||||||
|
childColumns = ["manga_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = TagEntity::class,
|
||||||
|
parentColumns = ["tag_id"],
|
||||||
|
childColumns = ["tag_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
data class MangaTagsEntity(
|
data class MangaTagsEntity(
|
||||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
@ColumnInfo(name = "manga_id", index = true) val mangaId: Long,
|
||||||
@ColumnInfo(name = "tag_id") val tagId: Long
|
@ColumnInfo(name = "tag_id", index = true) val tagId: Long
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.koitharu.kotatsu.core.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
object Migration1To2 : Migration(1, 2) {
|
||||||
|
/**
|
||||||
|
* Adding foreign keys
|
||||||
|
*/
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
/* manga_tags */
|
||||||
|
database.execSQL(
|
||||||
|
"CREATE TABLE IF NOT EXISTS manga_tags_tmp (manga_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, " +
|
||||||
|
"PRIMARY KEY(manga_id, tag_id), " +
|
||||||
|
"FOREIGN KEY(manga_id) REFERENCES manga(manga_id) ON UPDATE NO ACTION ON DELETE CASCADE, " +
|
||||||
|
"FOREIGN KEY(tag_id) REFERENCES tags(tag_id) ON UPDATE NO ACTION ON DELETE CASCADE )"
|
||||||
|
)
|
||||||
|
database.execSQL("CREATE INDEX IF NOT EXISTS index_manga_tags_manga_id ON manga_tags_tmp (manga_id)")
|
||||||
|
database.execSQL("CREATE INDEX IF NOT EXISTS index_manga_tags_tag_id ON manga_tags_tmp (tag_id)")
|
||||||
|
database.execSQL("INSERT INTO manga_tags_tmp (manga_id, tag_id) SELECT manga_id, tag_id FROM manga_tags")
|
||||||
|
database.execSQL("DROP TABLE manga_tags")
|
||||||
|
database.execSQL("ALTER TABLE manga_tags_tmp RENAME TO manga_tags")
|
||||||
|
/* favourites */
|
||||||
|
database.execSQL(
|
||||||
|
"CREATE TABLE IF NOT EXISTS favourites_tmp (manga_id INTEGER NOT NULL, category_id INTEGER NOT NULL, created_at INTEGER NOT NULL, " +
|
||||||
|
"PRIMARY KEY(manga_id, category_id), " +
|
||||||
|
"FOREIGN KEY(manga_id) REFERENCES manga(manga_id) ON UPDATE NO ACTION ON DELETE CASCADE , " +
|
||||||
|
"FOREIGN KEY(category_id) REFERENCES favourite_categories(category_id) ON UPDATE NO ACTION ON DELETE CASCADE )"
|
||||||
|
)
|
||||||
|
database.execSQL("CREATE INDEX IF NOT EXISTS index_favourites_manga_id ON favourites_tmp (manga_id)")
|
||||||
|
database.execSQL("CREATE INDEX IF NOT EXISTS index_favourites_category_id ON favourites_tmp (category_id)")
|
||||||
|
database.execSQL("INSERT INTO favourites_tmp (manga_id, category_id, created_at) SELECT manga_id, category_id, created_at FROM favourites")
|
||||||
|
database.execSQL("DROP TABLE favourites")
|
||||||
|
database.execSQL("ALTER TABLE favourites_tmp RENAME TO favourites")
|
||||||
|
/* history */
|
||||||
|
database.execSQL(
|
||||||
|
"CREATE TABLE IF NOT EXISTS history_tmp (manga_id INTEGER NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, chapter_id INTEGER NOT NULL, page INTEGER NOT NULL, " +
|
||||||
|
"PRIMARY KEY(manga_id), " +
|
||||||
|
"FOREIGN KEY(manga_id) REFERENCES manga(manga_id) ON UPDATE NO ACTION ON DELETE CASCADE )"
|
||||||
|
)
|
||||||
|
database.execSQL("INSERT INTO history_tmp (manga_id, created_at, updated_at, chapter_id, page) SELECT manga_id, created_at, updated_at, chapter_id, page FROM history")
|
||||||
|
database.execSQL("DROP TABLE history")
|
||||||
|
database.execSQL("ALTER TABLE history_tmp RENAME TO history")
|
||||||
|
/* preferences */
|
||||||
|
database.execSQL(
|
||||||
|
"CREATE TABLE IF NOT EXISTS preferences_tmp (manga_id INTEGER NOT NULL, mode INTEGER NOT NULL," +
|
||||||
|
" PRIMARY KEY(manga_id), " +
|
||||||
|
"FOREIGN KEY(manga_id) REFERENCES manga(manga_id) ON UPDATE NO ACTION ON DELETE CASCADE )"
|
||||||
|
)
|
||||||
|
database.execSQL("INSERT INTO preferences_tmp (manga_id, mode) SELECT manga_id, mode FROM preferences")
|
||||||
|
database.execSQL("DROP TABLE preferences")
|
||||||
|
database.execSQL("ALTER TABLE preferences_tmp RENAME TO preferences")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import java.util.zip.ZipFile
|
|||||||
|
|
||||||
class CbzFetcher : Fetcher<Uri> {
|
class CbzFetcher : Fetcher<Uri> {
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
override suspend fun fetch(
|
override suspend fun fetch(
|
||||||
pool: BitmapPool,
|
pool: BitmapPool,
|
||||||
data: Uri,
|
data: Uri,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class SetCookieCache : CookieCache {
|
|||||||
|
|
||||||
override fun iterator(): MutableIterator<Cookie> = SetCookieCacheIterator()
|
override fun iterator(): MutableIterator<Cookie> = SetCookieCacheIterator()
|
||||||
|
|
||||||
private inner class SetCookieCacheIterator internal constructor() : MutableIterator<Cookie> {
|
private inner class SetCookieCacheIterator() : MutableIterator<Cookie> {
|
||||||
|
|
||||||
private val iterator = cookies.iterator()
|
private val iterator = cookies.iterator()
|
||||||
|
|
||||||
|
|||||||
@@ -41,27 +41,24 @@ class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreference
|
|||||||
return cookies
|
return cookies
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
override fun saveAll(cookies: Collection<Cookie>) {
|
override fun saveAll(cookies: Collection<Cookie>) {
|
||||||
val editor = sharedPreferences.edit()
|
val editor = sharedPreferences.edit()
|
||||||
for (cookie in cookies) {
|
for (cookie in cookies) {
|
||||||
editor.putString(createCookieKey(cookie), SerializableCookie().encode(cookie))
|
editor.putString(createCookieKey(cookie), SerializableCookie().encode(cookie))
|
||||||
}
|
}
|
||||||
editor.commit()
|
editor.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
override fun removeAll(cookies: Collection<Cookie>) {
|
override fun removeAll(cookies: Collection<Cookie>) {
|
||||||
val editor = sharedPreferences.edit()
|
val editor = sharedPreferences.edit()
|
||||||
for (cookie in cookies) {
|
for (cookie in cookies) {
|
||||||
editor.remove(createCookieKey(cookie))
|
editor.remove(createCookieKey(cookie))
|
||||||
}
|
}
|
||||||
editor.commit()
|
editor.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
sharedPreferences.edit().clear().commit()
|
sharedPreferences.edit().clear().apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class LocalMangaRepository : MangaRepository, KoinComponent {
|
|||||||
getFromFile(Uri.parse(manga.url).toFile())
|
getFromFile(Uri.parse(manga.url).toFile())
|
||||||
} else manga
|
} else manga
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||||
val file = Uri.parse(chapter.url).toFile()
|
val file = Uri.parse(chapter.url).toFile()
|
||||||
val zip = ZipFile(file)
|
val zip = ZipFile(file)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import org.koitharu.kotatsu.ui.common.dialog.TextInputDialog
|
|||||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
class FavouriteCategoriesDialog() : BaseBottomSheet(R.layout.dialog_favorite_categories),
|
class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categories),
|
||||||
FavouriteCategoriesView,
|
FavouriteCategoriesView,
|
||||||
OnCategoryCheckListener {
|
OnCategoryCheckListener {
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class PageLoader : KoinComponent, CoroutineScope, DisposableHandle {
|
|||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
get() = Dispatchers.Main + job
|
get() = Dispatchers.Main + job
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
suspend fun loadFile(url: String, force: Boolean): File {
|
suspend fun loadFile(url: String, force: Boolean): File {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
cache[url]?.let {
|
cache[url]?.let {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class GroupedList<K, T> {
|
|||||||
lruGroup = entry.second
|
lruGroup = entry.second
|
||||||
lruGroupKey = entry.first
|
lruGroupKey = entry.first
|
||||||
lruGroupFirstIndex = lastIndex - entry.second.size
|
lruGroupFirstIndex = lastIndex - entry.second.size
|
||||||
return entry.second.get(index - lruGroupFirstIndex)
|
return entry.second[index - lruGroupFirstIndex]
|
||||||
}
|
}
|
||||||
lastIndex -= entry.second.size
|
lastIndex -= entry.second.size
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import org.koitharu.kotatsu.ui.reader.ReaderState
|
|||||||
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
|
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
|
||||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
class PagerReaderFragment() : AbstractReader(R.layout.fragment_reader_standard) {
|
class PagerReaderFragment : AbstractReader(R.layout.fragment_reader_standard) {
|
||||||
|
|
||||||
private var paginationListener: PagerPaginationListener? = null
|
private var paginationListener: PagerPaginationListener? = null
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.koitharu.kotatsu.utils.ext.withArgs
|
|||||||
class WebtoonReaderFragment : AbstractReader(R.layout.fragment_reader_webtoon) {
|
class WebtoonReaderFragment : AbstractReader(R.layout.fragment_reader_webtoon) {
|
||||||
|
|
||||||
private val scrollInterpolator = AccelerateDecelerateInterpolator()
|
private val scrollInterpolator = AccelerateDecelerateInterpolator()
|
||||||
protected var paginationListener: ListPaginationListener? = null
|
private var paginationListener: ListPaginationListener? = null
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.utils.ext
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@SuppressLint("SimpleDateFormat")
|
@SuppressLint("SimpleDateFormat")
|
||||||
fun Date.format(pattern: String): String = SimpleDateFormat(pattern).format(this)
|
fun Date.format(pattern: String): String = SimpleDateFormat(pattern).format(this)
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
package org.koitharu.kotatsu.utils.ext
|
package org.koitharu.kotatsu.utils.ext
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
fun NotificationCompat.Builder.clearActions(): NotificationCompat.Builder {
|
fun NotificationCompat.Builder.clearActions(): NotificationCompat.Builder {
|
||||||
mActions.clear()
|
safe {
|
||||||
|
mActions.clear()
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,8 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/imageView_cover"
|
app:layout_constraintStart_toEndOf="@id/imageView_cover"
|
||||||
app:layout_constraintTop_toBottomOf="@id/chips_tags"
|
app:layout_constraintTop_toBottomOf="@id/chips_tags"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
|
|||||||
@@ -132,7 +132,8 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/chips_tags"
|
app:layout_constraintTop_toBottomOf="@id/chips_tags"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<string name="settings">Настройки</string>
|
<string name="settings">Настройки</string>
|
||||||
<string name="remote_sources">Онлайн каталоги</string>
|
<string name="remote_sources">Онлайн каталоги</string>
|
||||||
<string name="loading_">Загрузка…</string>
|
<string name="loading_">Загрузка…</string>
|
||||||
<string name="chapter_d_of_d">Глава %d из %d</string>
|
<string name="chapter_d_of_d">Глава %1$d из %2$d</string>
|
||||||
<string name="close">Закрыть</string>
|
<string name="close">Закрыть</string>
|
||||||
<string name="try_again">Повторить</string>
|
<string name="try_again">Повторить</string>
|
||||||
<string name="clear_history">Очистить историю</string>
|
<string name="clear_history">Очистить историю</string>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="remote_sources">Remote sources</string>
|
<string name="remote_sources">Remote sources</string>
|
||||||
<string name="loading_">Loading…</string>
|
<string name="loading_">Loading…</string>
|
||||||
<string name="chapter_d_of_d">Chapter %d of %d</string>
|
<string name="chapter_d_of_d">Chapter %1$d of %2$d</string>
|
||||||
<string name="close">Close</string>
|
<string name="close">Close</string>
|
||||||
<string name="try_again">Try again</string>
|
<string name="try_again">Try again</string>
|
||||||
<string name="clear_history">Clear history</string>
|
<string name="clear_history">Clear history</string>
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ object AssertX {
|
|||||||
cn.connect()
|
cn.connect()
|
||||||
when (val code = cn.responseCode) {
|
when (val code = cn.responseCode) {
|
||||||
HttpURLConnection.HTTP_MOVED_PERM,
|
HttpURLConnection.HTTP_MOVED_PERM,
|
||||||
HttpURLConnection.HTTP_MOVED_TEMP -> assertContentType(cn.getHeaderField("Location"), *types)
|
HttpURLConnection.HTTP_MOVED_TEMP -> {
|
||||||
|
assertContentType(cn.getHeaderField("Location"), *types)
|
||||||
|
}
|
||||||
HttpURLConnection.HTTP_OK -> {
|
HttpURLConnection.HTTP_OK -> {
|
||||||
val ct = cn.contentType.substringBeforeLast(';').split("/")
|
val ct = cn.contentType.substringBeforeLast(';').split("/")
|
||||||
Assert.assertTrue(types.any {
|
Assert.assertTrue(types.any {
|
||||||
|
|||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
#Sun Mar 08 18:35:17 EET 2020
|
#Sat Mar 28 11:01:15 EET 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||||
|
|||||||
Reference in New Issue
Block a user