Compare commits

...

3 Commits

Author SHA1 Message Date
Jobobby04 26cfb4811f Fix a possible crash with auto-zoom 2024-11-07 22:21:39 -05:00
Jobobby04 e5a6d1b456 Fix a crash with migration list screen 2024-11-07 22:21:18 -05:00
Jobobby04 f0b621dfe5 Fix multiple issues with the E-Hentai updater 2024-11-07 22:21:02 -05:00
8 changed files with 164 additions and 15 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ android {
defaultConfig {
applicationId = "eu.kanade.tachiyomi.sy"
versionCode = 70
versionCode = 71
versionName = "1.11.0"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
@@ -30,6 +30,9 @@ object Notifications {
const val ID_LIBRARY_SIZE_WARNING = -103
const val CHANNEL_LIBRARY_ERROR = "library_errors_channel"
const val ID_LIBRARY_ERROR = -102
const val CHANNEL_LIBRARY_EHENTAI = "library_ehentai_channel"
const val ID_EHENTAI_PROGRESS = -199
const val ID_EHENTAI_ERROR = -198
/**
* Notification channel and ids used by the downloader.
@@ -166,6 +169,13 @@ object Notifications {
setGroup(GROUP_APK_UPDATES)
setName(context.stringResource(MR.strings.channel_ext_updates))
},
// SY -->
buildNotificationChannel(CHANNEL_LIBRARY_EHENTAI, IMPORTANCE_LOW) {
setName("EHentai")
setGroup(GROUP_LIBRARY)
setShowBadge(false)
},
//SY <--
),
)
}
@@ -5,8 +5,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
@@ -29,8 +27,7 @@ import tachiyomi.i18n.sy.SYMR
class MigrationListScreen(private val config: MigrationProcedureConfig) : Screen() {
@delegate:Transient
var newSelectedItem by mutableStateOf<Pair<Long, Long>?>(null)
var newSelectedItem: Pair<Long, Long>? = null
@Composable
override fun Content() {
@@ -122,21 +122,22 @@ open class ReaderPageImageView @JvmOverloads constructor(
}
private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) {
val config = config
if (config != null &&
config!!.landscapeZoom &&
config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE &&
config.landscapeZoom &&
config.minimumScaleType == SCALE_TYPE_CENTER_INSIDE &&
sWidth > sHeight &&
scale == minScale
) {
handler?.postDelayed(500) {
val point = when (config!!.zoomStartPosition) {
val point = when (config.zoomStartPosition) {
ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F)
ZoomStartPosition.RIGHT -> if (forward) PointF(sWidth.toFloat(), 0F) else PointF(0F, 0F)
ZoomStartPosition.CENTER -> center
}
val targetScale = height.toFloat() / sHeight.toFloat()
animateScaleAndCenter(targetScale, point)!!
(animateScaleAndCenter(targetScale, point) ?: return@postDelayed)
.withDuration(500)
.withEasing(EASE_IN_OUT_QUAD)
.withInterruptible(true)
@@ -0,0 +1,109 @@
package exh.eh
import android.content.Context
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.core.app.NotificationCompat
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.cancelNotification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notify
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import uy.kohesive.injekt.injectLazy
import java.math.RoundingMode
import java.text.NumberFormat
class EHentaiUpdateNotifier(private val context: Context) {
private val securityPreferences: SecurityPreferences by injectLazy()
private val percentFormatter = NumberFormat.getPercentInstance().apply {
roundingMode = RoundingMode.DOWN
maximumFractionDigits = 0
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)
}
/**
* Cached progress notification to avoid creating a lot.
*/
val progressNotificationBuilder by lazy {
context.notificationBuilder(Notifications.CHANNEL_LIBRARY_EHENTAI) {
setContentTitle(context.stringResource(MR.strings.app_name))
setSmallIcon(R.drawable.ic_refresh_24dp)
setLargeIcon(notificationBitmap)
setOngoing(true)
setOnlyAlertOnce(true)
}
}
/**
* Shows the notification containing the currently updating manga and the progress.
*
* @param manga the manga that are being updated.
* @param current the current progress.
* @param total the total progress.
*/
fun showProgressNotification(manga: Manga, current: Int, total: Int) {
progressNotificationBuilder
.setContentTitle(
context.stringResource(
MR.strings.notification_updating_progress,
percentFormatter.format(current.toFloat() / total),
),
)
if (!securityPreferences.hideNotificationContent().get()) {
val updatingText = manga.title.chop(40)
progressNotificationBuilder.setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
}
context.notify(
Notifications.ID_EHENTAI_PROGRESS,
progressNotificationBuilder
.setProgress(total, current, false)
.build(),
)
}
/**
* Shows notification containing update entries that failed with action to open full log.
*
* @param failed Number of entries that failed to update.
* @param uri Uri for error log file containing all titles that failed.
*/
fun showUpdateErrorNotification(failed: Int, uri: Uri) {
if (failed == 0) {
return
}
context.notify(
Notifications.ID_EHENTAI_ERROR,
Notifications.CHANNEL_LIBRARY_EHENTAI,
) {
setContentTitle(context.stringResource(MR.strings.notification_update_error, failed))
setContentText(context.stringResource(MR.strings.action_show_errors))
setSmallIcon(R.drawable.ic_tachi)
setContentIntent(NotificationReceiver.openErrorLogPendingActivity(context, uri))
}
}
/**
* Cancels the progress notification.
*/
fun cancelProgressNotification() {
context.cancelNotification(Notifications.ID_EHENTAI_PROGRESS)
}
}
@@ -1,11 +1,15 @@
package exh.eh
import android.content.Context
import android.content.pm.ServiceInfo
import android.os.Build
import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ForegroundInfo
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.OutOfQuotaPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkerParameters
import com.elvishew.xlog.Logger
@@ -14,8 +18,10 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toSManga
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.system.isConnectedToWifi
import eu.kanade.tachiyomi.util.system.setForegroundSafely
import eu.kanade.tachiyomi.util.system.workManager
import exh.debug.DebugToggles
import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION
@@ -48,7 +54,7 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
private val preferences: UnsortedPreferences by injectLazy()
private val sourceManager: SourceManager by injectLazy()
private val updateHelper: EHentaiUpdateHelper by injectLazy()
private val logger: Logger = xLog()
private val logger: Logger by lazy { xLog() }
private val updateManga: UpdateManga by injectLazy()
private val syncChaptersWithSource: SyncChaptersWithSource by injectLazy()
private val getChaptersByMangaId: GetChaptersByMangaId by injectLazy()
@@ -56,22 +62,38 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
private val insertFlatMetadata: InsertFlatMetadata by injectLazy()
private val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
private val updateNotifier by lazy { LibraryUpdateNotifier(context) }
private val updateNotifier by lazy { EHentaiUpdateNotifier(context) }
private val libraryUpdateNotifier by lazy { LibraryUpdateNotifier(context) }
override suspend fun doWork(): Result {
return try {
if (requiresWifiConnection(preferences) && !context.isConnectedToWifi()) {
Result.success() // retry again later
} else {
setForegroundSafely()
startUpdating()
logger.d("Update job completed!")
Result.success()
}
} catch (e: Exception) {
Result.success() // retry again later
} finally {
updateNotifier.cancelProgressNotification()
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
Notifications.ID_EHENTAI_PROGRESS,
updateNotifier.progressNotificationBuilder.build(),
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
} else {
0
},
)
}
private suspend fun startUpdating() {
logger.d("Update job started!")
val startTime = System.currentTimeMillis()
@@ -138,6 +160,11 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
}
val (new, chapters) = try {
updateNotifier.showProgressNotification(
manga,
updatedThisIteration + failuresThisIteration,
mangaMetaToUpdateThisIter.size,
)
updateEntryAndGetChapters(manga)
} catch (e: GalleryNotUpdatedException) {
if (e.network) {
@@ -193,8 +220,9 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
),
)
updateNotifier.cancelProgressNotification()
if (updatedManga.isNotEmpty()) {
updateNotifier.showUpdateNotifications(updatedManga)
libraryUpdateNotifier.showUpdateNotifications(updatedManga)
}
}
}
@@ -237,7 +265,11 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
private val logger by lazy { XLog.tag("EHUpdaterScheduler") }
fun launchBackgroundTest(context: Context) {
context.workManager.enqueue(OneTimeWorkRequestBuilder<EHentaiUpdateWorker>().build())
context.workManager.enqueue(
OneTimeWorkRequestBuilder<EHentaiUpdateWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build(),
)
}
fun scheduleBackground(context: Context, prefInterval: Int? = null, prefRestrictions: Set<String>? = null) {
@@ -445,7 +445,7 @@ class FavoritesSyncHelper(val context: Context) {
}
}
sealed class FavoritesSyncStatus() {
sealed class FavoritesSyncStatus {
abstract val message: String
data class Error(override val message: String) : FavoritesSyncStatus()
@@ -24,6 +24,6 @@ enum class MangaDexRelation(val res: StringResource, val mdString: String?) {
;
companion object {
fun fromDex(mdString: String) = values().find { it.mdString == mdString }
fun fromDex(mdString: String) = entries.find { it.mdString == mdString }
}
}