Remove loggers and reorganize settings
This commit is contained in:
@@ -1,148 +0,0 @@
|
||||
package org.koitharu.kotatsu.core.logs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.WorkerThread
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
|
||||
import org.koitharu.kotatsu.core.util.ext.subdir
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
private const val DIR = "logs"
|
||||
private const val FLUSH_DELAY = 2_000L
|
||||
private const val MAX_SIZE_BYTES = 1024 * 1024 // 1 MB
|
||||
|
||||
class FileLogger(
|
||||
context: Context,
|
||||
private val settings: AppSettings,
|
||||
name: String,
|
||||
) {
|
||||
|
||||
val file by lazy {
|
||||
val dir = context.getExternalFilesDir(DIR) ?: context.filesDir.subdir(DIR)
|
||||
File(dir, "$name.log")
|
||||
}
|
||||
val isEnabled: Boolean
|
||||
get() = settings.isLoggingEnabled
|
||||
private val dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.ROOT)
|
||||
private val buffer = ConcurrentLinkedQueue<String>()
|
||||
private val mutex = Mutex()
|
||||
private var flushJob: Job? = null
|
||||
|
||||
fun log(message: String, e: Throwable? = null) {
|
||||
if (!isEnabled) {
|
||||
return
|
||||
}
|
||||
val text = buildString {
|
||||
append(dateTimeFormatter.format(LocalDateTime.now()))
|
||||
append(": ")
|
||||
if (e != null) {
|
||||
append("E!")
|
||||
}
|
||||
append(message)
|
||||
if (e != null) {
|
||||
append(' ')
|
||||
append(e.stackTraceToString())
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
buffer.add(text)
|
||||
postFlush()
|
||||
}
|
||||
|
||||
inline fun log(messageProducer: () -> String) {
|
||||
if (isEnabled) {
|
||||
log(messageProducer())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun flush() {
|
||||
if (!isEnabled) {
|
||||
return
|
||||
}
|
||||
flushJob?.cancelAndJoin()
|
||||
flushImpl()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun flushBlocking() {
|
||||
if (!isEnabled) {
|
||||
return
|
||||
}
|
||||
runBlockingSafe { flushJob?.cancelAndJoin() }
|
||||
runBlockingSafe { flushImpl() }
|
||||
}
|
||||
|
||||
private fun postFlush() {
|
||||
if (flushJob?.isActive == true) {
|
||||
return
|
||||
}
|
||||
flushJob = processLifecycleScope.launch(Dispatchers.Default) {
|
||||
delay(FLUSH_DELAY)
|
||||
runCatchingCancellable {
|
||||
flushImpl()
|
||||
}.onFailure {
|
||||
it.printStackTraceDebug()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun flushImpl() = withContext(NonCancellable) {
|
||||
mutex.withLock {
|
||||
if (buffer.isEmpty()) {
|
||||
return@withContext
|
||||
}
|
||||
runInterruptible(Dispatchers.IO) {
|
||||
if (file.length() > MAX_SIZE_BYTES) {
|
||||
rotate()
|
||||
}
|
||||
FileOutputStream(file, true).use {
|
||||
while (true) {
|
||||
val message = buffer.poll() ?: break
|
||||
it.write(message.toByteArray())
|
||||
it.write('\n'.code)
|
||||
}
|
||||
it.flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun rotate() {
|
||||
val length = file.length()
|
||||
val bakFile = File(file.parentFile, file.name + ".bak")
|
||||
file.renameTo(bakFile)
|
||||
bakFile.inputStream().use { input ->
|
||||
input.skip(length - MAX_SIZE_BYTES / 2)
|
||||
file.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
output.flush()
|
||||
}
|
||||
}
|
||||
bakFile.delete()
|
||||
}
|
||||
|
||||
private inline fun runBlockingSafe(crossinline block: suspend () -> Unit) = try {
|
||||
runBlocking(NonCancellable) { block() }
|
||||
} catch (_: InterruptedException) {
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.koitharu.kotatsu.core.logs
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class TrackerLogger
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class SyncLogger
|
||||
@@ -1,40 +0,0 @@
|
||||
package org.koitharu.kotatsu.core.logs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.collection.arraySetOf
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ElementsIntoSet
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object LoggersModule {
|
||||
|
||||
@Provides
|
||||
@TrackerLogger
|
||||
fun provideTrackerLogger(
|
||||
@ApplicationContext context: Context,
|
||||
settings: AppSettings,
|
||||
) = FileLogger(context, settings, "tracker")
|
||||
|
||||
@Provides
|
||||
@SyncLogger
|
||||
fun provideSyncLogger(
|
||||
@ApplicationContext context: Context,
|
||||
settings: AppSettings,
|
||||
) = FileLogger(context, settings, "sync")
|
||||
|
||||
@Provides
|
||||
@ElementsIntoSet
|
||||
fun provideAllLoggers(
|
||||
@TrackerLogger trackerLogger: FileLogger,
|
||||
@SyncLogger syncLogger: FileLogger,
|
||||
): Set<@JvmSuppressWildcards FileLogger> = arraySetOf(
|
||||
trackerLogger,
|
||||
syncLogger,
|
||||
)
|
||||
}
|
||||
@@ -74,7 +74,7 @@ interface NetworkModule {
|
||||
if (settings.isSSLBypassEnabled) {
|
||||
disableCertificateVerification()
|
||||
} else {
|
||||
installExtraCertsificates(contextProvider.get())
|
||||
installExtraCertificates(contextProvider.get())
|
||||
}
|
||||
cache(cache)
|
||||
addInterceptor(GZipInterceptor())
|
||||
|
||||
@@ -35,7 +35,7 @@ fun OkHttpClient.Builder.disableCertificateVerification() = also { builder ->
|
||||
}
|
||||
}
|
||||
|
||||
fun OkHttpClient.Builder.installExtraCertsificates(context: Context) = also { builder ->
|
||||
fun OkHttpClient.Builder.installExtraCertificates(context: Context) = also { builder ->
|
||||
val certificatesBuilder = HandshakeCertificates.Builder()
|
||||
.addPlatformTrustedCertificates()
|
||||
val assets = context.assets.list("").orEmpty()
|
||||
|
||||
@@ -247,9 +247,6 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
}
|
||||
} ?: EnumSet.allOf(SearchSuggestionType::class.java)
|
||||
|
||||
val isLoggingEnabled: Boolean
|
||||
get() = prefs.getBoolean(KEY_LOGGING_ENABLED, false)
|
||||
|
||||
var isBiometricProtectionEnabled: Boolean
|
||||
get() = prefs.getBoolean(KEY_PROTECT_APP_BIOMETRIC, true)
|
||||
set(value) = prefs.edit { putBoolean(KEY_PROTECT_APP_BIOMETRIC, value) }
|
||||
@@ -673,7 +670,6 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_WEBTOON_ZOOM_OUT = "webtoon_zoom_out"
|
||||
const val KEY_PREFETCH_CONTENT = "prefetch_content"
|
||||
const val KEY_APP_LOCALE = "app_locale"
|
||||
const val KEY_LOGGING_ENABLED = "logging"
|
||||
const val KEY_SOURCES_GRID = "sources_grid"
|
||||
const val KEY_UPDATES_UNSTABLE = "updates_unstable"
|
||||
const val KEY_TIPS_CLOSED = "tips_closed"
|
||||
@@ -717,9 +713,11 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_APP_VERSION = "app_version"
|
||||
const val KEY_IGNORE_DOZE = "ignore_dose"
|
||||
const val KEY_TRACKER_DEBUG = "tracker_debug"
|
||||
const val KEY_LOGS_SHARE = "logs_share"
|
||||
const val KEY_APP_UPDATE = "app_update"
|
||||
const val KEY_APP_TRANSLATION = "about_app_translation"
|
||||
const val KEY_LINK_WEBLATE = "about_app_translation"
|
||||
const val KEY_LINK_TELEGRAM = "about_telegram"
|
||||
const val KEY_LINK_GITHUB = "about_github"
|
||||
const val KEY_LINK_MANUAL = "about_help"
|
||||
const val PROXY_TEST = "proxy_test"
|
||||
|
||||
// old keys are for migration only
|
||||
|
||||
@@ -80,11 +80,11 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
|
||||
(activity as? SettingsActivity)?.setSectionTitle(title)
|
||||
}
|
||||
|
||||
protected fun startActivitySafe(intent: Intent) {
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
Snackbar.make(listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
protected fun startActivitySafe(intent: Intent): Boolean = try {
|
||||
startActivity(intent)
|
||||
true
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
Snackbar.make(listView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT).show()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,10 @@ package org.koitharu.kotatsu.core.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.logs.FileLogger
|
||||
import org.koitharu.kotatsu.core.model.appUrl
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import java.io.File
|
||||
@@ -84,25 +82,4 @@ class ShareHelper(private val context: Context) {
|
||||
.setChooserTitle(R.string.share)
|
||||
.startChooser()
|
||||
}
|
||||
|
||||
fun shareLogs(loggers: Collection<FileLogger>) {
|
||||
val intentBuilder = ShareCompat.IntentBuilder(context)
|
||||
.setType(TYPE_TEXT)
|
||||
var hasLogs = false
|
||||
for (logger in loggers) {
|
||||
val logFile = logger.file
|
||||
if (!logFile.exists()) {
|
||||
continue
|
||||
}
|
||||
val uri = FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.files", logFile)
|
||||
intentBuilder.addStream(uri)
|
||||
hasLogs = true
|
||||
}
|
||||
if (hasLogs) {
|
||||
intentBuilder.setChooserTitle(R.string.share_logs)
|
||||
intentBuilder.startChooser()
|
||||
} else {
|
||||
Toast.makeText(context, R.string.nothing_here, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.settings.about
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.net.toUri
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.preference.Preference
|
||||
@@ -14,23 +15,16 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.github.AppVersion
|
||||
import org.koitharu.kotatsu.core.github.VersionId
|
||||
import org.koitharu.kotatsu.core.github.isStable
|
||||
import org.koitharu.kotatsu.core.logs.FileLogger
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
|
||||
import org.koitharu.kotatsu.core.util.ShareHelper
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
import org.koitharu.kotatsu.tracker.ui.debug.TrackerDebugActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
|
||||
|
||||
private val viewModel by viewModels<AboutSettingsViewModel>()
|
||||
|
||||
@Inject
|
||||
lateinit var loggers: Set<@JvmSuppressWildcards FileLogger>
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.pref_about)
|
||||
findPreference<Preference>(AppSettings.KEY_APP_VERSION)?.run {
|
||||
@@ -41,12 +35,6 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
|
||||
isEnabled = VersionId(BuildConfig.VERSION_NAME).isStable
|
||||
if (!isEnabled) isChecked = true
|
||||
}
|
||||
if (!settings.isTrackerEnabled) {
|
||||
findPreference<Preference>(AppSettings.KEY_TRACKER_DEBUG)?.run {
|
||||
isEnabled = false
|
||||
setSummary(R.string.check_for_new_chapters_disabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -64,21 +52,27 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_APP_TRANSLATION -> {
|
||||
openLink(getString(R.string.url_weblate), preference.title)
|
||||
AppSettings.KEY_LINK_WEBLATE -> {
|
||||
openLink(R.string.url_weblate, preference.title)
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_LOGS_SHARE -> {
|
||||
ShareHelper(preference.context).shareLogs(loggers)
|
||||
AppSettings.KEY_LINK_GITHUB -> {
|
||||
openLink(R.string.url_github, preference.title)
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_TRACKER_DEBUG -> {
|
||||
startActivity(Intent(preference.context, TrackerDebugActivity::class.java))
|
||||
AppSettings.KEY_LINK_MANUAL -> {
|
||||
openLink(R.string.url_user_manual, preference.title)
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_LINK_TELEGRAM -> {
|
||||
if (!openLink(R.string.url_telegram, null)) {
|
||||
openLink(R.string.url_telegram_web, preference.title)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
@@ -87,15 +81,15 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
|
||||
private fun onUpdateAvailable(version: AppVersion?) {
|
||||
if (version == null) {
|
||||
Snackbar.make(listView, R.string.no_update_available, Snackbar.LENGTH_SHORT).show()
|
||||
return
|
||||
} else {
|
||||
startActivity(Intent(requireContext(), AppUpdateActivity::class.java))
|
||||
}
|
||||
startActivity(Intent(requireContext(), AppUpdateActivity::class.java))
|
||||
}
|
||||
|
||||
private fun openLink(url: String, title: CharSequence?) {
|
||||
private fun openLink(@StringRes url: Int, title: CharSequence?): Boolean {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.data = url.toUri()
|
||||
startActivitySafe(
|
||||
intent.data = getString(url).toUri()
|
||||
return startActivitySafe(
|
||||
if (title != null) {
|
||||
Intent.createChooser(intent, title)
|
||||
} else {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.koitharu.kotatsu.parsers.util.names
|
||||
import org.koitharu.kotatsu.settings.tracker.categories.TrackerCategoriesConfigSheet
|
||||
import org.koitharu.kotatsu.settings.utils.DozeHelper
|
||||
import org.koitharu.kotatsu.settings.utils.MultiSummaryProvider
|
||||
import org.koitharu.kotatsu.tracker.ui.debug.TrackerDebugActivity
|
||||
import org.koitharu.kotatsu.tracker.work.TrackerNotificationHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -116,6 +117,11 @@ class TrackerSettingsFragment :
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_TRACKER_DEBUG -> {
|
||||
startActivity(Intent(preference.context, TrackerDebugActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package org.koitharu.kotatsu.settings.utils
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.forEach
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.databinding.PreferenceAboutLinksBinding
|
||||
|
||||
class AboutLinksPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
) : Preference(context, attrs), View.OnClickListener {
|
||||
|
||||
init {
|
||||
layoutResource = R.layout.preference_about_links
|
||||
isSelectable = false
|
||||
isPersistent = false
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
|
||||
val binding = PreferenceAboutLinksBinding.bind(holder.itemView)
|
||||
binding.root.forEach { button ->
|
||||
TooltipCompat.setTooltipText(button, button.contentDescription)
|
||||
button.setOnClickListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val urlResId = when (v.id) {
|
||||
R.id.btn_discord -> R.string.url_discord
|
||||
R.id.btn_telegram -> R.string.url_telegram
|
||||
R.id.btn_github -> R.string.url_github
|
||||
else -> return
|
||||
}
|
||||
openLink(v, v.context.getString(urlResId), v.contentDescription)
|
||||
}
|
||||
|
||||
private fun openLink(v: View, url: String, title: CharSequence?) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||
try {
|
||||
context.startActivity(
|
||||
if (title != null) {
|
||||
Intent.createChooser(intent, title)
|
||||
} else {
|
||||
intent
|
||||
},
|
||||
)
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
Snackbar.make(v, R.string.operation_not_supported, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import android.content.SyncResult
|
||||
import android.content.SyncStats
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.content.contentValuesOf
|
||||
import dagger.assisted.Assisted
|
||||
@@ -18,9 +19,9 @@ import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.TABLE_FAVOURITES
|
||||
import org.koitharu.kotatsu.core.db.TABLE_FAVOURITE_CATEGORIES
|
||||
@@ -28,10 +29,9 @@ import org.koitharu.kotatsu.core.db.TABLE_HISTORY
|
||||
import org.koitharu.kotatsu.core.db.TABLE_MANGA
|
||||
import org.koitharu.kotatsu.core.db.TABLE_MANGA_TAGS
|
||||
import org.koitharu.kotatsu.core.db.TABLE_TAGS
|
||||
import org.koitharu.kotatsu.core.logs.FileLogger
|
||||
import org.koitharu.kotatsu.core.logs.SyncLogger
|
||||
import org.koitharu.kotatsu.core.network.BaseHttpClient
|
||||
import org.koitharu.kotatsu.core.util.ext.parseJsonOrNull
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.toContentValues
|
||||
import org.koitharu.kotatsu.core.util.ext.toJson
|
||||
import org.koitharu.kotatsu.core.util.ext.toRequestBody
|
||||
@@ -50,7 +50,6 @@ class SyncHelper @AssistedInject constructor(
|
||||
@Assisted private val account: Account,
|
||||
@Assisted private val provider: ContentProviderClient,
|
||||
private val settings: SyncSettings,
|
||||
@SyncLogger private val logger: FileLogger,
|
||||
) {
|
||||
|
||||
private val authorityHistory = context.getString(R.string.sync_authority_history)
|
||||
@@ -75,7 +74,7 @@ class SyncHelper @AssistedInject constructor(
|
||||
.url("$baseUrl/resource/$TABLE_FAVOURITES")
|
||||
.post(data.toRequestBody())
|
||||
.build()
|
||||
val response = httpClient.newCall(request).execute().log().parseJsonOrNull()
|
||||
val response = httpClient.newCall(request).execute().parseJsonOrNull()
|
||||
if (response != null) {
|
||||
val categoriesResult = upsertFavouriteCategories(response.getJSONArray(TABLE_FAVOURITE_CATEGORIES))
|
||||
stats.numDeletes += categoriesResult.first().count?.toLong() ?: 0L
|
||||
@@ -97,7 +96,7 @@ class SyncHelper @AssistedInject constructor(
|
||||
.url("$baseUrl/resource/$TABLE_HISTORY")
|
||||
.post(data.toRequestBody())
|
||||
.build()
|
||||
val response = httpClient.newCall(request).execute().log().parseJsonOrNull()
|
||||
val response = httpClient.newCall(request).execute().parseJsonOrNull()
|
||||
if (response != null) {
|
||||
val result = upsertHistory(
|
||||
json = response.getJSONArray(TABLE_HISTORY),
|
||||
@@ -110,15 +109,12 @@ class SyncHelper @AssistedInject constructor(
|
||||
}
|
||||
|
||||
fun onError(e: Throwable) {
|
||||
if (logger.isEnabled) {
|
||||
logger.log("Sync error", e)
|
||||
}
|
||||
e.printStackTraceDebug()
|
||||
}
|
||||
|
||||
fun onSyncComplete(result: SyncResult) {
|
||||
if (logger.isEnabled) {
|
||||
logger.log("Sync finished: ${result.toDebugString()}")
|
||||
logger.flushBlocking()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i("Sync", "Sync finished: ${result.toDebugString()}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,12 +294,6 @@ class SyncHelper @AssistedInject constructor(
|
||||
|
||||
private fun JSONObject.removeJSONArray(name: String) = remove(name) as JSONArray
|
||||
|
||||
private fun Response.log() = apply {
|
||||
if (logger.isEnabled) {
|
||||
logger.log("$code ${request.url}")
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
|
||||
@@ -45,13 +45,12 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.browser.cloudflare.CaptchaNotifier
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.logs.FileLogger
|
||||
import org.koitharu.kotatsu.core.logs.TrackerLogger
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.TrackerDownloadStrategy
|
||||
import org.koitharu.kotatsu.core.util.ext.awaitUniqueWorkInfoByName
|
||||
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
||||
import org.koitharu.kotatsu.core.util.ext.onEachIndexed
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.trySetForeground
|
||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||
import org.koitharu.kotatsu.local.data.LocalMangaRepository
|
||||
@@ -80,7 +79,6 @@ class TrackWorker @AssistedInject constructor(
|
||||
private val getTracksUseCase: GetTracksUseCase,
|
||||
private val checkNewChaptersUseCase: CheckNewChaptersUseCase,
|
||||
private val workManager: WorkManager,
|
||||
@TrackerLogger private val logger: FileLogger,
|
||||
private val localRepositoryLazy: Lazy<LocalMangaRepository>,
|
||||
private val downloadSchedulerLazy: Lazy<DownloadWorker.Scheduler>,
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
@@ -90,17 +88,15 @@ class TrackWorker @AssistedInject constructor(
|
||||
override suspend fun doWork(): Result {
|
||||
notificationHelper.updateChannels()
|
||||
val isForeground = trySetForeground()
|
||||
logger.log("doWork(): attempt $runAttemptCount")
|
||||
return try {
|
||||
doWorkImpl(isFullRun = isForeground && TAG_ONESHOT in tags)
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
logger.log("fatal", e)
|
||||
e.printStackTraceDebug()
|
||||
Result.failure()
|
||||
} finally {
|
||||
withContext(NonCancellable) {
|
||||
logger.flush()
|
||||
notificationManager.cancel(WORKER_NOTIFICATION_ID)
|
||||
}
|
||||
}
|
||||
@@ -111,7 +107,6 @@ class TrackWorker @AssistedInject constructor(
|
||||
return Result.success()
|
||||
}
|
||||
val tracks = getTracksUseCase(if (isFullRun) Int.MAX_VALUE else BATCH_SIZE)
|
||||
logger.log("Total ${tracks.size} tracks")
|
||||
if (tracks.isEmpty()) {
|
||||
return Result.success()
|
||||
}
|
||||
@@ -154,7 +149,6 @@ class TrackWorker @AssistedInject constructor(
|
||||
when (it) {
|
||||
is MangaUpdates.Failure -> {
|
||||
val e = it.error
|
||||
logger.log("checkUpdatesAsync", e)
|
||||
if (e is CloudFlareProtectedException) {
|
||||
CaptchaNotifier(applicationContext).notify(e)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="url_github" translatable="false">https://github.com/KotatsuApp/Kotatsu</string>
|
||||
<string name="url_discord" translatable="false">https://discord.gg/NNJ5RgVBC5</string>
|
||||
<string name="url_telegram" translatable="false">https://t.me/kotatsuapp</string>
|
||||
<string name="url_telegram_web" translatable="false">https://t.me/kotatsuapp</string>
|
||||
<string name="url_telegram" translatable="false">tg://resolve?domain=kotatsuapp</string>
|
||||
<string name="url_weblate" translatable="false">https://hosted.weblate.org/engage/kotatsu</string>
|
||||
<string name="url_user_manual" translatable="false">https://kotatsu.app/manuals/guides/getting-started/</string>
|
||||
<string name="url_error_report" translatable="false">https://bugs.kotatsu.app/report</string>
|
||||
<string name="account_type_sync" translatable="false">org.kotatsu.sync</string>
|
||||
<string name="sync_url_default" translatable="false">https://sync.kotatsu.app</string>
|
||||
|
||||
@@ -733,4 +733,8 @@
|
||||
<string name="content_type_image_set">Image set</string>
|
||||
<string name="content_type_artist_cg">Artist CG</string>
|
||||
<string name="content_type_game_cg">Game CG</string>
|
||||
<string name="debug">Debug</string>
|
||||
<string name="source_code">Source code</string>
|
||||
<string name="user_manual">User manual</string>
|
||||
<string name="telegram_group">Telegram group</string>
|
||||
</resources>
|
||||
|
||||
@@ -3,45 +3,40 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory android:title="@string/app_name">
|
||||
<Preference
|
||||
android:key="app_version"
|
||||
android:persistent="false"
|
||||
android:summary="@string/check_for_updates" />
|
||||
|
||||
<Preference
|
||||
android:key="app_version"
|
||||
android:persistent="false"
|
||||
android:summary="@string/check_for_updates" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="updates_unstable"
|
||||
android:summary="@string/allow_unstable_updates_summary"
|
||||
android:title="@string/allow_unstable_updates" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="updates_unstable"
|
||||
android:summary="@string/allow_unstable_updates_summary"
|
||||
android:title="@string/allow_unstable_updates" />
|
||||
<Preference
|
||||
android:key="about_help"
|
||||
android:persistent="false"
|
||||
android:summary="@string/url_user_manual"
|
||||
android:title="@string/user_manual"
|
||||
app:allowDividerAbove="true" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="logging"
|
||||
android:summary="@string/enable_logging_summary"
|
||||
android:title="@string/enable_logging"
|
||||
app:allowDividerAbove="true" />
|
||||
<Preference
|
||||
android:key="about_github"
|
||||
android:persistent="false"
|
||||
android:summary="@string/url_github"
|
||||
android:title="@string/source_code" />
|
||||
|
||||
<Preference
|
||||
android:dependency="logging"
|
||||
android:key="logs_share"
|
||||
android:title="@string/share_logs" />
|
||||
<Preference
|
||||
android:key="about_app_translation"
|
||||
android:persistent="false"
|
||||
android:summary="@string/url_weblate"
|
||||
android:title="@string/about_app_translation_summary" />
|
||||
|
||||
<Preference
|
||||
android:key="tracker_debug"
|
||||
android:persistent="false"
|
||||
android:summary="@string/tracker_debug_info_summary"
|
||||
android:title="@string/tracker_debug_info" />
|
||||
|
||||
<Preference
|
||||
android:key="about_app_translation"
|
||||
android:summary="@string/about_app_translation_summary"
|
||||
android:title="@string/about_app_translation"
|
||||
app:allowDividerAbove="true" />
|
||||
|
||||
<org.koitharu.kotatsu.settings.utils.AboutLinksPreference />
|
||||
|
||||
</PreferenceCategory>
|
||||
<Preference
|
||||
android:key="about_telegram"
|
||||
android:persistent="false"
|
||||
android:summary="@string/url_telegram_web"
|
||||
android:title="@string/telegram_group" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
@@ -59,22 +58,29 @@
|
||||
android:title="@string/download_new_chapters"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<Preference
|
||||
android:dependency="tracker_enabled"
|
||||
android:key="ignore_dose"
|
||||
android:persistent="false"
|
||||
android:summary="@string/disable_battery_optimization_summary"
|
||||
android:title="@string/disable_battery_optimization"
|
||||
app:allowDividerAbove="true"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPrefrenceVisible="true" />
|
||||
<PreferenceCategory android:title="@string/debug">
|
||||
|
||||
<org.koitharu.kotatsu.settings.utils.LinksPreference
|
||||
android:icon="@drawable/ic_info_outline"
|
||||
android:key="track_warning"
|
||||
android:persistent="false"
|
||||
android:selectable="false"
|
||||
android:summary="@string/tracker_warning"
|
||||
app:allowDividerAbove="true" />
|
||||
<Preference
|
||||
android:dependency="tracker_enabled"
|
||||
android:key="tracker_debug"
|
||||
android:persistent="false"
|
||||
android:summary="@string/tracker_debug_info_summary"
|
||||
android:title="@string/tracker_debug_info" />
|
||||
|
||||
<Preference
|
||||
android:dependency="tracker_enabled"
|
||||
android:key="ignore_dose"
|
||||
android:persistent="false"
|
||||
android:summary="@string/disable_battery_optimization_summary"
|
||||
android:title="@string/disable_battery_optimization"
|
||||
app:isPreferenceVisible="false" />
|
||||
|
||||
<org.koitharu.kotatsu.settings.utils.LinksPreference
|
||||
android:icon="@drawable/ic_info_outline"
|
||||
android:key="track_warning"
|
||||
android:persistent="false"
|
||||
android:selectable="false"
|
||||
android:summary="@string/tracker_warning" />
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
Reference in New Issue
Block a user