Init commit
This commit is contained in:
26
app/src/main/java/io/nekohasekai/sfa/ktx/Browsers.kt
Normal file
26
app/src/main/java/io/nekohasekai/sfa/ktx/Browsers.kt
Normal file
@@ -0,0 +1,26 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.browser.customtabs.CustomTabColorSchemeParams
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import com.google.android.material.elevation.SurfaceColors
|
||||
|
||||
fun Context.launchCustomTab(link: String) {
|
||||
val color = SurfaceColors.SURFACE_2.getColor(this)
|
||||
CustomTabsIntent.Builder().apply {
|
||||
setColorScheme(CustomTabsIntent.COLOR_SCHEME_SYSTEM)
|
||||
setColorSchemeParams(
|
||||
CustomTabsIntent.COLOR_SCHEME_LIGHT,
|
||||
CustomTabColorSchemeParams.Builder().apply {
|
||||
setToolbarColor(color)
|
||||
}.build()
|
||||
)
|
||||
setColorSchemeParams(
|
||||
CustomTabsIntent.COLOR_SCHEME_DARK,
|
||||
CustomTabColorSchemeParams.Builder().apply {
|
||||
setToolbarColor(color)
|
||||
}.build()
|
||||
)
|
||||
}.build().launchUrl(this, Uri.parse(link))
|
||||
}
|
||||
17
app/src/main/java/io/nekohasekai/sfa/ktx/Colors.kt
Normal file
17
app/src/main/java/io/nekohasekai/sfa/ktx/Colors.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
|
||||
|
||||
@ColorInt
|
||||
fun Context.getAttrColor(
|
||||
@AttrRes attrColor: Int,
|
||||
typedValue: TypedValue = TypedValue(),
|
||||
resolveRefs: Boolean = true
|
||||
): Int {
|
||||
theme.resolveAttribute(attrColor, typedValue, resolveRefs)
|
||||
return typedValue.data
|
||||
}
|
||||
18
app/src/main/java/io/nekohasekai/sfa/ktx/Continuations.kt
Normal file
18
app/src/main/java/io/nekohasekai/sfa/ktx/Continuations.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import kotlin.coroutines.Continuation
|
||||
|
||||
|
||||
fun <T> Continuation<T>.tryResume(value: T) {
|
||||
try {
|
||||
resumeWith(Result.success(value))
|
||||
} catch (ignored: IllegalStateException) {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Continuation<T>.tryResumeWithException(exception: Throwable) {
|
||||
try {
|
||||
resumeWith(Result.failure(exception))
|
||||
} catch (ignored: IllegalStateException) {
|
||||
}
|
||||
}
|
||||
24
app/src/main/java/io/nekohasekai/sfa/ktx/Dialogs.kt
Normal file
24
app/src/main/java/io/nekohasekai/sfa/ktx/Dialogs.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.StringRes
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.nekohasekai.sfa.R
|
||||
|
||||
fun Context.errorDialogBuilder(@StringRes messageId: Int): MaterialAlertDialogBuilder {
|
||||
return MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error_title)
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(resources.getString(android.R.string.ok), null)
|
||||
}
|
||||
|
||||
fun Context.errorDialogBuilder(message: String): MaterialAlertDialogBuilder {
|
||||
return MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error_title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(resources.getString(android.R.string.ok), null)
|
||||
}
|
||||
|
||||
fun Context.errorDialogBuilder(exception: Throwable): MaterialAlertDialogBuilder {
|
||||
return errorDialogBuilder(exception.localizedMessage ?: exception.toString())
|
||||
}
|
||||
51
app/src/main/java/io/nekohasekai/sfa/ktx/Inputs.kt
Normal file
51
app/src/main/java/io/nekohasekai/sfa/ktx/Inputs.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import androidx.annotation.ArrayRes
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import io.nekohasekai.sfa.R
|
||||
|
||||
var TextInputLayout.text: String
|
||||
get() = editText?.text?.toString() ?: ""
|
||||
set(value) {
|
||||
editText?.setText(value)
|
||||
}
|
||||
|
||||
var TextInputLayout.error: String
|
||||
get() = editText?.error?.toString() ?: ""
|
||||
set(value) {
|
||||
editText?.error = value
|
||||
}
|
||||
|
||||
|
||||
fun TextInputLayout.setSimpleItems(@ArrayRes redId: Int) {
|
||||
(editText as? MaterialAutoCompleteTextView)?.setSimpleItems(redId)
|
||||
}
|
||||
|
||||
fun TextInputLayout.removeErrorIfNotEmpty() {
|
||||
addOnEditTextAttachedListener {
|
||||
editText?.addTextChangedListener {
|
||||
if (text.isNotBlank()) {
|
||||
error = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun TextInputLayout.showErrorIfEmpty(): Boolean {
|
||||
if (text.isBlank()) {
|
||||
error = context.getString(R.string.profile_input_required)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
fun TextInputLayout.addTextChangedListener(listener: (String) -> Unit) {
|
||||
addOnEditTextAttachedListener {
|
||||
editText?.addTextChangedListener {
|
||||
listener(it?.toString() ?: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
21
app/src/main/java/io/nekohasekai/sfa/ktx/Intents.kt
Normal file
21
app/src/main/java/io/nekohasekai/sfa/ktx/Intents.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.ui.shared.AbstractActivity
|
||||
|
||||
fun AbstractActivity.startFilesForResult(
|
||||
launcher: ActivityResultLauncher<String>, input: String
|
||||
) {
|
||||
try {
|
||||
return launcher.launch(input)
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
} catch (_: SecurityException) {
|
||||
}
|
||||
val builder = MaterialAlertDialogBuilder(this)
|
||||
builder.setPositiveButton(resources.getString(android.R.string.ok), null)
|
||||
builder.setMessage(R.string.file_manager_missing)
|
||||
builder.show()
|
||||
}
|
||||
66
app/src/main/java/io/nekohasekai/sfa/ktx/Preferences.kt
Normal file
66
app/src/main/java/io/nekohasekai/sfa/ktx/Preferences.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import androidx.preference.PreferenceDataStore
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun PreferenceDataStore.string(
|
||||
name: String,
|
||||
defaultValue: () -> String = { "" },
|
||||
) = PreferenceProxy(name, defaultValue, ::getString, ::putString)
|
||||
|
||||
fun PreferenceDataStore.stringNotBlack(
|
||||
name: String,
|
||||
defaultValue: () -> String = { "" },
|
||||
) = PreferenceProxy(name, defaultValue, { key, default ->
|
||||
getString(key, default)?.takeIf { it.isNotBlank() } ?: default
|
||||
}, { key, value ->
|
||||
putString(key, value.takeIf { it.isNotBlank() } ?: defaultValue())
|
||||
})
|
||||
|
||||
fun PreferenceDataStore.boolean(
|
||||
name: String,
|
||||
defaultValue: () -> Boolean = { false },
|
||||
) = PreferenceProxy(name, defaultValue, ::getBoolean, ::putBoolean)
|
||||
|
||||
fun PreferenceDataStore.int(
|
||||
name: String,
|
||||
defaultValue: () -> Int = { 0 },
|
||||
) = PreferenceProxy(name, defaultValue, ::getInt, ::putInt)
|
||||
|
||||
fun PreferenceDataStore.stringToInt(
|
||||
name: String,
|
||||
defaultValue: () -> Int = { 0 },
|
||||
) = PreferenceProxy(name, defaultValue, { key, default ->
|
||||
getString(key, "$default")?.toIntOrNull() ?: default
|
||||
}, { key, value -> putString(key, "$value") })
|
||||
|
||||
fun PreferenceDataStore.stringToIntIfExists(
|
||||
name: String,
|
||||
defaultValue: () -> Int = { 0 },
|
||||
) = PreferenceProxy(name, defaultValue, { key, default ->
|
||||
getString(key, "$default")?.toIntOrNull() ?: default
|
||||
}, { key, value -> putString(key, value.takeIf { it > 0 }?.toString() ?: "") })
|
||||
|
||||
fun PreferenceDataStore.long(
|
||||
name: String,
|
||||
defaultValue: () -> Long = { 0L },
|
||||
) = PreferenceProxy(name, defaultValue, ::getLong, ::putLong)
|
||||
|
||||
fun PreferenceDataStore.stringToLong(
|
||||
name: String,
|
||||
defaultValue: () -> Long = { 0L },
|
||||
) = PreferenceProxy(name, defaultValue, { key, default ->
|
||||
getString(key, "$default")?.toLongOrNull() ?: default
|
||||
}, { key, value -> putString(key, "$value") })
|
||||
|
||||
class PreferenceProxy<T>(
|
||||
val name: String,
|
||||
val defaultValue: () -> T,
|
||||
val getter: (String, T) -> T?,
|
||||
val setter: (String, value: T) -> Unit,
|
||||
) {
|
||||
|
||||
operator fun setValue(thisObj: Any?, property: KProperty<*>, value: T) = setter(name, value)
|
||||
operator fun getValue(thisObj: Any?, property: KProperty<*>) = getter(name, defaultValue())!!
|
||||
|
||||
}
|
||||
21
app/src/main/java/io/nekohasekai/sfa/ktx/Room.kt
Normal file
21
app/src/main/java/io/nekohasekai/sfa/ktx/Room.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package io.nekohasekai.sfa.ktx
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
fun Parcelable.marshall(): ByteArray {
|
||||
val parcel = Parcel.obtain()
|
||||
writeToParcel(parcel, 0)
|
||||
val content = parcel.marshall()
|
||||
parcel.recycle()
|
||||
return content
|
||||
}
|
||||
|
||||
fun <T> ByteArray.unmarshall(constructor: (Parcel) -> T): T {
|
||||
val parcel = Parcel.obtain()
|
||||
parcel.unmarshall(this, 0, size)
|
||||
parcel.setDataPosition(0) // This is extremely important!
|
||||
val result = constructor(parcel)
|
||||
parcel.recycle()
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user