aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/dev/msfjarvis/aps/util/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/dev/msfjarvis/aps/util/extensions')
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt167
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/extensions/Extensions.kt65
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentExtensions.kt40
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt66
4 files changed, 147 insertions, 191 deletions
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt b/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt
index e200320e..94103118 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt
@@ -34,146 +34,115 @@ import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.util.git.operation.GitOperation
/**
- * Extension function for [AlertDialog] that requests focus for the
- * view whose id is [id]. Solution based on a StackOverflow
- * answer: https://stackoverflow.com/a/13056259/297261
+ * Extension function for [AlertDialog] that requests focus for the view whose id is [id]. Solution
+ * based on a StackOverflow answer: https://stackoverflow.com/a/13056259/297261
*/
fun <T : View> AlertDialog.requestInputFocusOnView(@IdRes id: Int) {
- setOnShowListener {
- findViewById<T>(id)?.apply {
- setOnFocusChangeListener { v, _ ->
- v.post {
- context.getSystemService<InputMethodManager>()
- ?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
- }
- }
- requestFocus()
- }
+ setOnShowListener {
+ findViewById<T>(id)?.apply {
+ setOnFocusChangeListener { v, _ ->
+ v.post { context.getSystemService<InputMethodManager>()?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT) }
+ }
+ requestFocus()
}
+ }
}
-/**
- * Get an instance of [AutofillManager]. Only
- * available on Android Oreo and above
- */
+/** Get an instance of [AutofillManager]. Only available on Android Oreo and above */
val Context.autofillManager: AutofillManager?
- @RequiresApi(Build.VERSION_CODES.O)
- get() = getSystemService()
+ @RequiresApi(Build.VERSION_CODES.O) get() = getSystemService()
-/**
- * Get an instance of [ClipboardManager]
- */
+/** Get an instance of [ClipboardManager] */
val Context.clipboard
- get() = getSystemService<ClipboardManager>()
+ get() = getSystemService<ClipboardManager>()
-/**
- * Wrapper for [getEncryptedPrefs] to avoid open-coding the file name at
- * each call site
- */
+/** Wrapper for [getEncryptedPrefs] to avoid open-coding the file name at each call site */
fun Context.getEncryptedGitPrefs() = getEncryptedPrefs("git_operation")
-/**
- * Wrapper for [getEncryptedPrefs] to get the encrypted preference set for the HTTP
- * proxy.
- */
+/** Wrapper for [getEncryptedPrefs] to get the encrypted preference set for the HTTP proxy. */
fun Context.getEncryptedProxyPrefs() = getEncryptedPrefs("http_proxy")
-/**
- * Get an instance of [EncryptedSharedPreferences] with the given [fileName]
- */
+/** Get an instance of [EncryptedSharedPreferences] with the given [fileName] */
private fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
- val masterKeyAlias = MasterKey.Builder(applicationContext)
- .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
- .build()
- return EncryptedSharedPreferences.create(
- applicationContext,
- fileName,
- masterKeyAlias,
- EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
- EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
- )
+ val masterKeyAlias = MasterKey.Builder(applicationContext).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
+ return EncryptedSharedPreferences.create(
+ applicationContext,
+ fileName,
+ masterKeyAlias,
+ EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
+ EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
+ )
}
-/**
- * Get an instance of [KeyguardManager]
- */
+/** Get an instance of [KeyguardManager] */
val Context.keyguardManager: KeyguardManager
- get() = getSystemService()!!
+ get() = getSystemService()!!
-/**
- * Get the default [SharedPreferences] instance
- */
+/** Get the default [SharedPreferences] instance */
val Context.sharedPrefs: SharedPreferences
- get() = PreferenceManager.getDefaultSharedPreferences(applicationContext)
-
+ get() = PreferenceManager.getDefaultSharedPreferences(applicationContext)
-/**
- * Resolve [attr] from the [Context]'s theme
- */
+/** Resolve [attr] from the [Context]'s theme */
fun Context.resolveAttribute(attr: Int): Int {
- val typedValue = TypedValue()
- this.theme.resolveAttribute(attr, typedValue, true)
- return typedValue.data
+ val typedValue = TypedValue()
+ this.theme.resolveAttribute(attr, typedValue, true)
+ return typedValue.data
}
/**
- * Commit changes to the store from a [FragmentActivity] using
- * a custom implementation of [GitOperation]
+ * Commit changes to the store from a [FragmentActivity] using a custom implementation of
+ * [GitOperation]
*/
suspend fun FragmentActivity.commitChange(
- message: String,
+ message: String,
): Result<Unit, Throwable> {
- if (!PasswordRepository.isGitRepo()) {
- return Ok(Unit)
- }
- return object : GitOperation(this@commitChange) {
- override val commands = arrayOf(
- // Stage all files
- git.add().addFilepattern("."),
- // Populate the changed files count
- git.status(),
- // Commit everything! If anything changed, that is.
- git.commit().setAll(true).setMessage(message),
+ if (!PasswordRepository.isGitRepo()) {
+ return Ok(Unit)
+ }
+ return object : GitOperation(this@commitChange) {
+ override val commands =
+ arrayOf(
+ // Stage all files
+ git.add().addFilepattern("."),
+ // Populate the changed files count
+ git.status(),
+ // Commit everything! If anything changed, that is.
+ git.commit().setAll(true).setMessage(message),
)
- override fun preExecute(): Boolean {
- d { "Committing with message: '$message'" }
- return true
- }
- }.execute()
+ override fun preExecute(): Boolean {
+ d { "Committing with message: '$message'" }
+ return true
+ }
+ }
+ .execute()
}
-/**
- * Check if [permission] has been granted to the app.
- */
+/** Check if [permission] has been granted to the app. */
fun FragmentActivity.isPermissionGranted(permission: String): Boolean {
- return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
+ return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
/**
- * Show a [Snackbar] in a [FragmentActivity] and correctly
- * anchor it to a [com.google.android.material.floatingactionbutton.FloatingActionButton]
- * if one exists in the [view]
+ * Show a [Snackbar] in a [FragmentActivity] and correctly anchor it to a
+ * [com.google.android.material.floatingactionbutton.FloatingActionButton] if one exists in the
+ * [view]
*/
fun FragmentActivity.snackbar(
- view: View = findViewById(android.R.id.content),
- message: String,
- length: Int = Snackbar.LENGTH_SHORT,
+ view: View = findViewById(android.R.id.content),
+ message: String,
+ length: Int = Snackbar.LENGTH_SHORT,
): Snackbar {
- val snackbar = Snackbar.make(view, message, length)
- snackbar.anchorView = findViewById(R.id.fab)
- snackbar.show()
- return snackbar
+ val snackbar = Snackbar.make(view, message, length)
+ snackbar.anchorView = findViewById(R.id.fab)
+ snackbar.show()
+ return snackbar
}
-/**
- * Simplifies the common `getString(key, null) ?: defaultValue` case slightly
- */
+/** Simplifies the common `getString(key, null) ?: defaultValue` case slightly */
fun SharedPreferences.getString(key: String): String? = getString(key, null)
-/**
- * Convert this [String] to its [Base64] representation
- */
+/** Convert this [String] to its [Base64] representation */
fun String.base64(): String {
- return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP)
+ return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP)
}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/extensions/Extensions.kt b/app/src/main/java/dev/msfjarvis/aps/util/extensions/Extensions.kt
index 9b6d044c..a6d0066c 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/extensions/Extensions.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/Extensions.kt
@@ -12,53 +12,40 @@ import java.util.Date
import org.eclipse.jgit.lib.ObjectId
import org.eclipse.jgit.revwalk.RevCommit
-/**
- * The default OpenPGP provider for the app
- */
+/** The default OpenPGP provider for the app */
const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain"
-/**
- * Clears the given [flag] from the value of this [Int]
- */
+/** Clears the given [flag] from the value of this [Int] */
fun Int.clearFlag(flag: Int): Int {
- return this and flag.inv()
+ return this and flag.inv()
}
-/**
- * Checks if this [Int] contains the given [flag]
- */
+/** Checks if this [Int] contains the given [flag] */
infix fun Int.hasFlag(flag: Int): Boolean {
- return this and flag == flag
+ return this and flag == flag
}
-/**
- * Checks whether this [File] is a directory that contains [other].
- */
+/** Checks whether this [File] is a directory that contains [other]. */
fun File.contains(other: File): Boolean {
- if (!isDirectory)
- return false
- if (!other.exists())
- return false
- val relativePath = runCatching {
- other.relativeTo(this)
- }.getOrElse {
- return false
+ if (!isDirectory) return false
+ if (!other.exists()) return false
+ val relativePath =
+ runCatching { other.relativeTo(this) }.getOrElse {
+ return false
}
- // Direct containment is equivalent to the relative path being equal to the filename.
- return relativePath.path == other.name
+ // Direct containment is equivalent to the relative path being equal to the filename.
+ return relativePath.path == other.name
}
/**
- * Checks if this [File] is in the password repository directory as given
- * by [PasswordRepository.getRepositoryDirectory]
+ * Checks if this [File] is in the password repository directory as given by
+ * [PasswordRepository.getRepositoryDirectory]
*/
fun File.isInsideRepository(): Boolean {
- return canonicalPath.contains(PasswordRepository.getRepositoryDirectory().canonicalPath)
+ return canonicalPath.contains(PasswordRepository.getRepositoryDirectory().canonicalPath)
}
-/**
- * Recursively lists the files in this [File], skipping any directories it encounters.
- */
+/** Recursively lists the files in this [File], skipping any directories it encounters. */
fun File.listFilesRecursively() = walkTopDown().filter { !it.isDirectory }.toList()
/**
@@ -67,7 +54,7 @@ fun File.listFilesRecursively() = walkTopDown().filter { !it.isDirectory }.toLis
* @see RevCommit.getId
*/
val RevCommit.hash: String
- get() = ObjectId.toString(id)
+ get() = ObjectId.toString(id)
/**
* Time this commit was made with second precision.
@@ -75,16 +62,16 @@ val RevCommit.hash: String
* @see RevCommit.commitTime
*/
val RevCommit.time: Date
- get() {
- val epochSeconds = commitTime.toLong()
- val epochMilliseconds = epochSeconds * 1000
- return Date(epochMilliseconds)
- }
+ get() {
+ val epochSeconds = commitTime.toLong()
+ val epochMilliseconds = epochSeconds * 1000
+ return Date(epochMilliseconds)
+ }
/**
- * Splits this [String] into an [Array] of [String]s, split on the UNIX LF line ending
- * and stripped of any empty lines.
+ * Splits this [String] into an [Array] of [String] s, split on the UNIX LF line ending and stripped
+ * of any empty lines.
*/
fun String.splitLines(): Array<String> {
- return split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ return split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentExtensions.kt b/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentExtensions.kt
index 088b15f6..3a256ee7 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentExtensions.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentExtensions.kt
@@ -11,31 +11,31 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.commit
import dev.msfjarvis.aps.R
-/**
- * Check if [permission] is granted to the app. Aliases to [isPermissionGranted] internally.
- */
+/** Check if [permission] is granted to the app. Aliases to [isPermissionGranted] internally. */
fun Fragment.isPermissionGranted(permission: String): Boolean {
- return requireActivity().isPermissionGranted(permission)
+ return requireActivity().isPermissionGranted(permission)
}
-/**
- * Calls `finish()` on the enclosing [androidx.fragment.app.FragmentActivity]
- */
+/** Calls `finish()` on the enclosing [androidx.fragment.app.FragmentActivity] */
fun Fragment.finish() = requireActivity().finish()
/**
- * Perform a [commit] on this [FragmentManager] with custom animations and adding the [destinationFragment]
- * to the fragment backstack
+ * Perform a [commit] on this [FragmentManager] with custom animations and adding the
+ * [destinationFragment] to the fragment backstack
*/
-fun FragmentManager.performTransactionWithBackStack(destinationFragment: Fragment, @IdRes containerViewId: Int = android.R.id.content) {
- commit {
- beginTransaction()
- addToBackStack(destinationFragment.tag)
- setCustomAnimations(
- R.animator.slide_in_left,
- R.animator.slide_out_left,
- R.animator.slide_in_right,
- R.animator.slide_out_right)
- replace(containerViewId, destinationFragment)
- }
+fun FragmentManager.performTransactionWithBackStack(
+ destinationFragment: Fragment,
+ @IdRes containerViewId: Int = android.R.id.content
+) {
+ commit {
+ beginTransaction()
+ addToBackStack(destinationFragment.tag)
+ setCustomAnimations(
+ R.animator.slide_in_left,
+ R.animator.slide_out_left,
+ R.animator.slide_in_right,
+ R.animator.slide_out_right
+ )
+ replace(containerViewId, destinationFragment)
+ }
}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt b/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt
index af2afe9e..5a1b554f 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt
@@ -5,7 +5,6 @@
package dev.msfjarvis.aps.util.extensions
-
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AppCompatActivity
@@ -18,48 +17,49 @@ import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
/**
- * Imported from https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c
+ * Imported from
+ * https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c
*/
-class FragmentViewBindingDelegate<T : ViewBinding>(
- val fragment: Fragment,
- val viewBindingFactory: (View) -> T
-) : ReadOnlyProperty<Fragment, T> {
+class FragmentViewBindingDelegate<T : ViewBinding>(val fragment: Fragment, val viewBindingFactory: (View) -> T) :
+ ReadOnlyProperty<Fragment, T> {
- private var binding: T? = null
+ private var binding: T? = null
- init {
- fragment.lifecycle.addObserver(object : DefaultLifecycleObserver {
- override fun onCreate(owner: LifecycleOwner) {
- fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
- viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
- override fun onDestroy(owner: LifecycleOwner) {
- binding = null
- }
- })
+ init {
+ fragment.lifecycle.addObserver(
+ object : DefaultLifecycleObserver {
+ override fun onCreate(owner: LifecycleOwner) {
+ fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
+ viewLifecycleOwner.lifecycle.addObserver(
+ object : DefaultLifecycleObserver {
+ override fun onDestroy(owner: LifecycleOwner) {
+ binding = null
}
- }
- })
- }
-
- override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
- val binding = binding
- if (binding != null) {
- return binding
+ }
+ )
+ }
}
+ }
+ )
+ }
- val lifecycle = fragment.viewLifecycleOwner.lifecycle
- if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
- throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
- }
+ override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
+ val binding = binding
+ if (binding != null) {
+ return binding
+ }
- return viewBindingFactory(thisRef.requireView()).also { this.binding = it }
+ val lifecycle = fragment.viewLifecycleOwner.lifecycle
+ if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
+ throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
}
+
+ return viewBindingFactory(thisRef.requireView()).also { this.binding = it }
+ }
}
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
- FragmentViewBindingDelegate(this, viewBindingFactory)
+ FragmentViewBindingDelegate(this, viewBindingFactory)
inline fun <T : ViewBinding> AppCompatActivity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) =
- lazy(LazyThreadSafetyMode.NONE) {
- bindingInflater.invoke(layoutInflater)
- }
+ lazy(LazyThreadSafetyMode.NONE) { bindingInflater.invoke(layoutInflater) }