mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-28 17:19:00 +03:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
48c802a294
122 changed files with 1600 additions and 1184 deletions
|
@ -22,7 +22,6 @@ shortcutHelper.setFilePath("./shortcuts.xml")
|
|||
|
||||
android {
|
||||
compileSdkVersion(AndroidConfig.compileSdk)
|
||||
buildToolsVersion(AndroidConfig.buildTools)
|
||||
ndkVersion = AndroidConfig.ndk
|
||||
|
||||
defaultConfig {
|
||||
|
@ -150,6 +149,7 @@ dependencies {
|
|||
implementation("androidx.constraintlayout:constraintlayout:2.1.0-beta02")
|
||||
implementation("androidx.coordinatorlayout:coordinatorlayout:1.1.0")
|
||||
implementation("androidx.core:core-ktx:1.7.0-alpha01")
|
||||
implementation("androidx.core:core-splashscreen:1.0.0-alpha01")
|
||||
implementation("androidx.multidex:multidex:2.0.1")
|
||||
implementation("androidx.preference:preference-ktx:1.1.1")
|
||||
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
||||
|
@ -247,12 +247,6 @@ dependencies {
|
|||
implementation("com.github.tachiyomiorg:DirectionalViewPager:1.0.0")
|
||||
implementation("dev.chrisbanes.insetter:insetter:0.6.0")
|
||||
|
||||
// 3.2.0+ introduces weird UI blinking or cut off issues on some devices
|
||||
val materialDialogsVersion = "3.1.1"
|
||||
implementation("com.afollestad.material-dialogs:core:$materialDialogsVersion")
|
||||
implementation("com.afollestad.material-dialogs:input:$materialDialogsVersion")
|
||||
implementation("com.afollestad.material-dialogs:datetime:$materialDialogsVersion")
|
||||
|
||||
// Conductor
|
||||
val conductorVersion = "3.0.0"
|
||||
implementation("com.bluelinelabs:conductor:$conductorVersion")
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<activity
|
||||
android:name=".ui.main.MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/Theme.Splash">
|
||||
android:theme="@style/Theme.Tachiyomi.SplashScreen">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
|
|
@ -74,7 +74,7 @@ class AnimelibUpdateNotifier(private val context: Context) {
|
|||
.setContentTitle(context.getString(R.string.notification_check_updates))
|
||||
.setContentText("($current/$total)")
|
||||
} else {
|
||||
val updatingText = anime.joinToString("\n") { it.title }
|
||||
val updatingText = anime.joinToString("\n") { it.title.chop(40) }
|
||||
progressNotificationBuilder
|
||||
.setContentTitle(context.getString(R.string.notification_updating, current, total))
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
|
||||
|
|
|
@ -295,7 +295,6 @@ class AnimelibUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingAnime.add(anime)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingAnime,
|
||||
progressCount.get(),
|
||||
|
@ -328,6 +327,7 @@ class AnimelibUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingAnime.remove(anime)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingAnime,
|
||||
progressCount.get(),
|
||||
|
@ -416,7 +416,6 @@ class AnimelibUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingAnime.add(anime)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingAnime,
|
||||
progressCount.get(),
|
||||
|
@ -440,6 +439,7 @@ class AnimelibUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingAnime.remove(anime)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingAnime,
|
||||
progressCount.get(),
|
||||
|
|
|
@ -74,7 +74,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
|||
.setContentTitle(context.getString(R.string.notification_check_updates))
|
||||
.setContentText("($current/$total)")
|
||||
} else {
|
||||
val updatingText = manga.joinToString("\n") { it.title }
|
||||
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
|
||||
progressNotificationBuilder
|
||||
.setContentTitle(context.getString(R.string.notification_updating, current, total))
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
|
||||
|
|
|
@ -295,7 +295,6 @@ class LibraryUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingManga.add(manga)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount.get(),
|
||||
|
@ -328,6 +327,7 @@ class LibraryUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingManga.remove(manga)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount.get(),
|
||||
|
@ -416,7 +416,6 @@ class LibraryUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingManga.add(manga)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount.get(),
|
||||
|
@ -440,6 +439,7 @@ class LibraryUpdateService(
|
|||
}
|
||||
|
||||
currentlyUpdatingManga.remove(manga)
|
||||
progressCount.andIncrement
|
||||
notifier.showProgressNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount.get(),
|
||||
|
|
|
@ -27,8 +27,9 @@ object PreferenceValues {
|
|||
GREEN_APPLE(R.string.theme_greenapple),
|
||||
MIDNIGHT_DUSK(R.string.theme_midnightdusk),
|
||||
STRAWBERRY_DAIQUIRI(R.string.theme_strawberrydaiquiri),
|
||||
YOTSUBA(R.string.theme_yotsuba),
|
||||
TAKO(R.string.theme_tako),
|
||||
YINYANG(R.string.theme_yinyang),
|
||||
YOTSUBA(R.string.theme_yotsuba),
|
||||
|
||||
// Deprecated
|
||||
DARK_BLUE(null),
|
||||
|
|
|
@ -40,6 +40,14 @@ abstract class TrackService(val id: Int) {
|
|||
|
||||
abstract fun getStatus(status: Int): String
|
||||
|
||||
abstract fun getReadingStatus(): Int
|
||||
|
||||
abstract fun getWatchingStatus(): Int
|
||||
|
||||
abstract fun getRereadingStatus(): Int
|
||||
|
||||
abstract fun getRewatchingStatus(): Int
|
||||
|
||||
abstract fun getCompletionStatus(): Int
|
||||
|
||||
abstract fun getScoreList(): List<String>
|
||||
|
@ -52,13 +60,13 @@ abstract class TrackService(val id: Int) {
|
|||
|
||||
abstract fun displayScore(track: AnimeTrack): String
|
||||
|
||||
abstract suspend fun update(track: Track): Track
|
||||
abstract suspend fun update(track: Track, didReadChapter: Boolean = false): Track
|
||||
|
||||
abstract suspend fun update(track: AnimeTrack): AnimeTrack
|
||||
abstract suspend fun update(track: AnimeTrack, didReadChapter: Boolean = false): AnimeTrack
|
||||
|
||||
abstract suspend fun bind(track: Track): Track
|
||||
abstract suspend fun bind(track: Track, hasReadChapters: Boolean = false): Track
|
||||
|
||||
abstract suspend fun bind(track: AnimeTrack): AnimeTrack
|
||||
abstract suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean = false): AnimeTrack
|
||||
|
||||
abstract suspend fun search(query: String): List<TrackSearch>
|
||||
|
||||
|
|
|
@ -82,6 +82,14 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getReadingStatus(): Int = READING
|
||||
|
||||
override fun getWatchingStatus(): Int = WATCHING
|
||||
|
||||
override fun getRereadingStatus(): Int = REPEATING
|
||||
|
||||
override fun getRewatchingStatus(): Int = REPEATING_ANIME
|
||||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
|
@ -166,7 +174,7 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
|||
return api.addLibAnime(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: Track): Track {
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
// If user was using API v1 fetch library_id
|
||||
if (track.library_id == null || track.library_id!! == 0L) {
|
||||
val libManga = api.findLibManga(track, getUsername().toInt())
|
||||
|
@ -174,10 +182,16 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
|||
track.library_id = libManga.library_id
|
||||
}
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
if (track.status != REPEATING && didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun update(track: AnimeTrack, didReadChapter: Boolean): AnimeTrack {
|
||||
// If user was using API v1 fetch library_id
|
||||
if (track.library_id == null || track.library_id!! == 0L) {
|
||||
val libManga = api.findLibAnime(track, getUsername().toInt())
|
||||
|
@ -188,21 +202,27 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
|||
return api.updateLibAnime(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track): Track {
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val remoteTrack = api.findLibManga(track, getUsername().toInt())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
val isRereading = track.status == REPEATING
|
||||
track.status = if (isRereading.not() && hasReadChapters) READING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = READING
|
||||
track.status = if (hasReadChapters) READING else PLANNING
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun bind(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean): AnimeTrack {
|
||||
val remoteTrack = api.findLibAnime(track, getUsername().toInt())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
|
|
|
@ -2,9 +2,6 @@ package eu.kanade.tachiyomi.data.track.anilist
|
|||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import com.afollestad.date.dayOfMonth
|
||||
import com.afollestad.date.month
|
||||
import com.afollestad.date.year
|
||||
import eu.kanade.tachiyomi.data.database.models.AnimeTrack
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
|
@ -531,9 +528,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = dateValue
|
||||
return buildJsonObject {
|
||||
put("year", calendar.year)
|
||||
put("month", calendar.month + 1)
|
||||
put("day", calendar.dayOfMonth)
|
||||
put("year", calendar.get(Calendar.YEAR))
|
||||
put("month", calendar.get(Calendar.MONTH) + 1)
|
||||
put("day", calendar.get(Calendar.DAY_OF_MONTH))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,40 +45,61 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
|
|||
return api.addLibAnime(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: Track): Track {
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
if (didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun update(track: AnimeTrack, didReadChapter: Boolean): AnimeTrack {
|
||||
if (track.status != COMPLETED) {
|
||||
if (didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibAnime(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track): Track {
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val statusTrack = api.statusLibManga(track)
|
||||
val remoteTrack = api.findLibManga(track)
|
||||
return if (remoteTrack != null && statusTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
track.status = statusTrack.status
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
track.status = if (hasReadChapters) READING else statusTrack.status
|
||||
}
|
||||
|
||||
track.score = statusTrack.score
|
||||
track.last_chapter_read = statusTrack.last_chapter_read
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
refresh(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = READING
|
||||
track.status = if (hasReadChapters) READING else PLANNING
|
||||
track.score = 0F
|
||||
add(track)
|
||||
update(track)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun bind(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean): AnimeTrack {
|
||||
val statusTrack = api.statusLibAnime(track)
|
||||
val remoteTrack = api.findLibAnime(track)
|
||||
return if (remoteTrack != null && statusTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
track.status = if (hasReadChapters) READING else statusTrack.status
|
||||
}
|
||||
|
||||
track.status = statusTrack.status
|
||||
track.score = statusTrack.score
|
||||
track.last_episode_seen = statusTrack.last_episode_seen
|
||||
|
@ -86,7 +107,7 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
|
|||
refresh(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = READING
|
||||
track.status = if (hasReadChapters) READING else PLANNING
|
||||
track.score = 0F
|
||||
add(track)
|
||||
update(track)
|
||||
|
@ -142,6 +163,14 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getReadingStatus(): Int = READING
|
||||
|
||||
override fun getWatchingStatus(): Int = READING
|
||||
|
||||
override fun getRereadingStatus(): Int = -1
|
||||
|
||||
override fun getRewatchingStatus(): Int = -1
|
||||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override suspend fun login(username: String, password: String) = login(password)
|
||||
|
|
|
@ -61,6 +61,14 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getReadingStatus(): Int = READING
|
||||
|
||||
override fun getWatchingStatus(): Int = WATCHING
|
||||
|
||||
override fun getRereadingStatus(): Int = -1
|
||||
|
||||
override fun getRewatchingStatus(): Int = -1
|
||||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
|
@ -90,35 +98,57 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
|||
return api.addLibAnime(track, getUserId())
|
||||
}
|
||||
|
||||
override suspend fun update(track: Track): Track {
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
if (didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun update(track: AnimeTrack, didReadChapter: Boolean): AnimeTrack {
|
||||
if (track.status != COMPLETED) {
|
||||
if (didReadChapter) {
|
||||
track.status = WATCHING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibAnime(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track): Track {
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val remoteTrack = api.findLibManga(track, getUserId())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
track.status = if (hasReadChapters) READING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
track.status = READING
|
||||
track.status = if (hasReadChapters) READING else PLAN_TO_READ
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun bind(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean): AnimeTrack {
|
||||
val remoteTrack = api.findLibAnime(track, getUserId())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
track.status = if (hasReadChapters) WATCHING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
track.status = WATCHING
|
||||
track.status = if (hasReadChapters) WATCHING else PLAN_TO_WATCH
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
|
|
|
@ -55,6 +55,14 @@ class Komga(private val context: Context, id: Int) : TrackService(id), Unattende
|
|||
}
|
||||
}
|
||||
|
||||
override fun getReadingStatus(): Int = READING
|
||||
|
||||
override fun getWatchingStatus(): Int = throw Exception("Not used")
|
||||
|
||||
override fun getRereadingStatus(): Int = -1
|
||||
|
||||
override fun getRewatchingStatus(): Int = throw Exception("Not used")
|
||||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> = emptyList()
|
||||
|
@ -62,17 +70,23 @@ class Komga(private val context: Context, id: Int) : TrackService(id), Unattende
|
|||
override fun displayScore(track: Track): String = ""
|
||||
override fun displayScore(track: AnimeTrack): String = throw Exception("Not used")
|
||||
|
||||
override suspend fun update(track: Track): Track {
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
if (didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateProgress(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: AnimeTrack): AnimeTrack = throw Exception("Not used")
|
||||
override suspend fun update(track: AnimeTrack, didReadChapter: Boolean): AnimeTrack = throw Exception("Not used")
|
||||
|
||||
override suspend fun bind(track: Track): Track {
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
return track
|
||||
}
|
||||
|
||||
override suspend fun bind(track: AnimeTrack): AnimeTrack = throw Exception("Not used")
|
||||
override suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean): AnimeTrack = throw Exception("Not used")
|
||||
|
||||
override suspend fun search(query: String): List<TrackSearch> = throw Exception("Not used")
|
||||
|
||||
|
|
|
@ -68,6 +68,14 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getReadingStatus(): Int = READING
|
||||
|
||||
override fun getWatchingStatus(): Int = WATCHING
|
||||
|
||||
override fun getRereadingStatus(): Int = REREADING
|
||||
|
||||
override fun getRewatchingStatus(): Int = REWATCHING
|
||||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
|
@ -83,8 +91,6 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
|||
}
|
||||
|
||||
private suspend fun add(track: Track): Track {
|
||||
track.status = READING
|
||||
track.score = 0F
|
||||
return api.updateItem(track)
|
||||
}
|
||||
|
||||
|
@ -94,32 +100,62 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
|||
return api.updateItem(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: Track): Track {
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
if (track.status != REREADING && didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateItem(track)
|
||||
}
|
||||
|
||||
override suspend fun update(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun update(track: AnimeTrack, didReadChapter: Boolean): AnimeTrack {
|
||||
if (track.status != COMPLETED) {
|
||||
if (track.status != REWATCHING && didReadChapter) {
|
||||
track.status = WATCHING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateItem(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track): Track {
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val remoteTrack = api.findListItem(track)
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
val isRereading = track.status == REREADING
|
||||
track.status = if (isRereading.not() && hasReadChapters) READING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = if (hasReadChapters) READING else PLAN_TO_READ
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun bind(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean): AnimeTrack {
|
||||
val remoteTrack = api.findListItem(track)
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
val isRereading = track.status == REWATCHING
|
||||
track.status = if (isRereading.not() && hasReadChapters) WATCHING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = if (hasReadChapters) WATCHING else PLAN_TO_WATCH
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,37 +54,61 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
|
|||
return api.addLibAnime(track, getUsername())
|
||||
}
|
||||
|
||||
override suspend fun update(track: Track): Track {
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
if (track.status != REPEATING && didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibManga(track, getUsername())
|
||||
}
|
||||
|
||||
override suspend fun update(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun update(track: AnimeTrack, didReadChapter: Boolean): AnimeTrack {
|
||||
if (track.status != COMPLETED) {
|
||||
if (track.status != REPEATING && didReadChapter) {
|
||||
track.status = READING
|
||||
}
|
||||
}
|
||||
|
||||
return api.updateLibAnime(track, getUsername())
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track): Track {
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val remoteTrack = api.findLibManga(track, getUsername())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
val isRereading = track.status == REPEATING
|
||||
track.status = if (isRereading.not() && hasReadChapters) READING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = READING
|
||||
track.status = if (hasReadChapters) READING else PLANNING
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun bind(track: AnimeTrack): AnimeTrack {
|
||||
override suspend fun bind(track: AnimeTrack, hasReadChapters: Boolean): AnimeTrack {
|
||||
val remoteTrack = api.findLibAnime(track, getUsername())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
val isRereading = track.status == REPEATING
|
||||
track.status = if (isRereading.not() && hasReadChapters) READING else track.status
|
||||
}
|
||||
|
||||
update(track)
|
||||
} else {
|
||||
// Set default fields if it's not found in the list
|
||||
track.status = READING
|
||||
track.status = if (hasReadChapters) READING else PLANNING
|
||||
track.score = 0F
|
||||
add(track)
|
||||
}
|
||||
|
@ -138,6 +162,14 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getReadingStatus(): Int = READING
|
||||
|
||||
override fun getWatchingStatus(): Int = READING
|
||||
|
||||
override fun getRereadingStatus(): Int = REPEATING
|
||||
|
||||
override fun getRewatchingStatus(): Int = REPEATING
|
||||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override suspend fun login(username: String, password: String) = login(password)
|
||||
|
|
|
@ -306,7 +306,7 @@ class AnimeController :
|
|||
}
|
||||
}
|
||||
|
||||
trackSheet = TrackSheet(this, anime!!)
|
||||
trackSheet = TrackSheet(this, anime!!, (activity as MainActivity).supportFragmentManager)
|
||||
|
||||
updateFilterIconState()
|
||||
}
|
||||
|
@ -678,7 +678,7 @@ class AnimeController :
|
|||
}
|
||||
}
|
||||
|
||||
private fun shareCover() {
|
||||
fun shareCover() {
|
||||
try {
|
||||
val activity = activity!!
|
||||
val cover = presenter.shareCover(activity)
|
||||
|
@ -690,7 +690,7 @@ class AnimeController :
|
|||
}
|
||||
}
|
||||
|
||||
private fun saveCover() {
|
||||
fun saveCover() {
|
||||
try {
|
||||
presenter.saveCover(activity!!)
|
||||
activity?.toast(R.string.cover_saved)
|
||||
|
@ -700,7 +700,7 @@ class AnimeController :
|
|||
}
|
||||
}
|
||||
|
||||
private fun changeCover() {
|
||||
fun changeCover() {
|
||||
val anime = anime ?: return
|
||||
if (anime.hasCustomCover(coverCache)) {
|
||||
ChangeAnimeCoverDialog(this, anime).showDialog(router)
|
||||
|
|
|
@ -815,7 +815,8 @@ class AnimePresenter(
|
|||
item.anime_id = anime.id!!
|
||||
launchIO {
|
||||
try {
|
||||
service.bind(item)
|
||||
val hasReadChapters = allEpisodes.any { it.seen }
|
||||
service.bind(item, hasReadChapters)
|
||||
db.insertTrack(item).executeAsBlocking()
|
||||
|
||||
if (service is UnattendedTrackService) {
|
||||
|
@ -866,6 +867,9 @@ class AnimePresenter(
|
|||
|
||||
fun setTrackerLastEpisodeSeen(item: TrackItem, episodeNumber: Int) {
|
||||
val track = item.track!!
|
||||
if (track.last_episode_seen == 0 && track.last_episode_seen < episodeNumber && track.status != item.service.getRereadingStatus()) {
|
||||
track.status = item.service.getReadingStatus()
|
||||
}
|
||||
track.last_episode_seen = episodeNumber
|
||||
if (track.total_episodes != 0 && track.last_episode_seen == track.total_episodes) {
|
||||
track.status = item.service.getCompletionStatus()
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.anime.episode
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
|
@ -15,12 +15,13 @@ class DeleteEpisodesDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.confirm_delete_episodes)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.confirm_delete_chapters)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.deleteEpisodes()
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,9 +3,8 @@ package eu.kanade.tachiyomi.ui.anime.episode
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.DialogCustomDownloadView
|
||||
|
@ -57,13 +56,14 @@ class DownloadCustomEpisodesDialog<T> : DialogController
|
|||
|
||||
// Build dialog.
|
||||
// when positive dialog is pressed call custom listener.
|
||||
return MaterialDialog(activity)
|
||||
.title(R.string.custom_download)
|
||||
.customView(view = view, scrollable = true)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.custom_download)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.downloadCustomEpisodes(view.amount)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,8 +3,7 @@ package eu.kanade.tachiyomi.ui.anime.episode
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -24,13 +23,10 @@ class SetEpisodeSettingsDialog(bundle: Bundle? = null) : DialogController(bundle
|
|||
setOptionDescription(R.string.also_set_episode_settings_for_library)
|
||||
}
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.episode_settings)
|
||||
.customView(
|
||||
view = view,
|
||||
horizontalPadding = true
|
||||
)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.chapter_settings)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
EpisodeSettingsHelper.setGlobalSettings(args.getSerializable(ANIME_KEY)!! as Anime)
|
||||
if (view.isChecked()) {
|
||||
EpisodeSettingsHelper.updateAllAnimesWithGlobalDefaults()
|
||||
|
@ -38,7 +34,8 @@ class SetEpisodeSettingsDialog(bundle: Bundle? = null) : DialogController(bundle
|
|||
|
||||
activity?.toast(activity!!.getString(R.string.episode_settings_updated))
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.view.ViewGroup
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.loadAny
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.AnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.AnimeSourceManager
|
||||
|
@ -177,16 +178,34 @@ class AnimeInfoHeaderAdapter(
|
|||
|
||||
binding.mangaCover.longClicks()
|
||||
.onEach {
|
||||
controller.activity?.copyToClipboard(
|
||||
view.context.getString(R.string.title),
|
||||
controller.presenter.anime.title
|
||||
)
|
||||
showCoverOptionsDialog()
|
||||
}
|
||||
.launchIn(controller.viewScope)
|
||||
|
||||
setAnimeInfo(anime, source)
|
||||
}
|
||||
|
||||
private fun showCoverOptionsDialog() {
|
||||
val options = listOfNotNull(
|
||||
R.string.action_share,
|
||||
R.string.action_save,
|
||||
// Can only edit cover for library anime
|
||||
if (anime.favorite) R.string.action_edit else null
|
||||
).map(controller.activity!!::getString).toTypedArray()
|
||||
|
||||
MaterialAlertDialogBuilder(controller.activity!!)
|
||||
.setTitle(R.string.manga_cover)
|
||||
.setItems(options) { _, item ->
|
||||
when (item) {
|
||||
0 -> controller.shareCover()
|
||||
1 -> controller.saveCover()
|
||||
2 -> controller.changeCover()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the view with anime information.
|
||||
*
|
||||
|
|
|
@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.anime.track
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.widget.NumberPicker
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.afollestad.materialdialogs.customview.getCustomView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.AnimeTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.TrackChaptersDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
@ -38,23 +37,9 @@ class SetTrackEpisodesDialog<T> : DialogController
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val item = item
|
||||
val pickerView = TrackChaptersDialogBinding.inflate(LayoutInflater.from(activity!!))
|
||||
val np = pickerView.chaptersPicker
|
||||
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(R.string.episodes)
|
||||
.customView(R.layout.track_chapters_dialog, dialogWrapContent = false)
|
||||
.positiveButton(android.R.string.ok) { dialog ->
|
||||
val view = dialog.getCustomView()
|
||||
// Remove focus to update selected number
|
||||
val np: NumberPicker = view.findViewById(R.id.chapters_picker)
|
||||
np.clearFocus()
|
||||
|
||||
listener.setEpisodesSeen(item, np.value)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
val view = dialog.getCustomView()
|
||||
val np: NumberPicker = view.findViewById(R.id.chapters_picker)
|
||||
// Set initial value
|
||||
np.value = item.track?.last_episode_seen ?: 0
|
||||
|
||||
|
@ -66,7 +51,15 @@ class SetTrackEpisodesDialog<T> : DialogController
|
|||
// Don't allow to go from 0 to 9999
|
||||
np.wrapSelectorWheel = false
|
||||
|
||||
return dialog
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.chapters)
|
||||
.setView(pickerView.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
np.clearFocus()
|
||||
listener.setEpisodesSeen(item, np.value)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.anime.track
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.widget.NumberPicker
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.afollestad.materialdialogs.customview.getCustomView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.AnimeTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.TrackScoreDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
@ -38,23 +37,9 @@ class SetTrackScoreDialog<T> : DialogController
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val item = item
|
||||
val pickerView = TrackScoreDialogBinding.inflate(LayoutInflater.from(activity!!))
|
||||
val np = pickerView.scorePicker
|
||||
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(R.string.score)
|
||||
.customView(R.layout.track_score_dialog, dialogWrapContent = false)
|
||||
.positiveButton(android.R.string.ok) { dialog ->
|
||||
val view = dialog.getCustomView()
|
||||
// Remove focus to update selected number
|
||||
val np: NumberPicker = view.findViewById(R.id.score_picker)
|
||||
np.clearFocus()
|
||||
|
||||
listener.setScore(item, np.value)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
val view = dialog.getCustomView()
|
||||
val np: NumberPicker = view.findViewById(R.id.score_picker)
|
||||
val scores = item.service.getScoreList().toTypedArray()
|
||||
np.maxValue = scores.size - 1
|
||||
np.displayedValues = scores
|
||||
|
@ -66,7 +51,15 @@ class SetTrackScoreDialog<T> : DialogController
|
|||
np.value = if (index != -1) index else 0
|
||||
}
|
||||
|
||||
return dialog
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.score)
|
||||
.setView(pickerView.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
np.clearFocus()
|
||||
listener.setScore(item, np.value)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,9 +3,8 @@ package eu.kanade.tachiyomi.ui.anime.track
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.AnimeTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
|
@ -39,19 +38,18 @@ class SetTrackStatusDialog<T> : DialogController
|
|||
val item = item
|
||||
val statusList = item.service.getStatusListAnime()
|
||||
val statusString = statusList.map { item.service.getStatus(it) }
|
||||
val selectedIndex = statusList.indexOf(item.track?.status)
|
||||
var selectedIndex = statusList.indexOf(item.track?.status)
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.status)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.listItemsSingleChoice(
|
||||
items = statusString,
|
||||
initialSelection = selectedIndex,
|
||||
waitForPositiveButton = false
|
||||
) { dialog, position, _ ->
|
||||
listener.setStatus(item, position)
|
||||
dialog.dismiss()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.status)
|
||||
.setSingleChoiceItems(statusString.toTypedArray(), selectedIndex) { _, which ->
|
||||
selectedIndex = which
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
listener.setStatus(item, selectedIndex)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.anime.track
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.datetime.datePicker
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.AnimeTrack
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Calendar
|
||||
|
||||
class SetTrackWatchingDatesDialog<T> : DialogController
|
||||
where T : Controller {
|
||||
|
||||
private val item: TrackItem
|
||||
|
||||
private val dateToUpdate: ReadingDate
|
||||
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, listener: Listener, dateToUpdate: ReadingDate, item: TrackItem) : super(
|
||||
bundleOf(KEY_ITEM_TRACK to item.track)
|
||||
) {
|
||||
targetController = target
|
||||
this.listener = listener
|
||||
this.item = item
|
||||
this.dateToUpdate = dateToUpdate
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : super(bundle) {
|
||||
val track = bundle.getSerializable(KEY_ITEM_TRACK) as AnimeTrack
|
||||
val service = Injekt.get<TrackManager>().getService(track.sync_id)!!
|
||||
item = TrackItem(track, service)
|
||||
dateToUpdate = ReadingDate.Start
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(
|
||||
when (dateToUpdate) {
|
||||
ReadingDate.Start -> R.string.track_started_reading_date
|
||||
ReadingDate.Finish -> R.string.track_finished_reading_date
|
||||
}
|
||||
)
|
||||
.datePicker(currentDate = getCurrentDate()) { _, date ->
|
||||
listener.setReadingDate(item, dateToUpdate, date.timeInMillis)
|
||||
}
|
||||
.neutralButton(R.string.action_remove) {
|
||||
listener.setReadingDate(item, dateToUpdate, 0L)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentDate(): Calendar {
|
||||
// Today if no date is set, otherwise the already set date
|
||||
return Calendar.getInstance().apply {
|
||||
item.track?.let {
|
||||
val date = when (dateToUpdate) {
|
||||
ReadingDate.Start -> it.started_watching_date
|
||||
ReadingDate.Finish -> it.finished_watching_date
|
||||
}
|
||||
if (date != 0L) {
|
||||
timeInMillis = date
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun setReadingDate(item: TrackItem, type: ReadingDate, date: Long)
|
||||
}
|
||||
|
||||
enum class ReadingDate {
|
||||
Start,
|
||||
Finish
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_ITEM_TRACK = "SetTrackReadingDatesDialog.item.track"
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
||||
import eu.kanade.tachiyomi.util.view.applyElevationOverlay
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder>() {
|
||||
|
||||
|
@ -40,13 +39,16 @@ class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder
|
|||
}
|
||||
|
||||
interface OnClickListener {
|
||||
fun onLogoClick(position: Int)
|
||||
fun onOpenInBrowserClick(position: Int)
|
||||
fun onSetClick(position: Int)
|
||||
fun onTitleLongClick(position: Int)
|
||||
fun onStatusClick(position: Int)
|
||||
fun onEpisodesClick(position: Int)
|
||||
fun onScoreClick(position: Int)
|
||||
fun onStartDateClick(position: Int)
|
||||
fun onFinishDateClick(position: Int)
|
||||
fun onStartDateEditClick(position: Int)
|
||||
fun onStartDateRemoveClick(position: Int)
|
||||
fun onFinishDateEditClick(position: Int)
|
||||
fun onFinishDateRemoveClick(position: Int)
|
||||
fun onRemoveItemClick(position: Int)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
||||
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
|
||||
|
@ -17,10 +18,9 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
preferences.dateFormat()
|
||||
}
|
||||
|
||||
init {
|
||||
val listener = adapter.rowClickListener
|
||||
private val listener = adapter.rowClickListener
|
||||
|
||||
binding.logoContainer.setOnClickListener { listener.onLogoClick(bindingAdapterPosition) }
|
||||
init {
|
||||
binding.trackSet.setOnClickListener { listener.onSetClick(bindingAdapterPosition) }
|
||||
binding.trackTitle.setOnClickListener { listener.onSetClick(bindingAdapterPosition) }
|
||||
binding.trackTitle.setOnLongClickListener {
|
||||
|
@ -30,8 +30,6 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
binding.trackStatus.setOnClickListener { listener.onStatusClick(bindingAdapterPosition) }
|
||||
binding.trackChapters.setOnClickListener { listener.onEpisodesClick(bindingAdapterPosition) }
|
||||
binding.trackScore.setOnClickListener { listener.onScoreClick(bindingAdapterPosition) }
|
||||
binding.trackStartDate.setOnClickListener { listener.onStartDateClick(bindingAdapterPosition) }
|
||||
binding.trackFinishDate.setOnClickListener { listener.onFinishDateClick(bindingAdapterPosition) }
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
|
@ -42,6 +40,7 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
|
||||
binding.trackSet.isVisible = track == null
|
||||
binding.trackTitle.isVisible = track != null
|
||||
binding.more.isVisible = track != null
|
||||
|
||||
binding.middleRow.isVisible = track != null
|
||||
binding.bottomDivider.isVisible = track != null
|
||||
|
@ -77,20 +76,55 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
if (track.started_watching_date != 0L) {
|
||||
binding.trackStartDate.text = dateFormat.format(track.started_watching_date)
|
||||
binding.trackStartDate.alpha = SET_STATUS_TEXT_ALPHA
|
||||
binding.trackStartDate.setOnClickListener {
|
||||
it.popupMenu(R.menu.track_item_date) {
|
||||
when (itemId) {
|
||||
R.id.action_edit -> listener.onStartDateEditClick(bindingAdapterPosition)
|
||||
R.id.action_remove -> listener.onStartDateRemoveClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.trackStartDate.text = ctx.getString(R.string.track_started_reading_date)
|
||||
binding.trackStartDate.alpha = UNSET_STATUS_TEXT_ALPHA
|
||||
binding.trackStartDate.setOnClickListener {
|
||||
listener.onStartDateEditClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
if (track.finished_watching_date != 0L) {
|
||||
binding.trackFinishDate.text = dateFormat.format(track.finished_watching_date)
|
||||
binding.trackFinishDate.alpha = SET_STATUS_TEXT_ALPHA
|
||||
binding.trackFinishDate.setOnClickListener {
|
||||
it.popupMenu(R.menu.track_item_date) {
|
||||
when (itemId) {
|
||||
R.id.action_edit -> listener.onFinishDateEditClick(bindingAdapterPosition)
|
||||
R.id.action_remove -> listener.onFinishDateRemoveClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.trackFinishDate.text = ctx.getString(R.string.track_finished_reading_date)
|
||||
binding.trackFinishDate.alpha = UNSET_STATUS_TEXT_ALPHA
|
||||
binding.trackFinishDate.setOnClickListener {
|
||||
listener.onFinishDateEditClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.bottomDivider.isVisible = supportsWatchingDates
|
||||
binding.bottomRow.isVisible = supportsWatchingDates
|
||||
|
||||
binding.more.setOnClickListener {
|
||||
it.popupMenu(R.menu.track_item) {
|
||||
when (itemId) {
|
||||
R.id.action_open_in_browser -> {
|
||||
listener.onOpenInBrowserClick(bindingAdapterPosition)
|
||||
}
|
||||
R.id.action_remove -> {
|
||||
listener.onRemoveItemClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,14 +74,9 @@ class TrackSearchDialog : DialogController {
|
|||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
R.id.remove -> {
|
||||
trackController.presenter.unregisterTracking(service)
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
binding!!.toolbar.menu.findItem(R.id.remove).isVisible = currentTrackUrl != null
|
||||
|
||||
// Create adapter
|
||||
adapter = TrackSearchAdapter(currentTrackUrl) { which ->
|
||||
|
|
|
@ -3,9 +3,14 @@ package eu.kanade.tachiyomi.ui.anime.track
|
|||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import eu.kanade.tachiyomi.R.string
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.DateValidatorPointBackward
|
||||
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.AnimeSourceManager
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.data.track.UnattendedTrackService
|
||||
|
@ -13,6 +18,7 @@ import eu.kanade.tachiyomi.databinding.TrackControllerBinding
|
|||
import eu.kanade.tachiyomi.ui.anime.AnimeController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.toUtcCalendar
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
|
@ -23,13 +29,13 @@ import uy.kohesive.injekt.api.get
|
|||
class TrackSheet(
|
||||
val controller: AnimeController,
|
||||
val anime: Anime,
|
||||
val fragmentManager: FragmentManager,
|
||||
private val sourceManager: AnimeSourceManager = Injekt.get()
|
||||
) : BaseBottomSheetDialog(controller.activity!!),
|
||||
TrackAdapter.OnClickListener,
|
||||
SetTrackStatusDialog.Listener,
|
||||
SetTrackEpisodesDialog.Listener,
|
||||
SetTrackScoreDialog.Listener,
|
||||
SetTrackWatchingDatesDialog.Listener {
|
||||
SetTrackScoreDialog.Listener {
|
||||
|
||||
private lateinit var binding: TrackControllerBinding
|
||||
|
||||
|
@ -63,7 +69,7 @@ class TrackSheet(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onLogoClick(position: Int) {
|
||||
override fun onOpenInBrowserClick(position: Int) {
|
||||
val track = adapter.getItem(position)?.track ?: return
|
||||
|
||||
if (track.tracking_url.isNotBlank()) {
|
||||
|
@ -81,7 +87,7 @@ class TrackSheet(
|
|||
}
|
||||
|
||||
if (!item.service.accept(sourceManager.getOrStub(anime.source))) {
|
||||
controller.presenter.view?.applicationContext?.toast(string.source_unsupported)
|
||||
controller.presenter.view?.applicationContext?.toast(R.string.source_unsupported)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -90,9 +96,9 @@ class TrackSheet(
|
|||
item.service.match(anime)?.let { track ->
|
||||
controller.presenter.registerTracking(track, item.service)
|
||||
}
|
||||
?: withUIContext { controller.presenter.view?.applicationContext?.toast(string.error_no_match) }
|
||||
?: withUIContext { controller.presenter.view?.applicationContext?.toast(R.string.error_no_match) }
|
||||
} catch (e: Exception) {
|
||||
withUIContext { controller.presenter.view?.applicationContext?.toast(string.error_no_match) }
|
||||
withUIContext { controller.presenter.view?.applicationContext?.toast(R.string.error_no_match) }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -128,18 +134,74 @@ class TrackSheet(
|
|||
SetTrackScoreDialog(controller, this, item).showDialog(controller.router)
|
||||
}
|
||||
|
||||
override fun onStartDateClick(position: Int) {
|
||||
override fun onStartDateEditClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
|
||||
SetTrackWatchingDatesDialog(controller, this, SetTrackWatchingDatesDialog.ReadingDate.Start, item).showDialog(controller.router)
|
||||
val selection = item.track.started_watching_date.toUtcCalendar()?.timeInMillis
|
||||
?: MaterialDatePicker.todayInUtcMilliseconds()
|
||||
|
||||
// No time travellers allowed
|
||||
val constraints = CalendarConstraints.Builder().apply {
|
||||
val finishedMillis = item.track.finished_watching_date.toUtcCalendar()?.timeInMillis
|
||||
if (finishedMillis != null) {
|
||||
setValidator(DateValidatorPointBackward.before(finishedMillis))
|
||||
}
|
||||
}.build()
|
||||
|
||||
val picker = MaterialDatePicker.Builder.datePicker()
|
||||
.setTitleText(R.string.track_started_reading_date)
|
||||
.setSelection(selection)
|
||||
.setCalendarConstraints(constraints)
|
||||
.build()
|
||||
picker.addOnPositiveButtonClickListener {
|
||||
controller.presenter.setTrackerStartDate(item, it)
|
||||
}
|
||||
picker.show(fragmentManager, null)
|
||||
}
|
||||
|
||||
override fun onFinishDateClick(position: Int) {
|
||||
override fun onFinishDateEditClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
|
||||
SetTrackWatchingDatesDialog(controller, this, SetTrackWatchingDatesDialog.ReadingDate.Finish, item).showDialog(controller.router)
|
||||
val selection = item.track.finished_watching_date.toUtcCalendar()?.timeInMillis
|
||||
?: MaterialDatePicker.todayInUtcMilliseconds()
|
||||
|
||||
// No time travellers allowed
|
||||
val constraints = CalendarConstraints.Builder().apply {
|
||||
val startMillis = item.track.started_watching_date.toUtcCalendar()?.timeInMillis
|
||||
if (startMillis != null) {
|
||||
setValidator(DateValidatorPointForward.from(item.track.started_watching_date))
|
||||
}
|
||||
}.build()
|
||||
|
||||
val picker = MaterialDatePicker.Builder.datePicker()
|
||||
.setTitleText(R.string.track_finished_reading_date)
|
||||
.setSelection(selection)
|
||||
.setCalendarConstraints(constraints)
|
||||
.build()
|
||||
picker.addOnPositiveButtonClickListener {
|
||||
controller.presenter.setTrackerFinishDate(item, it)
|
||||
}
|
||||
picker.show(fragmentManager, null)
|
||||
}
|
||||
|
||||
override fun onStartDateRemoveClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
controller.presenter.setTrackerStartDate(item, 0)
|
||||
}
|
||||
|
||||
override fun onFinishDateRemoveClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
controller.presenter.setTrackerFinishDate(item, 0)
|
||||
}
|
||||
|
||||
override fun onRemoveItemClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
controller.presenter.unregisterTracking(item.service)
|
||||
}
|
||||
|
||||
override fun setStatus(item: TrackItem, selection: Int) {
|
||||
|
@ -154,13 +216,6 @@ class TrackSheet(
|
|||
controller.presenter.setTrackerScore(item, score)
|
||||
}
|
||||
|
||||
override fun setReadingDate(item: TrackItem, type: SetTrackWatchingDatesDialog.ReadingDate, date: Long) {
|
||||
when (type) {
|
||||
SetTrackWatchingDatesDialog.ReadingDate.Start -> controller.presenter.setTrackerStartDate(item, date)
|
||||
SetTrackWatchingDatesDialog.ReadingDate.Finish -> controller.presenter.setTrackerFinishDate(item, date)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSearchDialog(): TrackSearchDialog? {
|
||||
return controller.router.getControllerWithTag(TAG_SEARCH_CONTROLLER) as? TrackSearchDialog
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ package eu.kanade.tachiyomi.ui.animecategory
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.input.input
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
|
||||
|
||||
/**
|
||||
* Dialog to create a new category for the library.
|
||||
|
@ -30,18 +30,16 @@ class CategoryCreateDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
* @return a new dialog instance.
|
||||
*/
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_add_category)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.input(
|
||||
hint = resources?.getString(R.string.name),
|
||||
prefill = currentName
|
||||
) { _, input ->
|
||||
currentName = input.toString()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_add_category)
|
||||
.setTextInput(prefill = currentName) {
|
||||
currentName = it
|
||||
}
|
||||
.positiveButton(android.R.string.ok) {
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.createCategory(currentName)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.ui.animecategory
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.input.input
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
|
||||
|
||||
/**
|
||||
* Dialog to rename an existing category of the library.
|
||||
|
@ -35,16 +35,14 @@ class CategoryRenameDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
* @return a new dialog instance.
|
||||
*/
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_rename_category)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.input(
|
||||
hint = resources?.getString(R.string.name),
|
||||
prefill = currentName
|
||||
) { _, input ->
|
||||
currentName = input.toString()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_rename_category)
|
||||
.setTextInput(prefill = currentName) {
|
||||
currentName = it
|
||||
}
|
||||
.positiveButton(android.R.string.ok) { onPositive() }
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> onPositive() }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,9 +14,11 @@ import eu.kanade.tachiyomi.data.database.models.Anime
|
|||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.AnimelibCategoryBinding
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.inflate
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
|
@ -106,6 +108,10 @@ class AnimelibCategoryView @JvmOverloads constructor(context: Context, attrs: At
|
|||
}
|
||||
.launchIn(scope)
|
||||
|
||||
recycler.onAnimationsFinished {
|
||||
(controller.activity as? MainActivity)?.ready = true
|
||||
}
|
||||
|
||||
// Double the distance required to trigger sync
|
||||
binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
||||
binding.swipeRefresh.refreshes()
|
||||
|
|
|
@ -277,6 +277,7 @@ class AnimelibController(
|
|||
binding.emptyView.hide()
|
||||
} else {
|
||||
binding.emptyView.show(R.string.information_empty_library)
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
|
||||
// Get the current active category.
|
||||
|
|
|
@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.animelib
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.ui.animecategory.CategoryController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||
|
||||
class ChangeAnimeCategoriesDialog<T>(bundle: Bundle? = null) :
|
||||
DialogController(bundle) where T : Controller, T : ChangeAnimeCategoriesDialog.Listener {
|
||||
|
@ -32,32 +31,34 @@ class ChangeAnimeCategoriesDialog<T>(bundle: Bundle? = null) :
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_move_category)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_move_category)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.apply {
|
||||
if (categories.isNotEmpty()) {
|
||||
listItemsMultiChoice(
|
||||
items = categories.map { it.name },
|
||||
initialSelection = preselected.toIntArray(),
|
||||
allowEmptySelection = true
|
||||
) { _, selections, _ ->
|
||||
val newCategories = selections.map { categories[it] }
|
||||
val selected = categories
|
||||
.mapIndexed { i, _ -> preselected.contains(i) }
|
||||
.toBooleanArray()
|
||||
setMultiChoiceItems(categories.map { it.name }.toTypedArray(), selected) { _, which, checked ->
|
||||
selected[which] = checked
|
||||
}
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val newCategories = categories.filterIndexed { i, _ -> selected[i] }
|
||||
(targetController as? Listener)?.updateCategoriesForAnimes(animes, newCategories)
|
||||
}
|
||||
.positiveButton(android.R.string.ok)
|
||||
} else {
|
||||
message(R.string.information_empty_category_dialog)
|
||||
.positiveButton(R.string.action_edit_categories) {
|
||||
if (targetController is AnimelibController) {
|
||||
val libController = targetController as AnimelibController
|
||||
libController.clearSelection()
|
||||
}
|
||||
router.popCurrentController()
|
||||
router.pushController(CategoryController().withFadeTransaction())
|
||||
setMessage(R.string.information_empty_category_dialog)
|
||||
setPositiveButton(R.string.action_edit_categories) { _, _ ->
|
||||
if (targetController is AnimelibController) {
|
||||
val libController = targetController as AnimelibController
|
||||
libController.clearSelection()
|
||||
}
|
||||
router.popCurrentController()
|
||||
router.pushController(CategoryController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.animelib
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -20,15 +20,16 @@ class ChangeAnimeCoverDialog<T>(bundle: Bundle? = null) :
|
|||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_edit_cover)
|
||||
.positiveButton(R.string.action_edit) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_edit_cover)
|
||||
.setPositiveButton(R.string.action_edit) { _, _ ->
|
||||
(targetController as? Listener)?.openAnimeCoverPicker(anime)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.neutralButton(R.string.action_delete) {
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setNeutralButton(R.string.action_delete) { _, _ ->
|
||||
(targetController as? Listener)?.deleteAnimeCover(anime)
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.animelib
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -20,18 +19,22 @@ class DeleteAnimelibAnimesDialog<T>(bundle: Bundle? = null) :
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_remove)
|
||||
.listItemsMultiChoice(
|
||||
R.array.delete_selected_animes,
|
||||
initialSelection = intArrayOf(0)
|
||||
) { _, selections, _ ->
|
||||
val deleteFromAnimelib = 0 in selections
|
||||
val deleteChapters = 1 in selections
|
||||
(targetController as? Listener)?.deleteAnimes(animes, deleteFromAnimelib, deleteChapters)
|
||||
val items = resources!!.getStringArray(R.array.delete_selected_animes)
|
||||
val selected = items
|
||||
.mapIndexed { i, _ -> i == 0 }
|
||||
.toBooleanArray()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_remove)
|
||||
.setMultiChoiceItems(items, selected) { _, which, checked ->
|
||||
selected[which] = checked
|
||||
}
|
||||
.positiveButton(android.R.string.ok)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val deleteFromLibrary = selected[0]
|
||||
val deleteEpisodes = selected[1]
|
||||
(targetController as? Listener)?.deleteAnimes(animes, deleteFromLibrary, deleteEpisodes)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -53,12 +53,15 @@ abstract class BaseThemedActivity : AppCompatActivity() {
|
|||
PreferenceValues.AppTheme.STRAWBERRY_DAIQUIRI -> {
|
||||
resIds += R.style.Theme_Tachiyomi_StrawberryDaiquiri
|
||||
}
|
||||
PreferenceValues.AppTheme.YOTSUBA -> {
|
||||
resIds += R.style.Theme_Tachiyomi_Yotsuba
|
||||
PreferenceValues.AppTheme.TAKO -> {
|
||||
resIds += R.style.Theme_Tachiyomi_Tako
|
||||
}
|
||||
PreferenceValues.AppTheme.YINYANG -> {
|
||||
resIds += R.style.Theme_Tachiyomi_YinYang
|
||||
}
|
||||
PreferenceValues.AppTheme.YOTSUBA -> {
|
||||
resIds += R.style.Theme_Tachiyomi_Yotsuba
|
||||
}
|
||||
else -> {
|
||||
resIds += R.style.Theme_Tachiyomi
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.browse.animeextension
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
|
@ -21,15 +21,16 @@ class AnimeExtensionTrustDialog<T>(bundle: Bundle? = null) : DialogController(bu
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.untrusted_extension)
|
||||
.message(R.string.untrusted_extension_message)
|
||||
.positiveButton(R.string.ext_trust) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.untrusted_extension)
|
||||
.setMessage(R.string.untrusted_extension_message)
|
||||
.setPositiveButton(R.string.ext_trust) { _, _ ->
|
||||
(targetController as? Listener)?.trustSignature(args.getString(SIGNATURE_KEY)!!)
|
||||
}
|
||||
.negativeButton(R.string.ext_uninstall) {
|
||||
.setNegativeButton(R.string.ext_uninstall) { _, _ ->
|
||||
(targetController as? Listener)?.uninstallExtension(args.getString(PKGNAME_KEY)!!)
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
@ -9,10 +9,9 @@ import android.view.MenuInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
|
@ -32,6 +31,8 @@ import eu.kanade.tachiyomi.ui.browse.BrowseController
|
|||
import eu.kanade.tachiyomi.ui.browse.animesource.browse.BrowseAnimeSourceController
|
||||
import eu.kanade.tachiyomi.ui.browse.animesource.globalsearch.GlobalAnimeSearchController
|
||||
import eu.kanade.tachiyomi.ui.browse.animesource.latest.LatestUpdatesController
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
|
@ -82,6 +83,9 @@ class AnimeSourceController :
|
|||
// Create recycler and set adapter.
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = adapter
|
||||
binding.recycler.onAnimationsFinished {
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
adapter?.fastScroller = binding.fastScroller
|
||||
|
||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
||||
|
@ -238,15 +242,13 @@ class AnimeSourceController :
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(text = source)
|
||||
.listItems(
|
||||
items = items.map { it.first },
|
||||
waitForPositiveButton = false
|
||||
) { dialog, which, _ ->
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(source)
|
||||
.setItems(items.map { it.first }.toTypedArray()) { dialog, which ->
|
||||
items[which].second()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ import androidx.core.view.updatePadding
|
|||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tfcporciuncula.flow.Preference
|
||||
|
@ -589,11 +588,9 @@ open class BrowseAnimeSourceController(bundle: Bundle) :
|
|||
val anime = (adapter?.getItem(position) as? AnimeSourceItem?)?.anime ?: return
|
||||
|
||||
if (anime.favorite) {
|
||||
MaterialDialog(activity)
|
||||
.listItems(
|
||||
items = listOf(activity.getString(R.string.remove_from_library)),
|
||||
waitForPositiveButton = false
|
||||
) { _, which, _ ->
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(anime.title)
|
||||
.setItems(arrayOf(activity.getString(R.string.remove_from_library))) { _, which ->
|
||||
when (which) {
|
||||
0 -> {
|
||||
presenter.changeAnimeFavorite(anime)
|
||||
|
|
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.browse.extension
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
|
@ -21,15 +21,16 @@ class ExtensionTrustDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.untrusted_extension)
|
||||
.message(R.string.untrusted_extension_message)
|
||||
.positiveButton(R.string.ext_trust) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.untrusted_extension)
|
||||
.setMessage(R.string.untrusted_extension_message)
|
||||
.setPositiveButton(R.string.ext_trust) { _, _ ->
|
||||
(targetController as? Listener)?.trustSignature(args.getString(SIGNATURE_KEY)!!)
|
||||
}
|
||||
.negativeButton(R.string.ext_uninstall) {
|
||||
.setNegativeButton(R.string.ext_uninstall) { _, _ ->
|
||||
(targetController as? Listener)?.uninstallExtension(args.getString(PKGNAME_KEY)!!)
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
@ -3,13 +3,14 @@ package eu.kanade.tachiyomi.ui.browse.migration.search
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.isVisible
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.anime.AnimeController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.browse.animesource.globalsearch.GlobalAnimeSearchController
|
||||
|
@ -69,12 +70,14 @@ class AnimeSearchController(
|
|||
super.onAnimeClick(anime)
|
||||
}
|
||||
|
||||
fun renderIsReplacingAnime(isReplacingAnime: Boolean) {
|
||||
if (isReplacingAnime) {
|
||||
binding.progress.isVisible = true
|
||||
} else {
|
||||
binding.progress.isVisible = false
|
||||
fun renderIsReplacingAnime(isReplacingAnime: Boolean, newAnime: Anime?) {
|
||||
binding.progress.isVisible = isReplacingAnime
|
||||
if (!isReplacingAnime) {
|
||||
router.popController(this)
|
||||
if (newAnime != null) {
|
||||
// Replaces old AnimeController
|
||||
router.replaceTopController(RouterTransaction.with(AnimeController(newAnime)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,28 +85,29 @@ class AnimeSearchController(
|
|||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val prefValue = preferences.migrateFlags().get()
|
||||
val enabledFlagsPositions = AnimeMigrationFlags.getEnabledFlagsPositions(prefValue)
|
||||
val items = AnimeMigrationFlags.titles
|
||||
.map { resources?.getString(it) }
|
||||
.toTypedArray()
|
||||
val selected = items
|
||||
.mapIndexed { i, _ -> enabledFlagsPositions.contains(i) }
|
||||
.toBooleanArray()
|
||||
|
||||
val preselected =
|
||||
AnimeMigrationFlags.getEnabledFlagsPositions(
|
||||
prefValue
|
||||
)
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.migration_dialog_what_to_include)
|
||||
.listItemsMultiChoice(
|
||||
items = AnimeMigrationFlags.titles.map { resources?.getString(it) as CharSequence },
|
||||
initialSelection = preselected.toIntArray()
|
||||
) { _, positions, _ ->
|
||||
// Save current settings for the next time
|
||||
val newValue =
|
||||
AnimeMigrationFlags.getFlagsFromPositions(
|
||||
positions.toTypedArray()
|
||||
)
|
||||
preferences.migrateFlags().set(newValue)
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.migration_dialog_what_to_include)
|
||||
.setMultiChoiceItems(items, selected) { _, which, checked ->
|
||||
selected[which] = checked
|
||||
}
|
||||
.positiveButton(R.string.migrate) {
|
||||
.setPositiveButton(R.string.migrate) { _, _ ->
|
||||
// Save current settings for the next time
|
||||
val selectedIndices = mutableListOf<Int>()
|
||||
selected.forEachIndexed { i, b -> if (b) selectedIndices.add(i) }
|
||||
val newValue = AnimeMigrationFlags.getFlagsFromPositions(selectedIndices.toTypedArray())
|
||||
preferences.migrateFlags().set(newValue)
|
||||
|
||||
if (callingController != null) {
|
||||
if (callingController.javaClass == AnimeSourceSearchController::class.java) {
|
||||
router.popController(callingController)
|
||||
|
@ -111,7 +115,7 @@ class AnimeSearchController(
|
|||
}
|
||||
(targetController as? AnimeSearchController)?.migrateAnime(anime, newAnime)
|
||||
}
|
||||
.negativeButton(R.string.copy) {
|
||||
.setNegativeButton(R.string.copy) { _, _, ->
|
||||
if (callingController != null) {
|
||||
if (callingController.javaClass == AnimeSourceSearchController::class.java) {
|
||||
router.popController(callingController)
|
||||
|
@ -119,7 +123,8 @@ class AnimeSearchController(
|
|||
}
|
||||
(targetController as? AnimeSearchController)?.copyAnime(anime, newAnime)
|
||||
}
|
||||
.neutralButton(android.R.string.cancel)
|
||||
.setNeutralButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,12 +26,16 @@ class AnimeSearchPresenter(
|
|||
private val anime: Anime
|
||||
) : GlobalAnimeSearchPresenter(initialQuery) {
|
||||
|
||||
private val replacingAnimeRelay = BehaviorRelay.create<Boolean>()
|
||||
private val replacingAnimeRelay = BehaviorRelay.create<Pair<Boolean, Anime?>>()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
replacingAnimeRelay.subscribeLatestCache({ controller, isReplacingAnime -> (controller as? AnimeSearchController)?.renderIsReplacingAnime(isReplacingAnime) })
|
||||
replacingAnimeRelay.subscribeLatestCache(
|
||||
{ controller, (isReplacingAnime, newAnime) ->
|
||||
(controller as? AnimeSearchController)?.renderIsReplacingAnime(isReplacingAnime, newAnime)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun getEnabledSources(): List<AnimeCatalogueSource> {
|
||||
|
@ -55,7 +59,7 @@ class AnimeSearchPresenter(
|
|||
fun migrateAnime(prevAnime: Anime, anime: Anime, replace: Boolean) {
|
||||
val source = sourceManager.get(anime.source) ?: return
|
||||
|
||||
replacingAnimeRelay.call(true)
|
||||
replacingAnimeRelay.call(Pair(true, null))
|
||||
|
||||
presenterScope.launchIO {
|
||||
try {
|
||||
|
@ -67,7 +71,7 @@ class AnimeSearchPresenter(
|
|||
withUIContext { view?.applicationContext?.toast(e.message) }
|
||||
}
|
||||
|
||||
presenterScope.launchUI { replacingAnimeRelay.call(false) }
|
||||
presenterScope.launchUI { replacingAnimeRelay.call(Pair(false, anime)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,9 @@ package eu.kanade.tachiyomi.ui.browse.migration.search
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.isVisible
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
|
@ -89,26 +88,26 @@ class SearchController(
|
|||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val prefValue = preferences.migrateFlags().get()
|
||||
val enabledFlagsPositions = MigrationFlags.getEnabledFlagsPositions(prefValue)
|
||||
val items = MigrationFlags.titles
|
||||
.map { resources?.getString(it) }
|
||||
.toTypedArray()
|
||||
val selected = items
|
||||
.mapIndexed { i, _ -> enabledFlagsPositions.contains(i) }
|
||||
.toBooleanArray()
|
||||
|
||||
val preselected =
|
||||
MigrationFlags.getEnabledFlagsPositions(
|
||||
prefValue
|
||||
)
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.migration_dialog_what_to_include)
|
||||
.listItemsMultiChoice(
|
||||
items = MigrationFlags.titles.map { resources?.getString(it) as CharSequence },
|
||||
initialSelection = preselected.toIntArray()
|
||||
) { _, positions, _ ->
|
||||
// Save current settings for the next time
|
||||
val newValue =
|
||||
MigrationFlags.getFlagsFromPositions(
|
||||
positions.toTypedArray()
|
||||
)
|
||||
preferences.migrateFlags().set(newValue)
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.migration_dialog_what_to_include)
|
||||
.setMultiChoiceItems(items, selected) { _, which, checked ->
|
||||
selected[which] = checked
|
||||
}
|
||||
.positiveButton(R.string.migrate) {
|
||||
.setPositiveButton(R.string.migrate) { _, _ ->
|
||||
// Save current settings for the next time
|
||||
val selectedIndices = mutableListOf<Int>()
|
||||
selected.forEachIndexed { i, b -> if (b) selectedIndices.add(i) }
|
||||
val newValue = MigrationFlags.getFlagsFromPositions(selectedIndices.toTypedArray())
|
||||
preferences.migrateFlags().set(newValue)
|
||||
|
||||
if (callingController != null) {
|
||||
if (callingController.javaClass == SourceSearchController::class.java) {
|
||||
router.popController(callingController)
|
||||
|
@ -116,7 +115,7 @@ class SearchController(
|
|||
}
|
||||
(targetController as? SearchController)?.migrateManga(manga, newManga)
|
||||
}
|
||||
.negativeButton(R.string.copy) {
|
||||
.setNegativeButton(R.string.copy) { _, _, ->
|
||||
if (callingController != null) {
|
||||
if (callingController.javaClass == SourceSearchController::class.java) {
|
||||
router.popController(callingController)
|
||||
|
@ -124,7 +123,8 @@ class SearchController(
|
|||
}
|
||||
(targetController as? SearchController)?.copyManga(manga, newManga)
|
||||
}
|
||||
.neutralButton(android.R.string.cancel)
|
||||
.setNeutralButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,9 @@ import android.view.MenuInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
|
@ -32,6 +31,8 @@ import eu.kanade.tachiyomi.ui.browse.BrowseController
|
|||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.latest.LatestUpdatesController
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
|
@ -82,6 +83,9 @@ class SourceController :
|
|||
// Create recycler and set adapter.
|
||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recycler.adapter = adapter
|
||||
binding.recycler.onAnimationsFinished {
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
adapter?.fastScroller = binding.fastScroller
|
||||
|
||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
||||
|
@ -238,15 +242,13 @@ class SourceController :
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(text = source)
|
||||
.listItems(
|
||||
items = items.map { it.first },
|
||||
waitForPositiveButton = false
|
||||
) { dialog, which, _ ->
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(source)
|
||||
.setItems(items.map { it.first }.toTypedArray()) { dialog, which ->
|
||||
items[which].second()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ import androidx.core.view.updatePadding
|
|||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tfcporciuncula.flow.Preference
|
||||
|
@ -589,11 +588,9 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||
val manga = (adapter?.getItem(position) as? SourceItem?)?.manga ?: return
|
||||
|
||||
if (manga.favorite) {
|
||||
MaterialDialog(activity)
|
||||
.listItems(
|
||||
items = listOf(activity.getString(R.string.remove_from_library)),
|
||||
waitForPositiveButton = false
|
||||
) { _, which, _ ->
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(manga.title)
|
||||
.setItems(arrayOf(activity.getString(R.string.remove_from_library))) { _, which ->
|
||||
when (which) {
|
||||
0 -> {
|
||||
presenter.changeMangaFavorite(manga)
|
||||
|
|
|
@ -2,11 +2,11 @@ package eu.kanade.tachiyomi.ui.category
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.input.input
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
|
||||
|
||||
/**
|
||||
* Dialog to create a new category for the library.
|
||||
|
@ -30,18 +30,16 @@ class CategoryCreateDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
* @return a new dialog instance.
|
||||
*/
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_add_category)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.input(
|
||||
hint = resources?.getString(R.string.name),
|
||||
prefill = currentName
|
||||
) { _, input ->
|
||||
currentName = input.toString()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_add_category)
|
||||
.setTextInput(prefill = currentName) {
|
||||
currentName = it
|
||||
}
|
||||
.positiveButton(android.R.string.ok) {
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.createCategory(currentName)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.ui.category
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.input.input
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
|
||||
|
||||
/**
|
||||
* Dialog to rename an existing category of the library.
|
||||
|
@ -35,16 +35,14 @@ class CategoryRenameDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
* @return a new dialog instance.
|
||||
*/
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_rename_category)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.input(
|
||||
hint = resources?.getString(R.string.name),
|
||||
prefill = currentName
|
||||
) { _, input ->
|
||||
currentName = input.toString()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_rename_category)
|
||||
.setTextInput(prefill = currentName) {
|
||||
currentName = it
|
||||
}
|
||||
.positiveButton(android.R.string.ok) { onPositive() }
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> onPositive() }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.library
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
|
@ -32,32 +31,34 @@ class ChangeMangaCategoriesDialog<T>(bundle: Bundle? = null) :
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_move_category)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_move_category)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.apply {
|
||||
if (categories.isNotEmpty()) {
|
||||
listItemsMultiChoice(
|
||||
items = categories.map { it.name },
|
||||
initialSelection = preselected.toIntArray(),
|
||||
allowEmptySelection = true
|
||||
) { _, selections, _ ->
|
||||
val newCategories = selections.map { categories[it] }
|
||||
val selected = categories
|
||||
.mapIndexed { i, _ -> preselected.contains(i) }
|
||||
.toBooleanArray()
|
||||
setMultiChoiceItems(categories.map { it.name }.toTypedArray(), selected) { _, which, checked ->
|
||||
selected[which] = checked
|
||||
}
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val newCategories = categories.filterIndexed { i, _ -> selected[i] }
|
||||
(targetController as? Listener)?.updateCategoriesForMangas(mangas, newCategories)
|
||||
}
|
||||
.positiveButton(android.R.string.ok)
|
||||
} else {
|
||||
message(R.string.information_empty_category_dialog)
|
||||
.positiveButton(R.string.action_edit_categories) {
|
||||
if (targetController is LibraryController) {
|
||||
val libController = targetController as LibraryController
|
||||
libController.clearSelection()
|
||||
}
|
||||
router.popCurrentController()
|
||||
router.pushController(CategoryController().withFadeTransaction())
|
||||
setMessage(R.string.information_empty_category_dialog)
|
||||
setPositiveButton(R.string.action_edit_categories) { _, _ ->
|
||||
if (targetController is LibraryController) {
|
||||
val libController = targetController as LibraryController
|
||||
libController.clearSelection()
|
||||
}
|
||||
router.popCurrentController()
|
||||
router.pushController(CategoryController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.library
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -20,15 +20,16 @@ class ChangeMangaCoverDialog<T>(bundle: Bundle? = null) :
|
|||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_edit_cover)
|
||||
.positiveButton(R.string.action_edit) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_edit_cover)
|
||||
.setPositiveButton(R.string.action_edit) { _, _ ->
|
||||
(targetController as? Listener)?.openMangaCoverPicker(manga)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.neutralButton(R.string.action_delete) {
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setNeutralButton(R.string.action_delete) { _, _ ->
|
||||
(targetController as? Listener)?.deleteMangaCover(manga)
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.library
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -20,18 +19,22 @@ class DeleteLibraryMangasDialog<T>(bundle: Bundle? = null) :
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_remove)
|
||||
.listItemsMultiChoice(
|
||||
R.array.delete_selected_mangas,
|
||||
initialSelection = intArrayOf(0)
|
||||
) { _, selections, _ ->
|
||||
val deleteFromLibrary = 0 in selections
|
||||
val deleteChapters = 1 in selections
|
||||
val items = resources!!.getStringArray(R.array.delete_selected_mangas)
|
||||
val selected = items
|
||||
.mapIndexed { i, _ -> i == 0 }
|
||||
.toBooleanArray()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.action_remove)
|
||||
.setMultiChoiceItems(items, selected) { _, which, checked ->
|
||||
selected[which] = checked
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val deleteFromLibrary = selected[0]
|
||||
val deleteChapters = selected[1]
|
||||
(targetController as? Listener)?.deleteMangas(mangas, deleteFromLibrary, deleteChapters)
|
||||
}
|
||||
.positiveButton(android.R.string.ok)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -14,9 +14,11 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.inflate
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
|
@ -106,6 +108,10 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||
}
|
||||
.launchIn(scope)
|
||||
|
||||
recycler.onAnimationsFinished {
|
||||
(controller.activity as? MainActivity)?.ready = true
|
||||
}
|
||||
|
||||
// Double the distance required to trigger sync
|
||||
binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * resources.displayMetrics.density).toInt())
|
||||
binding.swipeRefresh.refreshes()
|
||||
|
|
|
@ -277,6 +277,7 @@ class LibraryController(
|
|||
binding.emptyView.hide()
|
||||
} else {
|
||||
binding.emptyView.show(R.string.information_empty_library)
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
|
||||
// Get the current active category.
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
package eu.kanade.tachiyomi.ui.main
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.SearchManager
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.splashscreen.SplashScreen
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceDialogController
|
||||
import com.bluelinelabs.conductor.Conductor
|
||||
|
@ -53,6 +62,7 @@ import eu.kanade.tachiyomi.ui.more.MoreController
|
|||
import eu.kanade.tachiyomi.ui.recent.UpdatesTabsController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -87,7 +97,13 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||
|
||||
private var fixedViewsToBottom = mutableMapOf<View, AppBarLayout.OnOffsetChangedListener>()
|
||||
|
||||
// To be checked by splash screen. If true then splash screen will be removed.
|
||||
var ready = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Prevent splash screen showing up on configuration changes
|
||||
val splashScreen = if (savedInstanceState == null) installSplashScreen() else null
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val didMigration = if (savedInstanceState == null) Migrations.upgrade(preferences) else false
|
||||
|
@ -121,13 +137,12 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure navigation bar is on bottom before we modify it
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
|
||||
window.setNavigationBarTransparentCompat(this)
|
||||
}
|
||||
insets
|
||||
val startTime = System.currentTimeMillis()
|
||||
splashScreen?.setKeepVisibleCondition {
|
||||
val elapsed = System.currentTimeMillis() - startTime
|
||||
elapsed <= SPLASH_MIN_DURATION || (!ready && elapsed <= SPLASH_MAX_DURATION)
|
||||
}
|
||||
setSplashScreenExitAnimation(splashScreen)
|
||||
|
||||
tabAnimator = ViewHeightAnimator(binding.tabs, 0L)
|
||||
|
||||
|
@ -274,6 +289,79 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets custom splash screen exit animation on devices prior to Android 12.
|
||||
*
|
||||
* When custom animation is used, status and navigation bar color will be set to transparent and will be restored
|
||||
* after the animation is finished.
|
||||
*/
|
||||
private fun setSplashScreenExitAnimation(splashScreen: SplashScreen?) {
|
||||
val setNavbarScrim = {
|
||||
// Make sure navigation bar is on bottom before we modify it
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
|
||||
window.setNavigationBarTransparentCompat(this@MainActivity)
|
||||
}
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(binding.root)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
val oldStatusColor = window.statusBarColor
|
||||
val oldNavigationColor = window.navigationBarColor
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
window.navigationBarColor = Color.TRANSPARENT
|
||||
|
||||
val wicc = WindowInsetsControllerCompat(window, window.decorView)
|
||||
val isLightStatusBars = wicc.isAppearanceLightStatusBars
|
||||
val isLightNavigationBars = wicc.isAppearanceLightNavigationBars
|
||||
wicc.isAppearanceLightStatusBars = false
|
||||
wicc.isAppearanceLightNavigationBars = false
|
||||
|
||||
splashScreen?.setOnExitAnimationListener { splashProvider ->
|
||||
// For some reason the SplashScreen applies (incorrect) Y translation to the iconView
|
||||
splashProvider.iconView.translationY = 0F
|
||||
|
||||
val activityAnim = ValueAnimator.ofFloat(1F, 0F).apply {
|
||||
interpolator = LinearOutSlowInInterpolator()
|
||||
duration = SPLASH_EXIT_ANIM_DURATION
|
||||
addUpdateListener { va ->
|
||||
val value = va.animatedValue as Float
|
||||
binding.root.translationY = value * 16.dpToPx
|
||||
}
|
||||
}
|
||||
|
||||
var barColorRestored = false
|
||||
val splashAnim = ValueAnimator.ofFloat(1F, 0F).apply {
|
||||
interpolator = FastOutSlowInInterpolator()
|
||||
duration = SPLASH_EXIT_ANIM_DURATION
|
||||
addUpdateListener { va ->
|
||||
val value = va.animatedValue as Float
|
||||
splashProvider.view.alpha = value
|
||||
|
||||
if (!barColorRestored && value <= 0.5F) {
|
||||
barColorRestored = true
|
||||
wicc.isAppearanceLightStatusBars = isLightStatusBars
|
||||
wicc.isAppearanceLightNavigationBars = isLightNavigationBars
|
||||
}
|
||||
}
|
||||
doOnEnd {
|
||||
splashProvider.remove()
|
||||
window.statusBarColor = oldStatusColor
|
||||
window.navigationBarColor = oldNavigationColor
|
||||
setNavbarScrim()
|
||||
}
|
||||
}
|
||||
|
||||
activityAnim.start()
|
||||
splashAnim.start()
|
||||
}
|
||||
} else {
|
||||
setNavbarScrim()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
if (!handleIntentAction(intent)) {
|
||||
super.onNewIntent(intent)
|
||||
|
@ -402,6 +490,7 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
ready = true
|
||||
isHandlingShortcut = false
|
||||
return true
|
||||
}
|
||||
|
@ -573,6 +662,11 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||
get() = binding.bottomNav ?: binding.sideNav!!
|
||||
|
||||
companion object {
|
||||
// Splash screen
|
||||
private const val SPLASH_MIN_DURATION = 500 // ms
|
||||
private const val SPLASH_MAX_DURATION = 5000 // ms
|
||||
private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms
|
||||
|
||||
// Shortcut actions
|
||||
const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
|
||||
const val SHORTCUT_ANIMELIB = "eu.kanade.tachiyomi.SHOW_ANIMELIB"
|
||||
|
|
|
@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.main
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -12,11 +12,12 @@ class WhatsNewDialogController(bundle: Bundle? = null) : DialogController(bundle
|
|||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(text = activity!!.getString(R.string.updated_version, BuildConfig.VERSION_NAME))
|
||||
.positiveButton(android.R.string.ok)
|
||||
.neutralButton(R.string.whats_new) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(activity!!.getString(R.string.updated_version, BuildConfig.VERSION_NAME))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setNeutralButton(R.string.whats_new) { _, _ ->
|
||||
openInBrowser("https://github.com/jmir1/aniyomi/releases/tag/v${BuildConfig.VERSION_NAME}")
|
||||
}
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,7 +289,7 @@ class MangaController :
|
|||
}
|
||||
}
|
||||
|
||||
trackSheet = TrackSheet(this, manga!!)
|
||||
trackSheet = TrackSheet(this, manga!!, (activity as MainActivity).supportFragmentManager)
|
||||
|
||||
updateFilterIconState()
|
||||
}
|
||||
|
@ -661,7 +661,7 @@ class MangaController :
|
|||
}
|
||||
}
|
||||
|
||||
private fun shareCover() {
|
||||
fun shareCover() {
|
||||
try {
|
||||
val activity = activity!!
|
||||
val cover = presenter.shareCover(activity)
|
||||
|
@ -673,7 +673,7 @@ class MangaController :
|
|||
}
|
||||
}
|
||||
|
||||
private fun saveCover() {
|
||||
fun saveCover() {
|
||||
try {
|
||||
presenter.saveCover(activity!!)
|
||||
activity?.toast(R.string.cover_saved)
|
||||
|
@ -683,7 +683,7 @@ class MangaController :
|
|||
}
|
||||
}
|
||||
|
||||
private fun changeCover() {
|
||||
fun changeCover() {
|
||||
val manga = manga ?: return
|
||||
if (manga.hasCustomCover(coverCache)) {
|
||||
ChangeMangaCoverDialog(this, manga).showDialog(router)
|
||||
|
|
|
@ -779,7 +779,8 @@ class MangaPresenter(
|
|||
item.manga_id = manga.id!!
|
||||
launchIO {
|
||||
try {
|
||||
service.bind(item)
|
||||
val hasReadChapters = allChapters.any { it.read }
|
||||
service.bind(item, hasReadChapters)
|
||||
db.insertTrack(item).executeAsBlocking()
|
||||
|
||||
if (service is UnattendedTrackService) {
|
||||
|
@ -830,6 +831,9 @@ class MangaPresenter(
|
|||
|
||||
fun setTrackerLastChapterRead(item: TrackItem, chapterNumber: Int) {
|
||||
val track = item.track!!
|
||||
if (track.last_chapter_read == 0 && track.last_chapter_read < chapterNumber && track.status != item.service.getRereadingStatus()) {
|
||||
track.status = item.service.getReadingStatus()
|
||||
}
|
||||
track.last_chapter_read = chapterNumber
|
||||
if (track.total_chapters != 0 && track.last_chapter_read == track.total_chapters) {
|
||||
track.status = item.service.getCompletionStatus()
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.manga.chapter
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
|
@ -15,12 +15,13 @@ class DeleteChaptersDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.confirm_delete_chapters)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.confirm_delete_chapters)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.deleteChapters()
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,9 +3,8 @@ package eu.kanade.tachiyomi.ui.manga.chapter
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.DialogCustomDownloadView
|
||||
|
@ -57,13 +56,14 @@ class DownloadCustomChaptersDialog<T> : DialogController
|
|||
|
||||
// Build dialog.
|
||||
// when positive dialog is pressed call custom listener.
|
||||
return MaterialDialog(activity)
|
||||
.title(R.string.custom_download)
|
||||
.customView(view = view, scrollable = true)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.custom_download)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.downloadCustomChapters(view.amount)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,8 +3,7 @@ package eu.kanade.tachiyomi.ui.manga.chapter
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
@ -24,13 +23,10 @@ class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle
|
|||
setOptionDescription(R.string.also_set_chapter_settings_for_library)
|
||||
}
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.chapter_settings)
|
||||
.customView(
|
||||
view = view,
|
||||
horizontalPadding = true
|
||||
)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.chapter_settings)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
ChapterSettingsHelper.setGlobalSettings(args.getSerializable(MANGA_KEY)!! as Manga)
|
||||
if (view.isChecked()) {
|
||||
ChapterSettingsHelper.updateAllMangasWithGlobalDefaults()
|
||||
|
@ -38,7 +34,8 @@ class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle
|
|||
|
||||
activity?.toast(activity!!.getString(R.string.chapter_settings_updated))
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.view.ViewGroup
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.loadAny
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
|
@ -177,16 +178,34 @@ class MangaInfoHeaderAdapter(
|
|||
|
||||
binding.mangaCover.longClicks()
|
||||
.onEach {
|
||||
controller.activity?.copyToClipboard(
|
||||
view.context.getString(R.string.title),
|
||||
controller.presenter.manga.title
|
||||
)
|
||||
showCoverOptionsDialog()
|
||||
}
|
||||
.launchIn(controller.viewScope)
|
||||
|
||||
setMangaInfo(manga, source)
|
||||
}
|
||||
|
||||
private fun showCoverOptionsDialog() {
|
||||
val options = listOfNotNull(
|
||||
R.string.action_share,
|
||||
R.string.action_save,
|
||||
// Can only edit cover for library manga
|
||||
if (manga.favorite) R.string.action_edit else null
|
||||
).map(controller.activity!!::getString).toTypedArray()
|
||||
|
||||
MaterialAlertDialogBuilder(controller.activity!!)
|
||||
.setTitle(R.string.manga_cover)
|
||||
.setItems(options) { _, item ->
|
||||
when (item) {
|
||||
0 -> controller.shareCover()
|
||||
1 -> controller.saveCover()
|
||||
2 -> controller.changeCover()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the view with manga information.
|
||||
*
|
||||
|
|
|
@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.manga.track
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.widget.NumberPicker
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.afollestad.materialdialogs.customview.getCustomView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.TrackChaptersDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
@ -38,23 +37,9 @@ class SetTrackChaptersDialog<T> : DialogController
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val item = item
|
||||
val pickerView = TrackChaptersDialogBinding.inflate(LayoutInflater.from(activity!!))
|
||||
val np = pickerView.chaptersPicker
|
||||
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(R.string.chapters)
|
||||
.customView(R.layout.track_chapters_dialog, dialogWrapContent = false)
|
||||
.positiveButton(android.R.string.ok) { dialog ->
|
||||
val view = dialog.getCustomView()
|
||||
// Remove focus to update selected number
|
||||
val np: NumberPicker = view.findViewById(R.id.chapters_picker)
|
||||
np.clearFocus()
|
||||
|
||||
listener.setChaptersRead(item, np.value)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
val view = dialog.getCustomView()
|
||||
val np: NumberPicker = view.findViewById(R.id.chapters_picker)
|
||||
// Set initial value
|
||||
np.value = item.track?.last_chapter_read ?: 0
|
||||
|
||||
|
@ -66,7 +51,15 @@ class SetTrackChaptersDialog<T> : DialogController
|
|||
// Don't allow to go from 0 to 9999
|
||||
np.wrapSelectorWheel = false
|
||||
|
||||
return dialog
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.chapters)
|
||||
.setView(pickerView.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
np.clearFocus()
|
||||
listener.setChaptersRead(item, np.value)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.manga.track
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.datetime.datePicker
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Calendar
|
||||
|
||||
class SetTrackReadingDatesDialog<T> : DialogController
|
||||
where T : Controller {
|
||||
|
||||
private val item: TrackItem
|
||||
|
||||
private val dateToUpdate: ReadingDate
|
||||
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, listener: Listener, dateToUpdate: ReadingDate, item: TrackItem) : super(
|
||||
bundleOf(KEY_ITEM_TRACK to item.track)
|
||||
) {
|
||||
targetController = target
|
||||
this.listener = listener
|
||||
this.item = item
|
||||
this.dateToUpdate = dateToUpdate
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : super(bundle) {
|
||||
val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track
|
||||
val service = Injekt.get<TrackManager>().getService(track.sync_id)!!
|
||||
item = TrackItem(track, service)
|
||||
dateToUpdate = ReadingDate.Start
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(
|
||||
when (dateToUpdate) {
|
||||
ReadingDate.Start -> R.string.track_started_reading_date
|
||||
ReadingDate.Finish -> R.string.track_finished_reading_date
|
||||
}
|
||||
)
|
||||
.datePicker(currentDate = getCurrentDate()) { _, date ->
|
||||
listener.setReadingDate(item, dateToUpdate, date.timeInMillis)
|
||||
}
|
||||
.neutralButton(R.string.action_remove) {
|
||||
listener.setReadingDate(item, dateToUpdate, 0L)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentDate(): Calendar {
|
||||
// Today if no date is set, otherwise the already set date
|
||||
return Calendar.getInstance().apply {
|
||||
item.track?.let {
|
||||
val date = when (dateToUpdate) {
|
||||
ReadingDate.Start -> it.started_reading_date
|
||||
ReadingDate.Finish -> it.finished_reading_date
|
||||
}
|
||||
if (date != 0L) {
|
||||
timeInMillis = date
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun setReadingDate(item: TrackItem, type: ReadingDate, date: Long)
|
||||
}
|
||||
|
||||
enum class ReadingDate {
|
||||
Start,
|
||||
Finish
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_ITEM_TRACK = "SetTrackReadingDatesDialog.item.track"
|
||||
}
|
||||
}
|
|
@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.manga.track
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.widget.NumberPicker
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.afollestad.materialdialogs.customview.getCustomView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.TrackScoreDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
@ -38,23 +37,9 @@ class SetTrackScoreDialog<T> : DialogController
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val item = item
|
||||
val pickerView = TrackScoreDialogBinding.inflate(LayoutInflater.from(activity!!))
|
||||
val np = pickerView.scorePicker
|
||||
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(R.string.score)
|
||||
.customView(R.layout.track_score_dialog, dialogWrapContent = false)
|
||||
.positiveButton(android.R.string.ok) { dialog ->
|
||||
val view = dialog.getCustomView()
|
||||
// Remove focus to update selected number
|
||||
val np: NumberPicker = view.findViewById(R.id.score_picker)
|
||||
np.clearFocus()
|
||||
|
||||
listener.setScore(item, np.value)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
val view = dialog.getCustomView()
|
||||
val np: NumberPicker = view.findViewById(R.id.score_picker)
|
||||
val scores = item.service.getScoreList().toTypedArray()
|
||||
np.maxValue = scores.size - 1
|
||||
np.displayedValues = scores
|
||||
|
@ -66,7 +51,15 @@ class SetTrackScoreDialog<T> : DialogController
|
|||
np.value = if (index != -1) index else 0
|
||||
}
|
||||
|
||||
return dialog
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.score)
|
||||
.setView(pickerView.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
np.clearFocus()
|
||||
listener.setScore(item, np.value)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,9 +3,8 @@ package eu.kanade.tachiyomi.ui.manga.track
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
|
@ -36,22 +35,20 @@ class SetTrackStatusDialog<T> : DialogController
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val item = item
|
||||
val statusList = item.service.getStatusList()
|
||||
val statusString = statusList.map { item.service.getStatus(it) }
|
||||
val selectedIndex = statusList.indexOf(item.track?.status)
|
||||
var selectedIndex = statusList.indexOf(item.track?.status)
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.status)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.listItemsSingleChoice(
|
||||
items = statusString,
|
||||
initialSelection = selectedIndex,
|
||||
waitForPositiveButton = false
|
||||
) { dialog, position, _ ->
|
||||
listener.setStatus(item, position)
|
||||
dialog.dismiss()
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.status)
|
||||
.setSingleChoiceItems(statusString.toTypedArray(), selectedIndex) { _, which ->
|
||||
selectedIndex = which
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
listener.setStatus(item, selectedIndex)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
||||
import eu.kanade.tachiyomi.util.view.applyElevationOverlay
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder>() {
|
||||
|
||||
|
@ -40,13 +39,16 @@ class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder
|
|||
}
|
||||
|
||||
interface OnClickListener {
|
||||
fun onLogoClick(position: Int)
|
||||
fun onOpenInBrowserClick(position: Int)
|
||||
fun onSetClick(position: Int)
|
||||
fun onTitleLongClick(position: Int)
|
||||
fun onStatusClick(position: Int)
|
||||
fun onChaptersClick(position: Int)
|
||||
fun onScoreClick(position: Int)
|
||||
fun onStartDateClick(position: Int)
|
||||
fun onFinishDateClick(position: Int)
|
||||
fun onStartDateEditClick(position: Int)
|
||||
fun onStartDateRemoveClick(position: Int)
|
||||
fun onFinishDateEditClick(position: Int)
|
||||
fun onFinishDateRemoveClick(position: Int)
|
||||
fun onRemoveItemClick(position: Int)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.TrackItemBinding
|
||||
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
|
||||
|
@ -17,10 +18,9 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
preferences.dateFormat()
|
||||
}
|
||||
|
||||
init {
|
||||
val listener = adapter.rowClickListener
|
||||
private val listener = adapter.rowClickListener
|
||||
|
||||
binding.logoContainer.setOnClickListener { listener.onLogoClick(bindingAdapterPosition) }
|
||||
init {
|
||||
binding.trackSet.setOnClickListener { listener.onSetClick(bindingAdapterPosition) }
|
||||
binding.trackTitle.setOnClickListener { listener.onSetClick(bindingAdapterPosition) }
|
||||
binding.trackTitle.setOnLongClickListener {
|
||||
|
@ -30,8 +30,6 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
binding.trackStatus.setOnClickListener { listener.onStatusClick(bindingAdapterPosition) }
|
||||
binding.trackChapters.setOnClickListener { listener.onChaptersClick(bindingAdapterPosition) }
|
||||
binding.trackScore.setOnClickListener { listener.onScoreClick(bindingAdapterPosition) }
|
||||
binding.trackStartDate.setOnClickListener { listener.onStartDateClick(bindingAdapterPosition) }
|
||||
binding.trackFinishDate.setOnClickListener { listener.onFinishDateClick(bindingAdapterPosition) }
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
|
@ -42,6 +40,7 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
|
||||
binding.trackSet.isVisible = track == null
|
||||
binding.trackTitle.isVisible = track != null
|
||||
binding.more.isVisible = track != null
|
||||
|
||||
binding.middleRow.isVisible = track != null
|
||||
binding.bottomDivider.isVisible = track != null
|
||||
|
@ -77,20 +76,55 @@ class TrackHolder(private val binding: TrackItemBinding, adapter: TrackAdapter)
|
|||
if (track.started_reading_date != 0L) {
|
||||
binding.trackStartDate.text = dateFormat.format(track.started_reading_date)
|
||||
binding.trackStartDate.alpha = SET_STATUS_TEXT_ALPHA
|
||||
binding.trackStartDate.setOnClickListener {
|
||||
it.popupMenu(R.menu.track_item_date) {
|
||||
when (itemId) {
|
||||
R.id.action_edit -> listener.onStartDateEditClick(bindingAdapterPosition)
|
||||
R.id.action_remove -> listener.onStartDateRemoveClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.trackStartDate.text = ctx.getString(R.string.track_started_reading_date)
|
||||
binding.trackStartDate.alpha = UNSET_STATUS_TEXT_ALPHA
|
||||
binding.trackStartDate.setOnClickListener {
|
||||
listener.onStartDateEditClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
if (track.finished_reading_date != 0L) {
|
||||
binding.trackFinishDate.text = dateFormat.format(track.finished_reading_date)
|
||||
binding.trackFinishDate.alpha = SET_STATUS_TEXT_ALPHA
|
||||
binding.trackFinishDate.setOnClickListener {
|
||||
it.popupMenu(R.menu.track_item_date) {
|
||||
when (itemId) {
|
||||
R.id.action_edit -> listener.onFinishDateEditClick(bindingAdapterPosition)
|
||||
R.id.action_remove -> listener.onFinishDateRemoveClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.trackFinishDate.text = ctx.getString(R.string.track_finished_reading_date)
|
||||
binding.trackFinishDate.alpha = UNSET_STATUS_TEXT_ALPHA
|
||||
binding.trackFinishDate.setOnClickListener {
|
||||
listener.onFinishDateEditClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.bottomDivider.isVisible = supportsReadingDates
|
||||
binding.bottomRow.isVisible = supportsReadingDates
|
||||
|
||||
binding.more.setOnClickListener {
|
||||
it.popupMenu(R.menu.track_item) {
|
||||
when (itemId) {
|
||||
R.id.action_open_in_browser -> {
|
||||
listener.onOpenInBrowserClick(bindingAdapterPosition)
|
||||
}
|
||||
R.id.action_remove -> {
|
||||
listener.onRemoveItemClick(bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,14 +74,9 @@ class TrackSearchDialog : DialogController {
|
|||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
R.id.remove -> {
|
||||
trackController.presenter.unregisterTracking(service)
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
binding!!.toolbar.menu.findItem(R.id.remove).isVisible = currentTrackUrl != null
|
||||
|
||||
// Create adapter
|
||||
adapter = TrackSearchAdapter(currentTrackUrl) { which ->
|
||||
|
|
|
@ -3,9 +3,14 @@ package eu.kanade.tachiyomi.ui.manga.track
|
|||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import eu.kanade.tachiyomi.R.string
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.DateValidatorPointBackward
|
||||
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.track.UnattendedTrackService
|
||||
import eu.kanade.tachiyomi.databinding.TrackControllerBinding
|
||||
|
@ -13,6 +18,7 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.toUtcCalendar
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
|
@ -23,13 +29,13 @@ import uy.kohesive.injekt.api.get
|
|||
class TrackSheet(
|
||||
val controller: MangaController,
|
||||
val manga: Manga,
|
||||
val fragmentManager: FragmentManager,
|
||||
private val sourceManager: SourceManager = Injekt.get()
|
||||
) : BaseBottomSheetDialog(controller.activity!!),
|
||||
TrackAdapter.OnClickListener,
|
||||
SetTrackStatusDialog.Listener,
|
||||
SetTrackChaptersDialog.Listener,
|
||||
SetTrackScoreDialog.Listener,
|
||||
SetTrackReadingDatesDialog.Listener {
|
||||
SetTrackScoreDialog.Listener {
|
||||
|
||||
private lateinit var binding: TrackControllerBinding
|
||||
|
||||
|
@ -63,7 +69,7 @@ class TrackSheet(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onLogoClick(position: Int) {
|
||||
override fun onOpenInBrowserClick(position: Int) {
|
||||
val track = adapter.getItem(position)?.track ?: return
|
||||
|
||||
if (track.tracking_url.isNotBlank()) {
|
||||
|
@ -81,7 +87,7 @@ class TrackSheet(
|
|||
}
|
||||
|
||||
if (!item.service.accept(sourceManager.getOrStub(manga.source))) {
|
||||
controller.presenter.view?.applicationContext?.toast(string.source_unsupported)
|
||||
controller.presenter.view?.applicationContext?.toast(R.string.source_unsupported)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -90,9 +96,9 @@ class TrackSheet(
|
|||
item.service.match(manga)?.let { track ->
|
||||
controller.presenter.registerTracking(track, item.service)
|
||||
}
|
||||
?: withUIContext { controller.presenter.view?.applicationContext?.toast(string.error_no_match) }
|
||||
?: withUIContext { controller.presenter.view?.applicationContext?.toast(R.string.error_no_match) }
|
||||
} catch (e: Exception) {
|
||||
withUIContext { controller.presenter.view?.applicationContext?.toast(string.error_no_match) }
|
||||
withUIContext { controller.presenter.view?.applicationContext?.toast(R.string.error_no_match) }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -128,18 +134,74 @@ class TrackSheet(
|
|||
SetTrackScoreDialog(controller, this, item).showDialog(controller.router)
|
||||
}
|
||||
|
||||
override fun onStartDateClick(position: Int) {
|
||||
override fun onStartDateEditClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
|
||||
SetTrackReadingDatesDialog(controller, this, SetTrackReadingDatesDialog.ReadingDate.Start, item).showDialog(controller.router)
|
||||
val selection = item.track.started_reading_date.toUtcCalendar()?.timeInMillis
|
||||
?: MaterialDatePicker.todayInUtcMilliseconds()
|
||||
|
||||
// No time travellers allowed
|
||||
val constraints = CalendarConstraints.Builder().apply {
|
||||
val finishedMillis = item.track.finished_reading_date.toUtcCalendar()?.timeInMillis
|
||||
if (finishedMillis != null) {
|
||||
setValidator(DateValidatorPointBackward.before(finishedMillis))
|
||||
}
|
||||
}.build()
|
||||
|
||||
val picker = MaterialDatePicker.Builder.datePicker()
|
||||
.setTitleText(R.string.track_started_reading_date)
|
||||
.setSelection(selection)
|
||||
.setCalendarConstraints(constraints)
|
||||
.build()
|
||||
picker.addOnPositiveButtonClickListener {
|
||||
controller.presenter.setTrackerStartDate(item, it)
|
||||
}
|
||||
picker.show(fragmentManager, null)
|
||||
}
|
||||
|
||||
override fun onFinishDateClick(position: Int) {
|
||||
override fun onFinishDateEditClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
|
||||
SetTrackReadingDatesDialog(controller, this, SetTrackReadingDatesDialog.ReadingDate.Finish, item).showDialog(controller.router)
|
||||
val selection = item.track.finished_reading_date.toUtcCalendar()?.timeInMillis
|
||||
?: MaterialDatePicker.todayInUtcMilliseconds()
|
||||
|
||||
// No time travellers allowed
|
||||
val constraints = CalendarConstraints.Builder().apply {
|
||||
val startMillis = item.track.started_reading_date.toUtcCalendar()?.timeInMillis
|
||||
if (startMillis != null) {
|
||||
setValidator(DateValidatorPointForward.from(item.track.started_reading_date))
|
||||
}
|
||||
}.build()
|
||||
|
||||
val picker = MaterialDatePicker.Builder.datePicker()
|
||||
.setTitleText(R.string.track_finished_reading_date)
|
||||
.setSelection(selection)
|
||||
.setCalendarConstraints(constraints)
|
||||
.build()
|
||||
picker.addOnPositiveButtonClickListener {
|
||||
controller.presenter.setTrackerFinishDate(item, it)
|
||||
}
|
||||
picker.show(fragmentManager, null)
|
||||
}
|
||||
|
||||
override fun onStartDateRemoveClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
controller.presenter.setTrackerStartDate(item, 0)
|
||||
}
|
||||
|
||||
override fun onFinishDateRemoveClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
controller.presenter.setTrackerFinishDate(item, 0)
|
||||
}
|
||||
|
||||
override fun onRemoveItemClick(position: Int) {
|
||||
val item = adapter.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
controller.presenter.unregisterTracking(item.service)
|
||||
}
|
||||
|
||||
override fun setStatus(item: TrackItem, selection: Int) {
|
||||
|
@ -154,13 +216,6 @@ class TrackSheet(
|
|||
controller.presenter.setTrackerScore(item, score)
|
||||
}
|
||||
|
||||
override fun setReadingDate(item: TrackItem, type: SetTrackReadingDatesDialog.ReadingDate, date: Long) {
|
||||
when (type) {
|
||||
SetTrackReadingDatesDialog.ReadingDate.Start -> controller.presenter.setTrackerStartDate(item, date)
|
||||
SetTrackReadingDatesDialog.ReadingDate.Finish -> controller.presenter.setTrackerFinishDate(item, date)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSearchDialog(): TrackSearchDialog? {
|
||||
return controller.router.getControllerWithTag(TAG_SEARCH_CONTROLLER) as? TrackSearchDialog
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.app.Dialog
|
|||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -133,10 +133,10 @@ class AboutController : SettingsController(), NoToolbarElevationController {
|
|||
)
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(res = R.string.update_check_notification_update_available)
|
||||
.message(text = args.getString(BODY_KEY) ?: "")
|
||||
.positiveButton(R.string.update_check_confirm) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.update_check_notification_update_available)
|
||||
.setMessage(args.getString(BODY_KEY) ?: "")
|
||||
.setPositiveButton(R.string.update_check_confirm) { _, _ ->
|
||||
val appContext = applicationContext
|
||||
if (appContext != null) {
|
||||
// Start download
|
||||
|
@ -144,7 +144,8 @@ class AboutController : SettingsController(), NoToolbarElevationController {
|
|||
UpdaterService.start(appContext, url)
|
||||
}
|
||||
}
|
||||
.negativeButton(R.string.update_check_ignore)
|
||||
.setNegativeButton(R.string.update_check_ignore, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
@ -29,6 +29,7 @@ import androidx.core.graphics.ColorUtils
|
|||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
|
@ -603,6 +604,9 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
viewer?.setChapters(viewerChapters)
|
||||
binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name
|
||||
|
||||
val currentChapterPageCount = viewerChapters.currChapter.pages?.size ?: 1
|
||||
binding.readerSeekbar.isInvisible = currentChapterPageCount == 1
|
||||
|
||||
val leftChapterObject = if (viewer is R2LPagerViewer) viewerChapters.nextChapter else viewerChapters.prevChapter
|
||||
val rightChapterObject = if (viewer is R2LPagerViewer) viewerChapters.prevChapter else viewerChapters.nextChapter
|
||||
|
||||
|
|
|
@ -19,17 +19,14 @@ class ReaderNavigationOverlayView(context: Context, attributeSet: AttributeSet)
|
|||
|
||||
private var navigation: ViewerNavigation? = null
|
||||
|
||||
fun setNavigation(navigation: ViewerNavigation, showOnStart: Boolean) {
|
||||
if (!showOnStart && this.navigation == null) {
|
||||
this.navigation = navigation
|
||||
isVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
fun setNavigation(navigation: ViewerNavigation, tappingEnabled: Boolean, showOnStart: Boolean) {
|
||||
val firstLaunch = this.navigation == null
|
||||
this.navigation = navigation
|
||||
invalidate()
|
||||
|
||||
if (isVisible) return
|
||||
if (isVisible || (!showOnStart && firstLaunch) || !tappingEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
viewPropertyAnimator = animate()
|
||||
.alpha(1f)
|
||||
|
|
|
@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.reader
|
|||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.ReaderPageSheetBinding
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
|
@ -35,13 +35,12 @@ class ReaderPageSheet(
|
|||
private fun setAsCover() {
|
||||
if (page.status != Page.READY) return
|
||||
|
||||
MaterialDialog(activity)
|
||||
.message(R.string.confirm_set_image_as_cover)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setMessage(R.string.confirm_set_image_as_cover)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
activity.setAsCover(page)
|
||||
dismiss()
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
|
|
|
@ -713,7 +713,7 @@ class ReaderPresenter(
|
|||
// for a while. The view can still be garbage collected.
|
||||
async {
|
||||
runCatching {
|
||||
service.update(track)
|
||||
service.update(track, true)
|
||||
db.insertTrack(track).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||
|
||||
config.navigationModeChangedListener = {
|
||||
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart)
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, config.tappingEnabled, showOnStart)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
|
||||
config.navigationModeChangedListener = {
|
||||
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart)
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, config.tappingEnabled, showOnStart)
|
||||
}
|
||||
|
||||
frame.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||
|
|
|
@ -9,7 +9,7 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -23,9 +23,11 @@ import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
|||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.ProgressItem
|
||||
import eu.kanade.tachiyomi.ui.browse.animesource.browse.ProgressItem
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.player.PlayerActivity
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -109,6 +111,9 @@ class AnimeHistoryController :
|
|||
} else {
|
||||
adapter?.onLoadMoreComplete(animeAnimeHistory)
|
||||
}
|
||||
binding.recycler.onAnimationsFinished {
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,12 +224,13 @@ class AnimeHistoryController :
|
|||
|
||||
class ClearAnimeHistoryDialogController : DialogController() {
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.clear_history_confirmation)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.clear_history_confirmation)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? AnimeHistoryController)?.clearAnimeHistory()
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.recent.animehistory
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.data.database.models.AnimeHistory
|
||||
|
@ -33,11 +32,12 @@ class RemoveAnimeHistoryDialog<T>(bundle: Bundle? = null) : DialogController(bun
|
|||
setOptionDescription(R.string.dialog_with_checkbox_reset_anime)
|
||||
}
|
||||
|
||||
return MaterialDialog(activity)
|
||||
.title(R.string.action_remove)
|
||||
.customView(view = dialogCheckboxView, horizontalPadding = true)
|
||||
.positiveButton(R.string.action_remove) { onPositive(dialogCheckboxView.isChecked()) }
|
||||
.negativeButton(android.R.string.cancel)
|
||||
return MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.action_remove)
|
||||
.setView(dialogCheckboxView)
|
||||
.setPositiveButton(R.string.action_remove) { _, _ -> onPositive(dialogCheckboxView.isChecked()) }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun onPositive(checked: Boolean) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
|
|||
import eu.kanade.tachiyomi.ui.player.PlayerActivity
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import reactivecircus.flowbinding.recyclerview.scrollStateChanges
|
||||
|
@ -233,6 +234,9 @@ class AnimeUpdatesController :
|
|||
fun onNextRecentEpisodes(episodes: List<IFlexible<*>>) {
|
||||
destroyActionModeIfNeeded()
|
||||
adapter?.updateDataSet(episodes)
|
||||
binding.recycler.onAnimationsFinished {
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUpdateEmptyView(size: Int) {
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.recent.animeupdates
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
|
@ -18,12 +18,13 @@ class ConfirmDeleteEpisodesDialog<T>(bundle: Bundle? = null) : DialogController(
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.confirm_delete_episodes)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.confirm_delete_episodes)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.deleteEpisodes(episodesToDelete)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -9,7 +9,7 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -23,9 +23,11 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
|||
import eu.kanade.tachiyomi.ui.base.controller.RootController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.ProgressItem
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -110,6 +112,9 @@ class HistoryController :
|
|||
} else {
|
||||
adapter?.onLoadMoreComplete(mangaHistory)
|
||||
}
|
||||
binding.recycler.onAnimationsFinished {
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -221,12 +226,13 @@ class HistoryController :
|
|||
|
||||
class ClearHistoryDialogController : DialogController() {
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.clear_history_confirmation)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.clear_history_confirmation)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? HistoryController)?.clearHistory()
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,8 @@ package eu.kanade.tachiyomi.ui.recent.history
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
|
@ -33,11 +32,12 @@ class RemoveHistoryDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
|||
setOptionDescription(R.string.dialog_with_checkbox_reset)
|
||||
}
|
||||
|
||||
return MaterialDialog(activity)
|
||||
.title(R.string.action_remove)
|
||||
.customView(view = dialogCheckboxView, horizontalPadding = true)
|
||||
.positiveButton(R.string.action_remove) { onPositive(dialogCheckboxView.isChecked()) }
|
||||
.negativeButton(android.R.string.cancel)
|
||||
return MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.action_remove)
|
||||
.setView(dialogCheckboxView)
|
||||
.setPositiveButton(R.string.action_remove) { _, _ -> onPositive(dialogCheckboxView.isChecked()) }
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun onPositive(checked: Boolean) {
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.recent.updates
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
|
@ -18,12 +18,13 @@ class ConfirmDeleteChaptersDialog<T>(bundle: Bundle? = null) : DialogController(
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.confirm_delete_chapters)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.confirm_delete_chapters)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? Listener)?.deleteChapters(chaptersToDelete)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChaptersAdapter
|
|||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.onAnimationsFinished
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import reactivecircus.flowbinding.recyclerview.scrollStateChanges
|
||||
|
@ -224,6 +225,9 @@ class UpdatesController :
|
|||
fun onNextRecentChapters(chapters: List<IFlexible<*>>) {
|
||||
destroyActionModeIfNeeded()
|
||||
adapter?.updateDataSet(chapters)
|
||||
binding.recycler.onAnimationsFinished {
|
||||
(activity as? MainActivity)?.ready = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUpdateEmptyView(size: Int) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.os.Bundle
|
|||
import android.provider.Settings
|
||||
import androidx.core.net.toUri
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.animelib.AnimelibUpdateService
|
||||
|
@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
|
@ -90,6 +91,16 @@ class SettingsAdvancedController : SettingsController() {
|
|||
}
|
||||
}
|
||||
|
||||
preference {
|
||||
key = "pref_dont_kill_my_app"
|
||||
title = "Don't kill my app!"
|
||||
summaryRes = R.string.about_dont_kill_my_app
|
||||
|
||||
onClick {
|
||||
openInBrowser("https://dontkillmyapp.com/")
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
titleRes = R.string.label_data
|
||||
|
||||
|
@ -191,12 +202,13 @@ class SettingsAdvancedController : SettingsController() {
|
|||
|
||||
class ClearDatabaseDialogController : DialogController() {
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.message(R.string.clear_database_confirmation)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setMessage(R.string.clear_database_confirmation)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
(targetController as? SettingsAdvancedController)?.clearDatabase()
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst
|
||||
|
@ -246,29 +246,34 @@ class SettingsBackupController : SettingsController() {
|
|||
R.string.history
|
||||
)
|
||||
.map { activity.getString(it) }
|
||||
val selected = options.map { true }.toBooleanArray()
|
||||
|
||||
return MaterialDialog(activity)
|
||||
.title(R.string.pref_create_backup)
|
||||
.message(R.string.backup_choice)
|
||||
.listItemsMultiChoice(
|
||||
items = options,
|
||||
disabledIndices = intArrayOf(0),
|
||||
initialSelection = intArrayOf(0, 1, 2, 3, 4)
|
||||
) { _, positions, _ ->
|
||||
return MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.backup_choice)
|
||||
.setMultiChoiceItems(options.toTypedArray(), selected) { dialog, which, checked ->
|
||||
if (which == 0) {
|
||||
(dialog as AlertDialog).listView.setItemChecked(which, true)
|
||||
} else {
|
||||
selected[which] = checked
|
||||
}
|
||||
}
|
||||
.setPositiveButton(R.string.action_create) { _, _ ->
|
||||
var flags = 0
|
||||
for (i in 1 until positions.size) {
|
||||
when (positions[i]) {
|
||||
1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY
|
||||
2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER
|
||||
3 -> flags = flags or BackupCreateService.BACKUP_TRACK
|
||||
4 -> flags = flags or BackupCreateService.BACKUP_HISTORY
|
||||
selected.forEachIndexed { i, checked ->
|
||||
if (checked) {
|
||||
when (i) {
|
||||
1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY
|
||||
2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER
|
||||
3 -> flags = flags or BackupCreateService.BACKUP_TRACK
|
||||
4 -> flags = flags or BackupCreateService.BACKUP_HISTORY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(targetController as? SettingsBackupController)?.createBackup(flags)
|
||||
}
|
||||
.positiveButton(R.string.action_create)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,17 +311,19 @@ class SettingsBackupController : SettingsController() {
|
|||
message += "\n\n${activity.getString(R.string.backup_restore_missing_trackers)}\n${results.missingTrackers.joinToString("\n") { "- $it" }}"
|
||||
}
|
||||
|
||||
MaterialDialog(activity)
|
||||
.title(R.string.pref_restore_backup)
|
||||
.message(text = message)
|
||||
.positiveButton(R.string.action_restore) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.pref_restore_backup)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.action_restore) { _, _ ->
|
||||
BackupRestoreService.start(activity, uri, type)
|
||||
}
|
||||
.create()
|
||||
} catch (e: Exception) {
|
||||
MaterialDialog(activity)
|
||||
.title(R.string.invalid_backup_file)
|
||||
.message(text = e.message)
|
||||
.positiveButton(android.R.string.cancel)
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.invalid_backup_file)
|
||||
.setMessage(e.message)
|
||||
.setPositiveButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.net.toUri
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
|
@ -21,8 +20,8 @@ import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
|||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.preference.*
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateCheckBox
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.listItemsQuadStateMultiChoice
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.setQuadStateMultiChoiceItems
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
@ -220,20 +219,22 @@ class SettingsDownloadController : SettingsController() {
|
|||
val activity = activity!!
|
||||
val currentDir = preferences.downloadsDirectory().get()
|
||||
val externalDirs = (getExternalDirs() + File(activity.getString(R.string.custom_dir))).map(File::toString)
|
||||
val selectedIndex = externalDirs.indexOfFirst { it in currentDir }
|
||||
var selectedIndex = externalDirs.indexOfFirst { it in currentDir }
|
||||
|
||||
return MaterialDialog(activity)
|
||||
.listItemsSingleChoice(
|
||||
items = externalDirs,
|
||||
initialSelection = selectedIndex
|
||||
) { _, position, text ->
|
||||
return MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.pref_download_directory)
|
||||
.setSingleChoiceItems(externalDirs.toTypedArray(), selectedIndex) { _, which ->
|
||||
selectedIndex = which
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val target = targetController as? SettingsDownloadController
|
||||
if (position == externalDirs.lastIndex) {
|
||||
if (selectedIndex == externalDirs.lastIndex) {
|
||||
target?.customDirectorySelected()
|
||||
} else {
|
||||
target?.predefinedDirectorySelected(text.toString())
|
||||
target?.predefinedDirectorySelected(externalDirs[selectedIndex])
|
||||
}
|
||||
}
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun getExternalDirs(): List<File> {
|
||||
|
@ -256,30 +257,33 @@ class SettingsDownloadController : SettingsController() {
|
|||
val categories = listOf(Category.createDefault()) + dbCategories
|
||||
|
||||
val items = categories.map { it.name }
|
||||
val preselected = categories
|
||||
var selected = categories
|
||||
.map {
|
||||
when (it.id.toString()) {
|
||||
in preferences.downloadNewCategories().get() -> QuadStateCheckBox.State.CHECKED.ordinal
|
||||
in preferences.downloadNewCategoriesExclude().get() -> QuadStateCheckBox.State.INVERSED.ordinal
|
||||
else -> QuadStateCheckBox.State.UNCHECKED.ordinal
|
||||
in preferences.downloadNewCategories().get() -> QuadStateTextView.State.CHECKED.ordinal
|
||||
in preferences.downloadNewCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal
|
||||
else -> QuadStateTextView.State.UNCHECKED.ordinal
|
||||
}
|
||||
}
|
||||
.toIntArray()
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.categories)
|
||||
.message(R.string.pref_download_new_categories_details)
|
||||
.listItemsQuadStateMultiChoice(
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.categories)
|
||||
.setMessage(R.string.pref_download_new_categories_details)
|
||||
.setQuadStateMultiChoiceItems(
|
||||
items = items,
|
||||
initialSelected = preselected
|
||||
initialSelected = selected
|
||||
) { selections ->
|
||||
val included = selections
|
||||
.mapIndexed { index, value -> if (value == QuadStateCheckBox.State.CHECKED.ordinal) index else null }
|
||||
selected = selections
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val included = selected
|
||||
.mapIndexed { index, value -> if (value == QuadStateTextView.State.CHECKED.ordinal) index else null }
|
||||
.filterNotNull()
|
||||
.map { categories[it].id.toString() }
|
||||
.toSet()
|
||||
val excluded = selections
|
||||
.mapIndexed { index, value -> if (value == QuadStateCheckBox.State.INVERSED.ordinal) index else null }
|
||||
val excluded = selected
|
||||
.mapIndexed { index, value -> if (value == QuadStateTextView.State.INVERSED.ordinal) index else null }
|
||||
.filterNotNull()
|
||||
.map { categories[it].id.toString() }
|
||||
.toSet()
|
||||
|
@ -287,8 +291,8 @@ class SettingsDownloadController : SettingsController() {
|
|||
preferences.downloadNewCategories().set(included)
|
||||
preferences.downloadNewCategoriesExclude().set(excluded)
|
||||
}
|
||||
.positiveButton(android.R.string.ok)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,11 @@ package eu.kanade.tachiyomi.ui.setting
|
|||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.animelib.AnimelibUpdateJob
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
|
@ -18,6 +17,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||
import eu.kanade.tachiyomi.data.preference.UNMETERED_NETWORK
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.PrefLibraryColumnsBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||
|
@ -33,9 +33,8 @@ import eu.kanade.tachiyomi.util.preference.summaryRes
|
|||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.isTablet
|
||||
import eu.kanade.tachiyomi.widget.MinMaxNumberPicker
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateCheckBox
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.listItemsQuadStateMultiChoice
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView
|
||||
import eu.kanade.tachiyomi.widget.materialdialogs.setQuadStateMultiChoiceItems
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -302,21 +301,21 @@ class SettingsLibraryController : SettingsController() {
|
|||
private var landscape = preferences.landscapeColumns().get()
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(R.string.pref_library_columns)
|
||||
.customView(R.layout.pref_library_columns, horizontalPadding = true)
|
||||
.positiveButton(android.R.string.ok) {
|
||||
val binding = PrefLibraryColumnsBinding.inflate(LayoutInflater.from(activity!!))
|
||||
onViewCreated(binding)
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.pref_library_columns)
|
||||
.setView(binding.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
preferences.portraitColumns().set(portrait)
|
||||
preferences.landscapeColumns().set(landscape)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
onViewCreated(dialog.view)
|
||||
return dialog
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
fun onViewCreated(view: View) {
|
||||
with(view.findViewById(R.id.portrait_columns) as MinMaxNumberPicker) {
|
||||
fun onViewCreated(binding: PrefLibraryColumnsBinding) {
|
||||
with(binding.portraitColumns) {
|
||||
displayedValues = arrayOf(context.getString(R.string.default_columns)) +
|
||||
IntRange(1, 10).map(Int::toString)
|
||||
value = portrait
|
||||
|
@ -325,7 +324,7 @@ class SettingsLibraryController : SettingsController() {
|
|||
portrait = newValue
|
||||
}
|
||||
}
|
||||
with(view.findViewById(R.id.landscape_columns) as MinMaxNumberPicker) {
|
||||
with(binding.landscapeColumns) {
|
||||
displayedValues = arrayOf(context.getString(R.string.default_columns)) +
|
||||
IntRange(1, 10).map(Int::toString)
|
||||
value = landscape
|
||||
|
@ -347,30 +346,30 @@ class SettingsLibraryController : SettingsController() {
|
|||
val categories = listOf(Category.createDefault()) + dbCategories
|
||||
|
||||
val items = categories.map { it.name }
|
||||
val preselected = categories
|
||||
var selected = categories
|
||||
.map {
|
||||
when (it.id.toString()) {
|
||||
in preferences.libraryUpdateCategories().get() -> QuadStateCheckBox.State.CHECKED.ordinal
|
||||
in preferences.libraryUpdateCategoriesExclude().get() -> QuadStateCheckBox.State.INVERSED.ordinal
|
||||
else -> QuadStateCheckBox.State.UNCHECKED.ordinal
|
||||
in preferences.libraryUpdateCategories().get() -> QuadStateTextView.State.CHECKED.ordinal
|
||||
in preferences.libraryUpdateCategoriesExclude().get() -> QuadStateTextView.State.INVERSED.ordinal
|
||||
else -> QuadStateTextView.State.UNCHECKED.ordinal
|
||||
}
|
||||
}
|
||||
.toIntArray()
|
||||
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.categories)
|
||||
.message(R.string.pref_library_update_categories_details)
|
||||
.listItemsQuadStateMultiChoice(
|
||||
items = items,
|
||||
initialSelected = preselected
|
||||
) { selections ->
|
||||
val included = selections
|
||||
.mapIndexed { index, value -> if (value == QuadStateCheckBox.State.CHECKED.ordinal) index else null }
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.categories)
|
||||
.setMessage(R.string.pref_library_update_categories_details)
|
||||
.setQuadStateMultiChoiceItems(items = items, initialSelected = selected) { selections ->
|
||||
selected = selections
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val included = selected
|
||||
.mapIndexed { index, value -> if (value == QuadStateTextView.State.CHECKED.ordinal) index else null }
|
||||
.filterNotNull()
|
||||
.map { categories[it].id.toString() }
|
||||
.toSet()
|
||||
val excluded = selections
|
||||
.mapIndexed { index, value -> if (value == QuadStateCheckBox.State.INVERSED.ordinal) index else null }
|
||||
val excluded = selected
|
||||
.mapIndexed { index, value -> if (value == QuadStateTextView.State.INVERSED.ordinal) index else null }
|
||||
.filterNotNull()
|
||||
.map { categories[it].id.toString() }
|
||||
.toSet()
|
||||
|
@ -378,8 +377,8 @@ class SettingsLibraryController : SettingsController() {
|
|||
preferences.libraryUpdateCategories().set(included)
|
||||
preferences.libraryUpdateCategoriesExclude().set(excluded)
|
||||
}
|
||||
.positiveButton(android.R.string.ok)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.setting.track
|
|||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
|
@ -20,14 +20,15 @@ class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
|||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val serviceName = activity!!.getString(service.nameRes())
|
||||
return MaterialDialog(activity!!)
|
||||
.title(text = activity!!.getString(R.string.logout_title, serviceName))
|
||||
.positiveButton(R.string.logout) {
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(activity!!.getString(R.string.logout_title, serviceName))
|
||||
.setPositiveButton(R.string.logout) { _, _ ->
|
||||
service.logout()
|
||||
(targetController as? Listener)?.trackLogoutDialogClosed(service)
|
||||
activity?.toast(R.string.logout_success)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.util.lang
|
|||
import java.text.DateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.TimeZone
|
||||
|
||||
fun Date.toDateTimestampString(dateFormatter: DateFormat): String {
|
||||
val date = dateFormatter.format(this)
|
||||
|
@ -43,3 +44,28 @@ fun Long.toCalendar(): Calendar? {
|
|||
cal.timeInMillis = this
|
||||
return cal
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert epoch long to Calendar instance in UTC
|
||||
*
|
||||
* @return UTC Calendar instance at supplied epoch time. Null if epoch was 0.
|
||||
*/
|
||||
fun Long.toUtcCalendar(): Calendar? {
|
||||
if (this == 0L) {
|
||||
return null
|
||||
}
|
||||
val rawCalendar = Calendar.getInstance().apply {
|
||||
timeInMillis = this@toUtcCalendar
|
||||
}
|
||||
return Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply {
|
||||
clear()
|
||||
set(
|
||||
rawCalendar.get(Calendar.YEAR),
|
||||
rawCalendar.get(Calendar.MONTH),
|
||||
rawCalendar.get(Calendar.DAY_OF_MONTH),
|
||||
rawCalendar.get(Calendar.HOUR_OF_DAY),
|
||||
rawCalendar.get(Calendar.MINUTE),
|
||||
rawCalendar.get(Calendar.SECOND)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,3 +197,20 @@ inline fun TextView.setMaxLinesAndEllipsize(_ellipsize: TextUtils.TruncateAt = T
|
|||
maxLines = (measuredHeight - paddingTop - paddingBottom) / lineHeight
|
||||
ellipsize = _ellipsize
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback will be run immediately when no animation running
|
||||
*/
|
||||
fun RecyclerView.onAnimationsFinished(callback: (RecyclerView) -> Unit) = post(
|
||||
object : Runnable {
|
||||
override fun run() {
|
||||
if (isAnimating) {
|
||||
itemAnimator?.isRunning {
|
||||
post(this)
|
||||
}
|
||||
} else {
|
||||
callback(this@onAnimationsFinished)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.databinding.DialogStubQuadstatemultichoiceBinding
|
||||
import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding
|
||||
|
||||
fun MaterialAlertDialogBuilder.setTextInput(
|
||||
hint: String? = null,
|
||||
prefill: String? = null,
|
||||
onTextChanged: (String) -> Unit
|
||||
): MaterialAlertDialogBuilder {
|
||||
val binding = DialogStubTextinputBinding.inflate(LayoutInflater.from(context))
|
||||
binding.textField.hint = hint
|
||||
binding.textField.editText?.apply {
|
||||
setText(prefill, TextView.BufferType.EDITABLE)
|
||||
doAfterTextChanged {
|
||||
onTextChanged(it?.toString() ?: "")
|
||||
}
|
||||
post {
|
||||
requestFocusFromTouch()
|
||||
context.getSystemService<InputMethodManager>()?.showSoftInput(this, 0)
|
||||
}
|
||||
}
|
||||
return setView(binding.root)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a list of items with checkboxes that supports 4 states.
|
||||
*
|
||||
* @see eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView
|
||||
*/
|
||||
fun MaterialAlertDialogBuilder.setQuadStateMultiChoiceItems(
|
||||
items: List<CharSequence>,
|
||||
initialSelected: IntArray,
|
||||
disabledIndices: IntArray? = null,
|
||||
selection: QuadStateMultiChoiceListener
|
||||
): MaterialAlertDialogBuilder {
|
||||
val binding = DialogStubQuadstatemultichoiceBinding.inflate(LayoutInflater.from(context))
|
||||
binding.list.layoutManager = LinearLayoutManager(context)
|
||||
binding.list.adapter = QuadStateMultiChoiceDialogAdapter(
|
||||
items = items,
|
||||
disabledItems = disabledIndices,
|
||||
initialSelected = initialSelected,
|
||||
listener = selection
|
||||
)
|
||||
setView(binding.root)
|
||||
return this
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.list.customListAdapter
|
||||
|
||||
/**
|
||||
* A variant of listItemsMultiChoice that allows for checkboxes that supports 4 states instead.
|
||||
*/
|
||||
@CheckResult
|
||||
fun MaterialDialog.listItemsQuadStateMultiChoice(
|
||||
items: List<CharSequence>,
|
||||
disabledIndices: IntArray? = null,
|
||||
initialSelected: IntArray = IntArray(items.size),
|
||||
selection: QuadStateMultiChoiceListener
|
||||
): MaterialDialog {
|
||||
return customListAdapter(
|
||||
QuadStateMultiChoiceDialogAdapter(
|
||||
dialog = this,
|
||||
items = items,
|
||||
disabledItems = disabledIndices,
|
||||
initialSelected = initialSelected,
|
||||
selection = selection
|
||||
)
|
||||
)
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
||||
|
||||
class QuadStateCheckBox @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
AppCompatImageView(context, attrs) {
|
||||
|
||||
var state: State = State.UNCHECKED
|
||||
set(value) {
|
||||
field = value
|
||||
updateDrawable()
|
||||
}
|
||||
|
||||
private fun updateDrawable() {
|
||||
when (state) {
|
||||
State.UNCHECKED -> setVectorCompat(R.drawable.ic_check_box_outline_blank_24dp, R.attr.colorControlNormal)
|
||||
State.INDETERMINATE -> setVectorCompat(R.drawable.ic_indeterminate_check_box_24dp, R.attr.colorAccent)
|
||||
State.CHECKED -> setVectorCompat(R.drawable.ic_check_box_24dp, R.attr.colorAccent)
|
||||
State.INVERSED -> setVectorCompat(R.drawable.ic_check_box_x_24dp, R.attr.colorAccent)
|
||||
}
|
||||
}
|
||||
|
||||
enum class State {
|
||||
UNCHECKED,
|
||||
INDETERMINATE,
|
||||
CHECKED,
|
||||
INVERSED,
|
||||
;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,9 @@
|
|||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import android.view.View
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.internal.list.DialogAdapter
|
||||
import com.afollestad.materialdialogs.list.getItemSelector
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.inflate
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.maybeSetTextColor
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DialogQuadstatemultichoiceItemBinding
|
||||
|
||||
private object CheckPayload
|
||||
private object InverseCheckPayload
|
||||
|
@ -17,15 +12,13 @@ private object UncheckPayload
|
|||
typealias QuadStateMultiChoiceListener = (indices: IntArray) -> Unit
|
||||
|
||||
internal class QuadStateMultiChoiceDialogAdapter(
|
||||
private var dialog: MaterialDialog,
|
||||
internal var items: List<CharSequence>,
|
||||
disabledItems: IntArray?,
|
||||
initialSelected: IntArray,
|
||||
internal var selection: QuadStateMultiChoiceListener
|
||||
) : RecyclerView.Adapter<QuadStateMultiChoiceViewHolder>(),
|
||||
DialogAdapter<CharSequence, QuadStateMultiChoiceListener> {
|
||||
internal var listener: QuadStateMultiChoiceListener
|
||||
) : RecyclerView.Adapter<QuadStateMultiChoiceViewHolder>() {
|
||||
|
||||
private val states = QuadStateCheckBox.State.values()
|
||||
private val states = QuadStateTextView.State.values()
|
||||
|
||||
private var currentSelection: IntArray = initialSelected
|
||||
set(value) {
|
||||
|
@ -34,15 +27,15 @@ internal class QuadStateMultiChoiceDialogAdapter(
|
|||
previousSelection.forEachIndexed { index, previous ->
|
||||
val current = value[index]
|
||||
when {
|
||||
current == QuadStateCheckBox.State.CHECKED.ordinal && previous != QuadStateCheckBox.State.CHECKED.ordinal -> {
|
||||
current == QuadStateTextView.State.CHECKED.ordinal && previous != QuadStateTextView.State.CHECKED.ordinal -> {
|
||||
// This value was selected
|
||||
notifyItemChanged(index, CheckPayload)
|
||||
}
|
||||
current == QuadStateCheckBox.State.INVERSED.ordinal && previous != QuadStateCheckBox.State.INVERSED.ordinal -> {
|
||||
current == QuadStateTextView.State.INVERSED.ordinal && previous != QuadStateTextView.State.INVERSED.ordinal -> {
|
||||
// This value was inverse selected
|
||||
notifyItemChanged(index, InverseCheckPayload)
|
||||
}
|
||||
current == QuadStateCheckBox.State.UNCHECKED.ordinal && previous != QuadStateCheckBox.State.UNCHECKED.ordinal -> {
|
||||
current == QuadStateTextView.State.UNCHECKED.ordinal && previous != QuadStateTextView.State.UNCHECKED.ordinal -> {
|
||||
// This value was unselected
|
||||
notifyItemChanged(index, UncheckPayload)
|
||||
}
|
||||
|
@ -54,26 +47,24 @@ internal class QuadStateMultiChoiceDialogAdapter(
|
|||
internal fun itemClicked(index: Int) {
|
||||
val newSelection = this.currentSelection.toMutableList()
|
||||
newSelection[index] = when (currentSelection[index]) {
|
||||
QuadStateCheckBox.State.CHECKED.ordinal -> QuadStateCheckBox.State.INVERSED.ordinal
|
||||
QuadStateCheckBox.State.INVERSED.ordinal -> QuadStateCheckBox.State.UNCHECKED.ordinal
|
||||
QuadStateTextView.State.CHECKED.ordinal -> QuadStateTextView.State.INVERSED.ordinal
|
||||
QuadStateTextView.State.INVERSED.ordinal -> QuadStateTextView.State.UNCHECKED.ordinal
|
||||
// INDETERMINATE or UNCHECKED
|
||||
else -> QuadStateCheckBox.State.CHECKED.ordinal
|
||||
else -> QuadStateTextView.State.CHECKED.ordinal
|
||||
}
|
||||
this.currentSelection = newSelection.toIntArray()
|
||||
listener(currentSelection)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): QuadStateMultiChoiceViewHolder {
|
||||
val listItemView: View = parent.inflate(dialog.windowContext, R.layout.md_listitem_quadstatemultichoice)
|
||||
val viewHolder = QuadStateMultiChoiceViewHolder(
|
||||
itemView = listItemView,
|
||||
return QuadStateMultiChoiceViewHolder(
|
||||
itemBinding = DialogQuadstatemultichoiceItemBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
adapter = this
|
||||
)
|
||||
viewHolder.titleView.maybeSetTextColor(dialog.windowContext, R.attr.md_color_content)
|
||||
|
||||
return viewHolder
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
@ -83,14 +74,8 @@ internal class QuadStateMultiChoiceDialogAdapter(
|
|||
position: Int
|
||||
) {
|
||||
holder.isEnabled = !disabledIndices.contains(position)
|
||||
|
||||
holder.controlView.state = states[currentSelection[position]]
|
||||
holder.titleView.text = items[position]
|
||||
holder.itemView.background = dialog.getItemSelector()
|
||||
|
||||
if (dialog.bodyFont != null) {
|
||||
holder.titleView.typeface = dialog.bodyFont
|
||||
}
|
||||
holder.controlView.text = items[position]
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(
|
||||
|
@ -100,88 +85,18 @@ internal class QuadStateMultiChoiceDialogAdapter(
|
|||
) {
|
||||
when (payloads.firstOrNull()) {
|
||||
CheckPayload -> {
|
||||
holder.controlView.state = QuadStateCheckBox.State.CHECKED
|
||||
holder.controlView.state = QuadStateTextView.State.CHECKED
|
||||
return
|
||||
}
|
||||
InverseCheckPayload -> {
|
||||
holder.controlView.state = QuadStateCheckBox.State.INVERSED
|
||||
holder.controlView.state = QuadStateTextView.State.INVERSED
|
||||
return
|
||||
}
|
||||
UncheckPayload -> {
|
||||
holder.controlView.state = QuadStateCheckBox.State.UNCHECKED
|
||||
holder.controlView.state = QuadStateTextView.State.UNCHECKED
|
||||
return
|
||||
}
|
||||
}
|
||||
super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
|
||||
override fun positiveButtonClicked() {
|
||||
selection.invoke(currentSelection)
|
||||
}
|
||||
|
||||
override fun replaceItems(
|
||||
items: List<CharSequence>,
|
||||
listener: QuadStateMultiChoiceListener?
|
||||
) {
|
||||
this.items = items
|
||||
if (listener != null) {
|
||||
this.selection = listener
|
||||
}
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun disableItems(indices: IntArray) {
|
||||
this.disabledIndices = indices
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun checkItems(indices: IntArray) {
|
||||
val newSelection = this.currentSelection.toMutableList()
|
||||
for (index in indices) {
|
||||
newSelection[index] = QuadStateCheckBox.State.CHECKED.ordinal
|
||||
}
|
||||
this.currentSelection = newSelection.toIntArray()
|
||||
}
|
||||
|
||||
override fun uncheckItems(indices: IntArray) {
|
||||
val newSelection = this.currentSelection.toMutableList()
|
||||
for (index in indices) {
|
||||
newSelection[index] = QuadStateCheckBox.State.UNCHECKED.ordinal
|
||||
}
|
||||
this.currentSelection = newSelection.toIntArray()
|
||||
}
|
||||
|
||||
override fun toggleItems(indices: IntArray) {
|
||||
val newSelection = this.currentSelection.toMutableList()
|
||||
for (index in indices) {
|
||||
if (this.disabledIndices.contains(index)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (this.currentSelection[index] != QuadStateCheckBox.State.CHECKED.ordinal) {
|
||||
newSelection[index] = QuadStateCheckBox.State.CHECKED.ordinal
|
||||
} else {
|
||||
newSelection[index] = QuadStateCheckBox.State.UNCHECKED.ordinal
|
||||
}
|
||||
}
|
||||
this.currentSelection = newSelection.toIntArray()
|
||||
}
|
||||
|
||||
override fun checkAllItems() {
|
||||
this.currentSelection = IntArray(itemCount) { QuadStateCheckBox.State.CHECKED.ordinal }
|
||||
}
|
||||
|
||||
override fun uncheckAllItems() {
|
||||
this.currentSelection = IntArray(itemCount) { QuadStateCheckBox.State.UNCHECKED.ordinal }
|
||||
}
|
||||
|
||||
override fun toggleAllChecked() {
|
||||
if (this.currentSelection.any { it != QuadStateCheckBox.State.CHECKED.ordinal }) {
|
||||
checkAllItems()
|
||||
} else {
|
||||
uncheckAllItems()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isItemChecked(index: Int) = this.currentSelection[index] == QuadStateCheckBox.State.CHECKED.ordinal
|
||||
}
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DialogQuadstatemultichoiceItemBinding
|
||||
|
||||
internal class QuadStateMultiChoiceViewHolder(
|
||||
itemView: View,
|
||||
itemBinding: DialogQuadstatemultichoiceItemBinding,
|
||||
private val adapter: QuadStateMultiChoiceDialogAdapter
|
||||
) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
) : RecyclerView.ViewHolder(itemBinding.root), View.OnClickListener {
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
val controlView: QuadStateCheckBox = itemView.findViewById(R.id.md_quad_state_control)
|
||||
val titleView: TextView = itemView.findViewById(R.id.md_quad_state_title)
|
||||
val controlView = itemBinding.quadStateControl
|
||||
|
||||
var isEnabled: Boolean
|
||||
get() = itemView.isEnabled
|
||||
set(value) {
|
||||
itemView.isEnabled = value
|
||||
controlView.isEnabled = value
|
||||
titleView.isEnabled = value
|
||||
}
|
||||
|
||||
override fun onClick(view: View) = adapter.itemClicked(bindingAdapterPosition)
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package eu.kanade.tachiyomi.widget.materialdialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.mikepenz.aboutlibraries.util.getThemeColor
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
class QuadStateTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
AppCompatTextView(context, attrs) {
|
||||
|
||||
var state: State = State.UNCHECKED
|
||||
set(value) {
|
||||
field = value
|
||||
updateDrawable()
|
||||
}
|
||||
|
||||
private fun updateDrawable() {
|
||||
val drawableStartId = when (state) {
|
||||
State.UNCHECKED -> R.drawable.ic_check_box_outline_blank_24dp
|
||||
State.INDETERMINATE -> R.drawable.ic_indeterminate_check_box_24dp
|
||||
State.CHECKED -> R.drawable.ic_check_box_24dp
|
||||
State.INVERSED -> R.drawable.ic_check_box_x_24dp
|
||||
}
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStartId, 0, 0, 0)
|
||||
|
||||
val tint = if (state == State.UNCHECKED) {
|
||||
context.getThemeColor(R.attr.colorControlNormal)
|
||||
} else {
|
||||
context.getThemeColor(R.attr.colorAccent)
|
||||
}
|
||||
if (tint != 0) {
|
||||
compoundDrawableTintList = ColorStateList.valueOf(tint)
|
||||
}
|
||||
}
|
||||
|
||||
enum class State {
|
||||
UNCHECKED,
|
||||
INDETERMINATE,
|
||||
CHECKED,
|
||||
INVERSED,
|
||||
;
|
||||
}
|
||||
}
|
|
@ -5,11 +5,10 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.dd.processbutton.iml.ActionProcessButton
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.PrefAccountLoginBinding
|
||||
|
@ -28,15 +27,13 @@ abstract class LoginDialogPreference(
|
|||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
binding = PrefAccountLoginBinding.inflate(LayoutInflater.from(activity!!))
|
||||
onViewCreated(binding!!.root)
|
||||
val titleName = activity!!.getString(getTitleName())
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(text = activity!!.getString(R.string.login_title, titleName))
|
||||
.customView(view = binding!!.root)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
onViewCreated(dialog.view)
|
||||
|
||||
return dialog
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(activity!!.getString(R.string.login_title, titleName))
|
||||
.setView(binding!!.root)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
}
|
||||
|
||||
fun onViewCreated(view: View) {
|
||||
|
|
10
app/src/main/res/drawable/ic_more_vert_24.xml
Normal file
10
app/src/main/res/drawable/ic_more_vert_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
|
@ -1,12 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@color/splash" />
|
||||
|
||||
<item
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:drawable="@drawable/ic_tachi"
|
||||
android:gravity="center" />
|
||||
|
||||
</layer-list>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue