aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/data/password/PasswordItem.kt14
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/crypto/BasePgpActivity.kt17
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/crypto/DecryptActivity.kt6
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordFragment.kt19
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt38
-rw-r--r--app/src/main/res/drawable/ic_push_pin_24dp.xml11
-rw-r--r--app/src/main/res/layout/decrypt_layout.xml15
-rw-r--r--app/src/main/res/menu/context_pass.xml6
-rw-r--r--app/src/main/res/values/strings.xml1
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>