Merge branch 'devel' into feature/nextgen
commit
4fcdd9f370
@ -0,0 +1,64 @@
|
|||||||
|
name: 🐞 Bug report
|
||||||
|
description: Report a bug in Kotatsu
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: summary
|
||||||
|
attributes:
|
||||||
|
label: Brief summary
|
||||||
|
description: Please describe, what went wrong
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce-steps
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Please provide a way to reproduce this issue. Screenshots or videos can be very helpful
|
||||||
|
placeholder: |
|
||||||
|
Example:
|
||||||
|
1. First step
|
||||||
|
2. Second step
|
||||||
|
3. Issue here
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: kotatsu-version
|
||||||
|
attributes:
|
||||||
|
label: Kotatsu version
|
||||||
|
description: You can find your Kotatsu version in **Settings → About**.
|
||||||
|
placeholder: |
|
||||||
|
Example: "3.3"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: android-version
|
||||||
|
attributes:
|
||||||
|
label: Android version
|
||||||
|
description: You can find this somewhere in your Android settings.
|
||||||
|
placeholder: |
|
||||||
|
Example: "12.0"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: Device
|
||||||
|
description: List your device and model.
|
||||||
|
placeholder: |
|
||||||
|
Example: "LG Nexus 5X"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: acknowledgements
|
||||||
|
attributes:
|
||||||
|
label: Acknowledgements
|
||||||
|
options:
|
||||||
|
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
|
||||||
|
required: true
|
||||||
@ -1,91 +0,0 @@
|
|||||||
name: 🐞 Issue report
|
|
||||||
description: Report an issue in Kotatsu
|
|
||||||
labels: [bug]
|
|
||||||
body:
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: reproduce-steps
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce
|
|
||||||
description: Provide an example of the issue.
|
|
||||||
placeholder: |
|
|
||||||
Example:
|
|
||||||
1. First step
|
|
||||||
2. Second step
|
|
||||||
3. Issue here
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: expected-behavior
|
|
||||||
attributes:
|
|
||||||
label: Expected behavior
|
|
||||||
description: Explain what you should expect to happen.
|
|
||||||
placeholder: |
|
|
||||||
Example:
|
|
||||||
"This should happen..."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: actual-behavior
|
|
||||||
attributes:
|
|
||||||
label: Actual behavior
|
|
||||||
description: Explain what actually happens.
|
|
||||||
placeholder: |
|
|
||||||
Example:
|
|
||||||
"This happened instead..."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: kotatsu-version
|
|
||||||
attributes:
|
|
||||||
label: Kotatsu version
|
|
||||||
description: You can find your Kotatsu version in **Settings → About**.
|
|
||||||
placeholder: |
|
|
||||||
Example: "3.3"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: android-version
|
|
||||||
attributes:
|
|
||||||
label: Android version
|
|
||||||
description: You can find this somewhere in your Android settings.
|
|
||||||
placeholder: |
|
|
||||||
Example: "Android 12"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: device
|
|
||||||
attributes:
|
|
||||||
label: Device
|
|
||||||
description: List your device and model.
|
|
||||||
placeholder: |
|
|
||||||
Example: "LG Nexus 5X"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: other-details
|
|
||||||
attributes:
|
|
||||||
label: Other details
|
|
||||||
placeholder: |
|
|
||||||
Additional details and attachments.
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: acknowledgements
|
|
||||||
attributes:
|
|
||||||
label: Acknowledgements
|
|
||||||
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
|
|
||||||
options:
|
|
||||||
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
|
|
||||||
required: true
|
|
||||||
- label: I have written a short but informative title.
|
|
||||||
required: true
|
|
||||||
- label: If this is an issue with a source, I should be opening an issue in the [parsers repository](https://github.com/KotatsuApp/kotatsu-parsers/issues/new).
|
|
||||||
required: true
|
|
||||||
- label: I will fill out all of the requested information in this form.
|
|
||||||
required: true
|
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package org.koitharu.kotatsu.settings
|
||||||
|
|
||||||
|
import okhttp3.internal.toCanonicalHost
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.utils.EditTextValidator
|
||||||
|
|
||||||
|
class DomainValidator : EditTextValidator() {
|
||||||
|
|
||||||
|
override fun validate(text: String): ValidationResult {
|
||||||
|
if (text.isBlank()) {
|
||||||
|
return ValidationResult.Success
|
||||||
|
}
|
||||||
|
val host = text.trim().toCanonicalHost()
|
||||||
|
return if (host == null) {
|
||||||
|
ValidationResult.Failed(context.getString(R.string.invalid_domain_message))
|
||||||
|
} else {
|
||||||
|
ValidationResult.Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package org.koitharu.kotatsu.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.annotation.CallSuper
|
||||||
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
abstract class EditTextValidator : TextWatcher {
|
||||||
|
|
||||||
|
private var editTextRef: WeakReference<EditText>? = null
|
||||||
|
|
||||||
|
protected val context: Context
|
||||||
|
get() = checkNotNull(editTextRef?.get()?.context) {
|
||||||
|
"EditTextValidator is not attached to EditText"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun afterTextChanged(s: Editable?) {
|
||||||
|
val editText = editTextRef?.get() ?: return
|
||||||
|
val newText = s?.toString().orEmpty()
|
||||||
|
val result = runCatching {
|
||||||
|
validate(newText)
|
||||||
|
}.getOrElse { e ->
|
||||||
|
ValidationResult.Failed(e.getDisplayMessage(editText.resources))
|
||||||
|
}
|
||||||
|
editText.error = when (result) {
|
||||||
|
is ValidationResult.Failed -> result.message
|
||||||
|
ValidationResult.Success -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun attachToEditText(editText: EditText) {
|
||||||
|
editTextRef = WeakReference(editText)
|
||||||
|
editText.removeTextChangedListener(this)
|
||||||
|
editText.addTextChangedListener(this)
|
||||||
|
afterTextChanged(editText.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun validate(text: String): ValidationResult
|
||||||
|
|
||||||
|
sealed class ValidationResult {
|
||||||
|
|
||||||
|
object Success : ValidationResult()
|
||||||
|
|
||||||
|
class Failed(val message: CharSequence) : ValidationResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package org.koitharu.kotatsu.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import kotlinx.coroutines.yield
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class CompositeMutexTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSingleLock() = runTest {
|
||||||
|
val mutex = CompositeMutex<Int>()
|
||||||
|
mutex.lock(1)
|
||||||
|
mutex.lock(2)
|
||||||
|
mutex.unlock(1)
|
||||||
|
assert(mutex.size == 1)
|
||||||
|
mutex.unlock(2)
|
||||||
|
assert(mutex.isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDoubleLock() = runTest {
|
||||||
|
val mutex = CompositeMutex<Int>()
|
||||||
|
repeat(2) {
|
||||||
|
launch(Dispatchers.Default) {
|
||||||
|
mutex.lock(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield()
|
||||||
|
mutex.unlock(1)
|
||||||
|
val tryLock = withTimeoutOrNull(1000) {
|
||||||
|
mutex.lock(1)
|
||||||
|
}
|
||||||
|
assertNull(tryLock)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue