diff options
author | Harsh Shandilya <me@msfjarvis.dev> | 2021-04-21 18:10:19 +0530 |
---|---|---|
committer | Harsh Shandilya <me@msfjarvis.dev> | 2021-04-21 18:10:19 +0530 |
commit | a5b6dfc106f448b59628724a08fb4d6897cbe1d0 (patch) | |
tree | 4e4f0f8af2fc3ce7011624bc3a338ae8bac926fc | |
parent | 6ff01f5e1ee90c6203bc9bd0189eea33c42d6db0 (diff) |
Support creating pinned shortcuts directly (#1393)
* CHANGELOG: update for pinning support
* PasswordFragment: support pinning
* PasswordStore: use `PasswordItem#createAuthEnabledIntent`
* PasswordItem: add `createAuthEnabledIntent` API
* DecryptActivity: remove last changed time
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | app/src/main/java/dev/msfjarvis/aps/data/password/PasswordItem.kt | 14 | ||||
-rw-r--r-- | app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt | 17 | ||||
-rw-r--r-- | app/src/main/java/dev/msfjarvis/aps/ui/crypto/DecryptActivity.kt | 6 | ||||
-rw-r--r-- | app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt | 19 | ||||
-rw-r--r-- | app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt | 38 | ||||
-rw-r--r-- | app/src/main/res/drawable/ic_push_pin_24dp.xml | 11 | ||||
-rw-r--r-- | app/src/main/res/layout/decrypt_layout.xml | 15 | ||||
-rw-r--r-- | app/src/main/res/menu/context_pass.xml | 6 | ||||
-rw-r--r-- | app/src/main/res/values/strings.xml | 1 |
10 files changed, 53 insertions, 75 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0304d949..6a20482b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. - Add support for manually providing TOTP parameters - Parse extra content as individual fields - Improve search result filtering logic +- Allow pinning shortcuts directly to the launcher home screen ### Fixed diff --git a/app/src/main/java/dev/msfjarvis/aps/data/password/PasswordItem.kt b/app/src/main/java/dev/msfjarvis/aps/data/password/PasswordItem.kt index 89923dff..82b0dc35 100644 --- a/app/src/main/java/dev/msfjarvis/aps/data/password/PasswordItem.kt +++ b/app/src/main/java/dev/msfjarvis/aps/data/password/PasswordItem.kt @@ -4,7 +4,11 @@ */ package dev.msfjarvis.aps.data.password +import android.content.Context +import android.content.Intent +import dev.msfjarvis.aps.data.repo.PasswordRepository import dev.msfjarvis.aps.ui.crypto.BasePgpActivity +import dev.msfjarvis.aps.ui.main.LaunchActivity import java.io.File data class PasswordItem( @@ -35,6 +39,16 @@ data class PasswordItem( return 0 } + /** Creates an [Intent] to launch this [PasswordItem] through the authentication process. */ + fun createAuthEnabledIntent(context: Context): Intent { + val intent = Intent(context, LaunchActivity::class.java) + intent.putExtra("NAME", toString()) + intent.putExtra("FILE_PATH", file.absolutePath) + intent.putExtra("REPO_PATH", PasswordRepository.getRepositoryDirectory().absolutePath) + intent.action = LaunchActivity.ACTION_DECRYPT_PASS + return intent + } + companion object { const val TYPE_CATEGORY = 'c' diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt index fc03b76b..eea7f79a 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt @@ -13,7 +13,6 @@ import android.content.SharedPreferences import android.net.Uri import android.os.Build import android.os.Bundle -import android.text.format.DateUtils import android.view.WindowManager import androidx.annotation.CallSuper import androidx.annotation.StringRes @@ -55,11 +54,6 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou */ val name: String by lazy(LazyThreadSafetyMode.NONE) { File(fullPath).nameWithoutExtension } - /** Get the timestamp for when this file was last modified. */ - val lastChangedString: CharSequence by lazy(LazyThreadSafetyMode.NONE) { - getLastChangedString(intent.getLongExtra("LAST_CHANGED_TIMESTAMP", -1L)) - } - /** [SharedPreferences] instance used by subclasses to persist settings */ val settings: SharedPreferences by lazy(LazyThreadSafetyMode.NONE) { sharedPrefs } @@ -177,15 +171,6 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou return result.getParcelableExtra<PendingIntent>(OpenPgpApi.RESULT_INTENT)!!.intentSender } - /** Gets a relative string describing when this shape was last changed (e.g. "one hour ago") */ - private fun getLastChangedString(timeStamp: Long): CharSequence { - if (timeStamp < 0) { - throw RuntimeException() - } - - return DateUtils.getRelativeTimeSpanString(this, timeStamp, true) - } - /** * Base handling of OpenKeychain errors based on the error contained in [result]. Subclasses can * use this when they want to default to sane error handling. @@ -256,8 +241,6 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou companion object { private const val TAG = "APS/BasePgpActivity" - const val KEY_PWGEN_TYPE_CLASSIC = "classic" - const val KEY_PWGEN_TYPE_XKPASSWD = "xkpasswd" /** Gets the relative path to the repository */ fun getRelativePath(fullPath: String, repositoryPath: String): String = diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/crypto/DecryptActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/crypto/DecryptActivity.kt index 571afb12..72a9a80d 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/crypto/DecryptActivity.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/crypto/DecryptActivity.kt @@ -9,7 +9,6 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem -import android.view.View import androidx.activity.result.IntentSenderRequest import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult import androidx.lifecycle.lifecycleScope @@ -78,11 +77,6 @@ class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound { copyTextToClipboard(name) true } - passwordLastChanged.run { - runCatching { text = resources.getString(R.string.last_changed, lastChangedString) }.onFailure { - visibility = View.GONE - } - } } } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt index c5712353..3740404a 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt @@ -24,6 +24,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.github.michaelbull.result.fold import com.github.michaelbull.result.onFailure import com.github.michaelbull.result.runCatching +import dagger.hilt.android.AndroidEntryPoint import dev.msfjarvis.aps.R import dev.msfjarvis.aps.data.password.PasswordItem import dev.msfjarvis.aps.data.repo.PasswordRepository @@ -42,13 +43,17 @@ import dev.msfjarvis.aps.util.settings.AuthMode import dev.msfjarvis.aps.util.settings.GitSettings import dev.msfjarvis.aps.util.settings.PasswordSortOrder import dev.msfjarvis.aps.util.settings.PreferenceKeys +import dev.msfjarvis.aps.util.shortcuts.ShortcutHandler import dev.msfjarvis.aps.util.viewmodel.SearchableRepositoryViewModel import java.io.File +import javax.inject.Inject import kotlinx.coroutines.launch import me.zhanghai.android.fastscroll.FastScrollerBuilder +@AndroidEntryPoint class PasswordFragment : Fragment(R.layout.password_recycler_view) { + @Inject lateinit var shortcutHandler: ShortcutHandler private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter private lateinit var listener: OnFragmentInteractionListener private lateinit var settings: SharedPreferences @@ -193,11 +198,12 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { } // Called each time the action mode is shown. Always called after onCreateActionMode, - // but - // may be called multiple times if the mode is invalidated. + // but may be called multiple times if the mode is invalidated. override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { - menu.findItem(R.id.menu_edit_password).isVisible = - recyclerAdapter.getSelectedItems().all { it.type == PasswordItem.TYPE_CATEGORY } + val selectedItems = recyclerAdapter.getSelectedItems() + menu.findItem(R.id.menu_edit_password).isVisible = selectedItems.all { it.type == PasswordItem.TYPE_CATEGORY } + menu.findItem(R.id.menu_pin_password).isVisible = + selectedItems.size == 1 && selectedItems[0].type == PasswordItem.TYPE_PASSWORD return true } @@ -219,6 +225,11 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { mode.finish() false } + R.id.menu_pin_password -> { + val passwordItem = recyclerAdapter.getSelectedItems()[0] + shortcutHandler.addPinnedShortcut(passwordItem, passwordItem.createAuthEnabledIntent(requireContext())) + false + } else -> false } } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt index 3339fc04..8ab69552 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt @@ -6,6 +6,7 @@ package dev.msfjarvis.aps.ui.passwords import android.Manifest import android.annotation.SuppressLint +import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Bundle @@ -26,9 +27,7 @@ import androidx.lifecycle.lifecycleScope import com.github.ajalt.timberkt.d import com.github.ajalt.timberkt.e import com.github.ajalt.timberkt.i -import com.github.ajalt.timberkt.w import com.github.michaelbull.result.fold -import com.github.michaelbull.result.getOr import com.github.michaelbull.result.onFailure import com.github.michaelbull.result.runCatching import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -44,7 +43,6 @@ import dev.msfjarvis.aps.ui.dialogs.BasicBottomSheet import dev.msfjarvis.aps.ui.dialogs.FolderCreationDialogFragment import dev.msfjarvis.aps.ui.folderselect.SelectFolderActivity import dev.msfjarvis.aps.ui.git.base.BaseGitActivity -import dev.msfjarvis.aps.ui.main.LaunchActivity import dev.msfjarvis.aps.ui.onboarding.activity.OnboardingActivity import dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity import dev.msfjarvis.aps.ui.settings.SettingsActivity @@ -69,7 +67,6 @@ import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.eclipse.jgit.api.Git const val PASSWORD_FRAGMENT_TAG = "PasswordsList" @@ -403,37 +400,10 @@ class PasswordStore : BaseGitActivity() { return fullPath.replace(repositoryPath, "").replace("/+".toRegex(), "/") } - private fun getLastChangedTimestamp(fullPath: String): Long { - val repoPath = PasswordRepository.getRepositoryDirectory() - val repository = PasswordRepository.getRepository(repoPath) - if (repository == null) { - d { "getLastChangedTimestamp: No git repository" } - return File(fullPath).lastModified() - } - val git = Git(repository) - val relativePath = getRelativePath(fullPath, repoPath.absolutePath).substring(1) // Removes leading '/' - return runCatching { - val iterator = git.log().addPath(relativePath).call().iterator() - if (!iterator.hasNext()) { - w { "getLastChangedTimestamp: No commits for file: $relativePath" } - return -1 - } - iterator.next().commitTime.toLong() * 1000 - } - .getOr(-1) - } - fun decryptPassword(item: PasswordItem) { - val decryptIntent = Intent(this, DecryptActivity::class.java) - val authDecryptIntent = Intent(this, LaunchActivity::class.java) - for (intent in arrayOf(decryptIntent, authDecryptIntent)) { - intent.putExtra("NAME", item.toString()) - intent.putExtra("FILE_PATH", item.file.absolutePath) - intent.putExtra("REPO_PATH", PasswordRepository.getRepositoryDirectory().absolutePath) - intent.putExtra("LAST_CHANGED_TIMESTAMP", getLastChangedTimestamp(item.file.absolutePath)) - } - // Needs an action to be a shortcut intent - authDecryptIntent.action = LaunchActivity.ACTION_DECRYPT_PASS + val authDecryptIntent = item.createAuthEnabledIntent(this) + val decryptIntent = + (authDecryptIntent.clone() as Intent).setComponent(ComponentName(this, DecryptActivity::class.java)) startActivity(decryptIntent) diff --git a/app/src/main/res/drawable/ic_push_pin_24dp.xml b/app/src/main/res/drawable/ic_push_pin_24dp.xml new file mode 100644 index 00000000..f1e14a86 --- /dev/null +++ b/app/src/main/res/drawable/ic_push_pin_24dp.xml @@ -0,0 +1,11 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M16,9V4l1,0c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H7C6.45,2 6,2.45 6,3v0c0,0.55 0.45,1 1,1l1,0v5c0,1.66 -1.34,3 -3,3h0v2h5.97v7l1,1l1,-1v-7H19v-2h0C17.34,12 16,10.66 16,9z" + android:fillType="evenOdd"/> +</vector> diff --git a/app/src/main/res/layout/decrypt_layout.xml b/app/src/main/res/layout/decrypt_layout.xml index 63ec9536..f705558a 100644 --- a/app/src/main/res/layout/decrypt_layout.xml +++ b/app/src/main/res/layout/decrypt_layout.xml @@ -38,19 +38,6 @@ app:layout_constraintTop_toBottomOf="@id/password_category" tools:text="PASSWORD FILE NAME HERE" /> - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/password_last_changed" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginStart="16dp" - android:textColor="?android:attr/textColor" - android:textIsSelectable="false" - android:textSize="18sp" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/password_file" - tools:text="LAST CHANGED HERE" /> - <androidx.appcompat.widget.AppCompatImageView android:id="@+id/divider" @@ -59,7 +46,7 @@ android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:src="@drawable/divider" - app:layout_constraintTop_toBottomOf="@id/password_last_changed" + app:layout_constraintTop_toBottomOf="@id/password_file" tools:ignore="ContentDescription" /> <androidx.recyclerview.widget.RecyclerView diff --git a/app/src/main/res/menu/context_pass.xml b/app/src/main/res/menu/context_pass.xml index 1ed6850b..2c6db5ff 100644 --- a/app/src/main/res/menu/context_pass.xml +++ b/app/src/main/res/menu/context_pass.xml @@ -25,4 +25,10 @@ android:icon="@drawable/ic_edit_24dp" android:title="@string/edit" app:showAsAction="ifRoom" /> + + <item + android:id="@+id/menu_pin_password" + android:icon="@drawable/ic_push_pin_24dp" + android:title="@string/place_shortcut_on_home_screen" + app:showAsAction="ifRoom" /> </menu> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e077bf11..bb736dc8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -405,5 +405,6 @@ <string name="otp_import_manual_hint_secret">Secret</string> <string name="otp_import_manual_hint_account">Account</string> <string name="gpg_key_select_mandatory">Selecting a GPG key is necessary to proceed</string> + <string name="place_shortcut_on_home_screen">Place shortcut on home screen</string> </resources> |