From 5e66d99c852ea67a88b650c03b0e8d55e83eccde Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sat, 5 Dec 2020 06:07:18 +0530 Subject: Refactor package structure (#1233) * idea: default test runner to Gradle * Kick off package structure revamp * Reparent all classes under dev.msfjarvis.aps Signed-off-by: Harsh Shandilya --- .../aps/util/extensions/AndroidExtensions.kt | 179 +++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt (limited to 'app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt') 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 new file mode 100644 index 00000000..308c5966 --- /dev/null +++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt @@ -0,0 +1,179 @@ +/* + * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.util.extensions + +import android.app.KeyguardManager +import android.content.ClipboardManager +import android.content.Context +import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.os.Build +import android.util.Base64 +import android.util.TypedValue +import android.view.View +import android.view.autofill.AutofillManager +import android.view.inputmethod.InputMethodManager +import androidx.annotation.IdRes +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat +import androidx.core.content.getSystemService +import androidx.fragment.app.FragmentActivity +import androidx.preference.PreferenceManager +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey +import com.github.ajalt.timberkt.d +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result +import com.google.android.material.snackbar.Snackbar +import dev.msfjarvis.aps.R +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 + */ +fun AlertDialog.requestInputFocusOnView(@IdRes id: Int) { + setOnShowListener { + findViewById(id)?.apply { + setOnFocusChangeListener { v, _ -> + v.post { + context.getSystemService() + ?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT) + } + } + requestFocus() + } + } +} + +/** + * Get an instance of [AutofillManager]. Only + * available on Android Oreo and above + */ +val Context.autofillManager: AutofillManager? + @RequiresApi(Build.VERSION_CODES.O) + get() = getSystemService() + +/** + * Get an instance of [ClipboardManager] + */ +val Context.clipboard + get() = getSystemService() + +/** + * 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. + */ +fun Context.getEncryptedProxyPrefs() = getEncryptedPrefs("http_proxy") + +/** + * 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 + ) +} + +/** + * Get an instance of [KeyguardManager] + */ +val Context.keyguardManager: KeyguardManager + get() = getSystemService()!! + +/** + * Get the default [SharedPreferences] instance + */ +val Context.sharedPrefs: SharedPreferences + get() = PreferenceManager.getDefaultSharedPreferences(applicationContext) + + +/** + * 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 +} + +/** + * Commit changes to the store from a [FragmentActivity] using + * a custom implementation of [GitOperation] + */ +suspend fun FragmentActivity.commitChange( + message: String, +): Result { + 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() +} + +/** + * Check if [permission] has been granted to the app. + */ +fun FragmentActivity.isPermissionGranted(permission: String): Boolean { + 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] + */ +fun FragmentActivity.snackbar( + 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 +} + +/** + * 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 + */ +fun String.base64(): String { + return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP) +} -- cgit v1.2.3