Small fixes
This commit is contained in:
@@ -42,7 +42,7 @@ class StrictModeNotifier(
|
||||
override fun onViolation(violation: FragmentViolation) = showNotification(violation)
|
||||
|
||||
private fun showNotification(violation: Throwable) = Notification.Builder(context, CHANNEL_ID)
|
||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
.setSmallIcon(R.drawable.ic_bug)
|
||||
.setContentTitle(context.getString(R.string.strict_mode))
|
||||
.setContentText(violation.message)
|
||||
.setStyle(
|
||||
|
||||
15
app/src/debug/res/drawable-anydpi-v24/ic_bug.xml
Normal file
15
app/src/debug/res/drawable-anydpi-v24/ic_bug.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF">
|
||||
<group android:scaleX="0.98150784"
|
||||
android:scaleY="0.98150784"
|
||||
android:translateX="0.22190611"
|
||||
android:translateY="-0.2688478">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"/>
|
||||
</group>
|
||||
</vector>
|
||||
BIN
app/src/debug/res/drawable-hdpi/ic_bug.png
Normal file
BIN
app/src/debug/res/drawable-hdpi/ic_bug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 417 B |
BIN
app/src/debug/res/drawable-mdpi/ic_bug.png
Normal file
BIN
app/src/debug/res/drawable-mdpi/ic_bug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 308 B |
BIN
app/src/debug/res/drawable-xhdpi/ic_bug.png
Normal file
BIN
app/src/debug/res/drawable-xhdpi/ic_bug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 480 B |
BIN
app/src/debug/res/drawable-xxhdpi/ic_bug.png
Normal file
BIN
app/src/debug/res/drawable-xxhdpi/ic_bug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 792 B |
@@ -29,7 +29,7 @@ class CaptchaNotifier(
|
||||
return
|
||||
}
|
||||
val manager = NotificationManagerCompat.from(context)
|
||||
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_DEFAULT)
|
||||
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_LOW)
|
||||
.setName(context.getString(R.string.captcha_required))
|
||||
.setShowBadge(true)
|
||||
.setVibrationEnabled(false)
|
||||
@@ -42,8 +42,8 @@ class CaptchaNotifier(
|
||||
.setData(exception.url.toUri())
|
||||
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setContentTitle(channel.name)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setDefaults(NotificationCompat.DEFAULT_SOUND)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setDefaults(0)
|
||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
.setGroup(GROUP_CAPTCHA)
|
||||
.setAutoCancel(true)
|
||||
|
||||
@@ -42,7 +42,7 @@ class ExternalMangaRepository(
|
||||
|
||||
override var defaultSortOrder: SortOrder
|
||||
get() = capabilities?.availableSortOrders?.firstOrNull() ?: SortOrder.ALPHABETICAL
|
||||
set(value) = Unit
|
||||
set(_) = Unit
|
||||
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions = filterOptions.get()
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.core.net.toUri
|
||||
import org.jetbrains.annotations.Blocking
|
||||
import org.koitharu.kotatsu.core.exceptions.IncompatiblePluginException
|
||||
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.ContentRating
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Demographic
|
||||
|
||||
@@ -42,7 +42,10 @@ import java.net.UnknownHostException
|
||||
private const val MSG_NO_SPACE_LEFT = "No space left on device"
|
||||
private const val IMAGE_FORMAT_NOT_SUPPORTED = "Image format not supported"
|
||||
|
||||
fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
||||
fun Throwable.getDisplayMessage(resources: Resources): String = getDisplayMessageOrNull(resources)
|
||||
?: resources.getString(R.string.error_occurred)
|
||||
|
||||
private fun Throwable.getDisplayMessageOrNull(resources: Resources): String? = when (this) {
|
||||
is ScrobblerAuthRequiredException -> resources.getString(
|
||||
R.string.scrobbler_auth_required,
|
||||
resources.getString(scrobbler.titleResId),
|
||||
@@ -88,7 +91,11 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
||||
)
|
||||
|
||||
is NoDataReceivedException -> resources.getString(R.string.error_no_data_received)
|
||||
is IncompatiblePluginException -> resources.getString(R.string.plugin_incompatible)
|
||||
is IncompatiblePluginException -> {
|
||||
cause?.getDisplayMessageOrNull(resources)?.let {
|
||||
resources.getString(R.string.plugin_incompatible_with_cause, it)
|
||||
} ?: resources.getString(R.string.plugin_incompatible)
|
||||
}
|
||||
is WrongPasswordException -> resources.getString(R.string.wrong_password)
|
||||
is NotFoundException -> resources.getString(R.string.not_found_404)
|
||||
is UnsupportedSourceException -> resources.getString(R.string.unsupported_source)
|
||||
@@ -97,9 +104,7 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
||||
is HttpStatusException -> getHttpDisplayMessage(statusCode, resources)
|
||||
|
||||
else -> getDisplayMessage(message, resources) ?: message
|
||||
}.ifNullOrEmpty {
|
||||
resources.getString(R.string.error_occurred)
|
||||
}
|
||||
}.takeUnless { it.isNullOrBlank() }
|
||||
|
||||
@DrawableRes
|
||||
fun Throwable.getDisplayIcon() = when (this) {
|
||||
|
||||
@@ -2,11 +2,13 @@ package org.koitharu.kotatsu.core.zip
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.collection.ArraySet
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.Closeable
|
||||
import org.jetbrains.annotations.Blocking
|
||||
import org.koitharu.kotatsu.core.util.ext.withChildren
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.io.FileOutputStream
|
||||
import java.util.zip.Deflater
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
@@ -14,27 +16,23 @@ import java.util.zip.ZipOutputStream
|
||||
|
||||
class ZipOutput(
|
||||
val file: File,
|
||||
compressionLevel: Int = Deflater.DEFAULT_COMPRESSION,
|
||||
private val compressionLevel: Int = Deflater.DEFAULT_COMPRESSION,
|
||||
) : Closeable {
|
||||
|
||||
private val entryNames = ArraySet<String>()
|
||||
private val isClosed = AtomicBoolean(false)
|
||||
private val output = ZipOutputStream(file.outputStream()).apply {
|
||||
setLevel(compressionLevel)
|
||||
// FIXME: Deflater has been closed
|
||||
private var cachedOutput: ZipOutputStream? = null
|
||||
|
||||
@Blocking
|
||||
fun put(name: String, file: File): Boolean = withOutput { output ->
|
||||
output.appendFile(file, name)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun put(name: String, file: File): Boolean {
|
||||
return output.appendFile(file, name)
|
||||
@Blocking
|
||||
fun put(name: String, content: String): Boolean = withOutput { output ->
|
||||
output.appendText(content, name)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun put(name: String, content: String): Boolean {
|
||||
return output.appendText(content, name)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@Blocking
|
||||
fun addDirectory(name: String): Boolean {
|
||||
val entry = if (name.endsWith("/")) {
|
||||
ZipEntry(name)
|
||||
@@ -42,24 +40,8 @@ class ZipOutput(
|
||||
ZipEntry("$name/")
|
||||
}
|
||||
return if (entryNames.add(entry.name)) {
|
||||
output.putNextEntry(entry)
|
||||
output.closeEntry()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun copyEntryFrom(other: ZipFile, entry: ZipEntry): Boolean {
|
||||
return if (entryNames.add(entry.name)) {
|
||||
val zipEntry = ZipEntry(entry.name)
|
||||
output.putNextEntry(zipEntry)
|
||||
try {
|
||||
other.getInputStream(entry).use { input ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
} finally {
|
||||
withOutput { output ->
|
||||
output.putNextEntry(entry)
|
||||
output.closeEntry()
|
||||
}
|
||||
true
|
||||
@@ -68,15 +50,35 @@ class ZipOutput(
|
||||
}
|
||||
}
|
||||
|
||||
fun finish() {
|
||||
output.finish()
|
||||
output.flush()
|
||||
@Blocking
|
||||
fun copyEntryFrom(other: ZipFile, entry: ZipEntry): Boolean {
|
||||
return if (entryNames.add(entry.name)) {
|
||||
val zipEntry = ZipEntry(entry.name)
|
||||
withOutput { output ->
|
||||
output.putNextEntry(zipEntry)
|
||||
try {
|
||||
other.getInputStream(entry).use { input ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
} finally {
|
||||
output.closeEntry()
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Blocking
|
||||
fun finish() = withOutput { output ->
|
||||
output.finish()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun close() {
|
||||
if (isClosed.compareAndSet(false, true)) {
|
||||
output.close()
|
||||
}
|
||||
cachedOutput?.close()
|
||||
cachedOutput = null
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -128,4 +130,18 @@ class ZipOutput(
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun <T> withOutput(block: (ZipOutputStream) -> T): T {
|
||||
val output = cachedOutput ?: newOutput(append = false)
|
||||
val res = block(output)
|
||||
output.flush()
|
||||
return res
|
||||
}
|
||||
|
||||
private fun newOutput(append: Boolean) = ZipOutputStream(FileOutputStream(file, append)).also {
|
||||
it.setLevel(compressionLevel)
|
||||
cachedOutput?.closeQuietly()
|
||||
cachedOutput = it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class LocalListFragment : MangaListFragment(), FilterCoordinator.Owner {
|
||||
|
||||
override fun onViewBindingCreated(binding: FragmentListBinding, savedInstanceState: Bundle?) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
addMenuProvider(LocalListMenuProvider(binding.root.context, this::onEmptyActionClick))
|
||||
addMenuProvider(LocalListMenuProvider(binding.root.context, childFragmentManager, this::onEmptyActionClick))
|
||||
addMenuProvider(MangaSearchMenuProvider(filterCoordinator, viewModel))
|
||||
viewModel.onMangaRemoved.observeEvent(viewLifecycleOwner) { onItemRemoved() }
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.filter.ui.sheet.FilterSheetFragment
|
||||
import org.koitharu.kotatsu.settings.storage.directories.MangaDirectoriesActivity
|
||||
|
||||
class LocalListMenuProvider(
|
||||
private val context: Context,
|
||||
private val fragmentManager: FragmentManager,
|
||||
private val onImportClick: Function0<Unit>,
|
||||
) : MenuProvider {
|
||||
|
||||
@@ -29,6 +32,11 @@ class LocalListMenuProvider(
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_filter -> {
|
||||
FilterSheetFragment.show(fragmentManager)
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,15 @@
|
||||
android:title="@string/_import"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_filter"
|
||||
android:orderInCategory="30"
|
||||
android:title="@string/filter"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_directories"
|
||||
android:orderInCategory="96"
|
||||
android:orderInCategory="80"
|
||||
android:title="@string/directories"
|
||||
app:showAsAction="never" />
|
||||
|
||||
|
||||
@@ -679,6 +679,7 @@
|
||||
<string name="chapters_left">Chapters left</string>
|
||||
<string name="external_source">External/plugin</string>
|
||||
<string name="plugin_incompatible">Incompatible plugin or internal error. Make sure you are using the latest version of the plugin and Kotatsu</string>
|
||||
<string name="plugin_incompatible_with_cause">Plugin error: %s\n Make sure you are using the latest version of the plugin and Kotatsu</string>
|
||||
<string name="connection_ok">Connection is OK</string>
|
||||
<string name="invalid_proxy_configuration">Invalid proxy configuration</string>
|
||||
<string name="show_quick_filters">Show quick filters</string>
|
||||
|
||||
Reference in New Issue
Block a user