summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorNosweh <62889203+Nosweh@users.noreply.github.com>2020-08-28 17:31:40 +0200
committerGitHub <noreply@github.com>2020-08-28 21:01:40 +0530
commit0f0d1994e589b4f2b2603c882f52c79e2307a4f7 (patch)
treeba6d5d5e80f9993ce8d21ea87d2ab687d1675ebb /app
parent88b1de2b509c007171b432da1d9b4b4761509def (diff)
Add Activity to view the Git commit log (#1056)
Diffstat (limited to 'app')
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt1
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt68
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/log/GitCommit.kt18
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/log/GitLogActivity.kt38
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/log/GitLogAdapter.kt56
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt53
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt23
-rw-r--r--app/src/main/res/layout/activity_git_config.xml38
-rw-r--r--app/src/main/res/layout/activity_git_log.xml22
-rw-r--r--app/src/main/res/layout/git_log_row_layout.xml45
-rw-r--r--app/src/main/res/values-de/strings.xml2
-rw-r--r--app/src/main/res/values-es/strings.xml2
-rw-r--r--app/src/main/res/values-fr/strings.xml2
-rw-r--r--app/src/main/res/values-pt-rBR/strings.xml2
-rw-r--r--app/src/main/res/values-ru/strings.xml2
-rw-r--r--app/src/main/res/values/strings.xml14
17 files changed, 340 insertions, 50 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index dae4466b..cbacda10 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -66,6 +66,10 @@
android:windowSoftInputMode="adjustResize" />
<activity
+ android:name=".git.log.GitLogActivity"
+ android:label="@string/title_activity_git_log" />
+
+ <activity
android:name=".UserPreference"
android:label="@string/action_settings"
android:parentActivityName=".PasswordStore" />
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt
index d9afc7c9..6a0d707c 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt
@@ -48,6 +48,7 @@ import com.zeapo.pwdstore.crypto.BasePgpActivity.Companion.getLongName
import com.zeapo.pwdstore.crypto.DecryptActivity
import com.zeapo.pwdstore.crypto.PasswordCreationActivity
import com.zeapo.pwdstore.git.BaseGitActivity
+import com.zeapo.pwdstore.git.log.GitLogActivity
import com.zeapo.pwdstore.git.GitOperationActivity
import com.zeapo.pwdstore.git.GitServerConfigActivity
import com.zeapo.pwdstore.git.config.AuthMode
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt
index 9205e7fc..89376bfd 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt
@@ -4,20 +4,24 @@
*/
package com.zeapo.pwdstore.git
+import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.util.Patterns
import androidx.core.os.postDelayed
import androidx.lifecycle.lifecycleScope
+import com.github.ajalt.timberkt.e
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.databinding.ActivityGitConfigBinding
import com.zeapo.pwdstore.git.config.GitSettings
+import com.zeapo.pwdstore.git.log.GitLogActivity
import com.zeapo.pwdstore.utils.PasswordRepository
import com.zeapo.pwdstore.utils.viewBinding
import kotlinx.coroutines.launch
import org.eclipse.jgit.lib.Constants
+import org.eclipse.jgit.lib.Repository
class GitConfigActivity : BaseGitActivity() {
@@ -33,23 +37,7 @@ class GitConfigActivity : BaseGitActivity() {
else
binding.gitUserName.setText(GitSettings.authorName)
binding.gitUserEmail.setText(GitSettings.authorEmail)
- val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory())
- if (repo != null) {
- try {
- val objectId = repo.resolve(Constants.HEAD)
- val ref = repo.getRef("refs/heads/${GitSettings.branch}")
- val head = if (ref.objectId.equals(objectId)) ref.name else "DETACHED"
- binding.gitCommitHash.text = String.format("%s (%s)", objectId.abbreviate(8).name(), head)
-
- // enable the abort button only if we're rebasing
- val isRebasing = repo.repositoryState.isRebasing
- binding.gitAbortRebase.isEnabled = isRebasing
- binding.gitAbortRebase.alpha = if (isRebasing) 1.0f else 0.5f
- } catch (ignored: Exception) {
- }
- }
- binding.gitAbortRebase.setOnClickListener { lifecycleScope.launch { launchGitOperation(BREAK_OUT_OF_DETACHED) } }
- binding.gitResetToRemote.setOnClickListener { lifecycleScope.launch { launchGitOperation(REQUEST_RESET) } }
+ setupTools()
binding.saveButton.setOnClickListener {
val email = binding.gitUserEmail.text.toString().trim()
val name = binding.gitUserName.text.toString().trim()
@@ -66,4 +54,50 @@ class GitConfigActivity : BaseGitActivity() {
}
}
}
+
+ /**
+ * Sets up the UI components of the tools section.
+ */
+ private fun setupTools() {
+ val repo = PasswordRepository.getRepository(null)
+ if (repo != null) {
+ binding.gitHeadStatus.text = headStatusMsg(repo)
+ // enable the abort button only if we're rebasing
+ val isRebasing = repo.repositoryState.isRebasing
+ binding.gitAbortRebase.isEnabled = isRebasing
+ binding.gitAbortRebase.alpha = if (isRebasing) 1.0f else 0.5f
+ }
+ binding.gitLog.setOnClickListener {
+ try {
+ intent = Intent(this, GitLogActivity::class.java)
+ startActivity(intent)
+ } catch (ex: Exception) {
+ e(ex) { "Failed to start GitLogActivity" }
+ }
+ }
+ binding.gitAbortRebase.setOnClickListener { lifecycleScope.launch { launchGitOperation(BREAK_OUT_OF_DETACHED) } }
+ binding.gitResetToRemote.setOnClickListener { lifecycleScope.launch { launchGitOperation(REQUEST_RESET) } }
+ }
+
+ /**
+ * Returns a user-friendly message about the current state of HEAD.
+ *
+ * The state is recognized to be either pointing to a branch or detached.
+ */
+ private fun headStatusMsg(repo: Repository): String {
+ return try {
+ val headRef = repo.getRef(Constants.HEAD)
+ if (headRef.isSymbolic) {
+ val branchName = headRef.target.name
+ val shortBranchName = Repository.shortenRefName(branchName)
+ getString(R.string.git_head_on_branch, shortBranchName)
+ } else {
+ val commitHash = headRef.objectId.abbreviate(8).name()
+ getString(R.string.git_head_detached, commitHash)
+ }
+ } catch (ex: Exception) {
+ e(ex) { "Error getting HEAD reference" }
+ getString(R.string.git_head_missing)
+ }
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/log/GitCommit.kt b/app/src/main/java/com/zeapo/pwdstore/git/log/GitCommit.kt
new file mode 100644
index 00000000..d2425592
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/git/log/GitCommit.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.git.log
+
+import java.util.Date
+
+/**
+ * Basic information about a git commit.
+ *
+ * @property hash full-length hash of the commit object.
+ * @property shortMessage the commit's short message (i.e. title line).
+ * @property authorName name of the commit's author without email address.
+ * @property time time when the commit was created.
+ */
+data class GitCommit(val hash: String, val shortMessage: String, val authorName: String, val time: Date)
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogActivity.kt
new file mode 100644
index 00000000..8c1c0f09
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogActivity.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.git.log
+
+import android.os.Bundle
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.zeapo.pwdstore.databinding.ActivityGitLogBinding
+import com.zeapo.pwdstore.git.BaseGitActivity
+import com.zeapo.pwdstore.utils.viewBinding
+
+/**
+ * Displays the repository's git commits in git-log fashion.
+ *
+ * It provides basic information about each commit by way of a non-interactive RecyclerView.
+ */
+class GitLogActivity : BaseGitActivity() {
+
+ private val binding by viewBinding(ActivityGitLogBinding::inflate)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ createRecyclerView()
+ }
+
+ private fun createRecyclerView() {
+ binding.gitLogRecyclerView.apply {
+ setHasFixedSize(true)
+ addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
+ adapter = GitLogAdapter()
+ }
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogAdapter.kt b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogAdapter.kt
new file mode 100644
index 00000000..a15e7f7e
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogAdapter.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.git.log
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.github.ajalt.timberkt.e
+import com.zeapo.pwdstore.databinding.GitLogRowLayoutBinding
+import java.text.DateFormat
+import java.util.Date
+
+private fun shortHash(hash: String): String {
+ return hash.substring(0 until 8)
+}
+
+private fun stringFrom(date: Date): String {
+ return DateFormat.getDateTimeInstance().format(date)
+}
+
+/**
+ * @see GitLogActivity
+ */
+class GitLogAdapter : RecyclerView.Adapter<GitLogAdapter.ViewHolder>() {
+
+ private val model = GitLogModel()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ val binding = GitLogRowLayoutBinding.inflate(inflater, parent, false)
+ return ViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
+ val commit = model.get(position)
+ if (commit == null) {
+ e { "There is no git commit for view holder at position $position." }
+ return
+ }
+ viewHolder.bind(commit)
+ }
+
+ override fun getItemCount() = model.size
+
+ class ViewHolder(private val binding: GitLogRowLayoutBinding) : RecyclerView.ViewHolder(binding.root) {
+
+ fun bind(commit: GitCommit) = with(binding) {
+ gitLogRowMessage.text = commit.shortMessage
+ gitLogRowHash.text = shortHash(commit.hash)
+ gitLogRowTime.text = stringFrom(commit.time)
+ }
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt
new file mode 100644
index 00000000..22c1ec78
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.git.log
+
+import com.github.ajalt.timberkt.e
+import com.zeapo.pwdstore.utils.PasswordRepository
+import com.zeapo.pwdstore.utils.hash
+import com.zeapo.pwdstore.utils.time
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.revwalk.RevCommit
+
+private fun commits(): Iterable<RevCommit> {
+ val repo = PasswordRepository.getRepository(null)
+ if (repo == null) {
+ e { "Could not access git repository" }
+ return listOf()
+ }
+ return try {
+ Git(repo).log().call()
+ } catch (exc: Exception) {
+ e(exc) { "Failed to obtain git commits" }
+ listOf()
+ }
+}
+
+/**
+ * Provides [GitCommit]s from a git-log of the password git repository.
+ *
+ * All commits are acquired on the first request to this object.
+ */
+class GitLogModel {
+
+ // All commits are acquired here at once. Acquiring the commits in batches would not have been
+ // entirely sensible because the amount of computation required to obtain commit number n from
+ // the log includes the amount of computation required to obtain commit number n-1 from the log.
+ // This is because the commit graph is walked from HEAD to the last commit to obtain.
+ // Additionally, tests with 1000 commits in the log have not produced a significant delay in the
+ // user experience.
+ private val cache: MutableList<GitCommit> by lazy {
+ commits().map {
+ GitCommit(it.hash, it.shortMessage, it.authorIdent.name, it.time)
+ }.toMutableList()
+ }
+ val size = cache.size
+
+ fun get(index: Int): GitCommit? {
+ if (index >= size) e { "Cannot get git commit with index $index. There are only $size." }
+ return cache.getOrNull(index)
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
index 561b8d99..edc01776 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
@@ -28,6 +28,9 @@ import com.zeapo.pwdstore.git.GitCommandExecutor
import com.zeapo.pwdstore.git.operation.GitOperation
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepositoryDirectory
import java.io.File
+import java.util.Date
+import org.eclipse.jgit.lib.ObjectId
+import org.eclipse.jgit.revwalk.RevCommit
const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain"
@@ -162,3 +165,23 @@ val Context.autofillManager: AutofillManager?
fun File.isInsideRepository(): Boolean {
return canonicalPath.contains(getRepositoryDirectory().canonicalPath)
}
+
+/**
+ * Unique SHA-1 hash of this commit as hexadecimal string.
+ *
+ * @see RevCommit.id
+ */
+val RevCommit.hash: String
+ get() = ObjectId.toString(id)
+
+/**
+ * Time this commit was made with second precision.
+ *
+ * @see RevCommit.commitTime
+ */
+val RevCommit.time: Date
+ get() {
+ val epochSeconds = commitTime.toLong()
+ val epochMilliseconds = epochSeconds * 1000
+ return Date(epochMilliseconds)
+ }
diff --git a/app/src/main/res/layout/activity_git_config.xml b/app/src/main/res/layout/activity_git_config.xml
index df1874a9..1d495250 100644
--- a/app/src/main/res/layout/activity_git_config.xml
+++ b/app/src/main/res/layout/activity_git_config.xml
@@ -17,7 +17,7 @@
android:id="@+id/username_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
+ android:layout_margin="@dimen/normal_margin"
android:hint="@string/git_user_name_hint"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@@ -35,7 +35,7 @@
android:id="@+id/email_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
+ android:layout_margin="@dimen/normal_margin"
android:hint="@string/git_user_email"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/username_input_layout">
@@ -52,7 +52,7 @@
android:id="@+id/save_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
+ android:layout_margin="@dimen/normal_margin"
android:text="@string/crypto_save"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/email_input_layout" />
@@ -62,45 +62,43 @@
style="@style/TextAppearance.MaterialComponents.Headline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:text="@string/hackish_tools"
+ android:layout_margin="@dimen/normal_margin"
+ android:text="@string/git_tools"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/save_button" />
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/commit_hash_label"
+ android:id="@+id/git_head_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:text="@string/commit_hash"
+ android:layout_margin="@dimen/normal_margin"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/git_tools_title" />
+ app:layout_constraintTop_toBottomOf="@id/git_tools_title"
+ tools:text="HEAD status" />
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/git_commit_hash"
- android:layout_width="wrap_content"
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/git_log"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:textStyle="bold"
- app:layout_constraintStart_toEndOf="@id/commit_hash_label"
- app:layout_constraintTop_toBottomOf="@id/git_tools_title"
- tools:text="HASH" />
+ android:layout_margin="@dimen/normal_margin"
+ android:text="@string/git_log"
+ app:layout_constraintTop_toBottomOf="@+id/git_head_status" />
<com.google.android.material.button.MaterialButton
android:id="@+id/git_abort_rebase"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
+ android:layout_margin="@dimen/normal_margin"
android:text="@string/abort_rebase"
- app:layout_constraintTop_toBottomOf="@id/commit_hash_label" />
+ app:layout_constraintTop_toBottomOf="@+id/git_log" />
<com.google.android.material.button.MaterialButton
android:id="@+id/git_reset_to_remote"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
+ android:layout_margin="@dimen/normal_margin"
android:text="@string/reset_to_remote"
app:layout_constraintTop_toBottomOf="@id/git_abort_rebase" />
diff --git a/app/src/main/res/layout/activity_git_log.xml b/app/src/main/res/layout/activity_git_log.xml
new file mode 100644
index 00000000..96b28487
--- /dev/null
+++ b/app/src/main/res/layout/activity_git_log.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: GPL-3.0-only
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/git_log_recycler_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:scrollbars="vertical"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:context="com.zeapo.pwdstore.git.log.GitLogActivity"
+ tools:listitem="@layout/git_log_row_layout" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/git_log_row_layout.xml b/app/src/main/res/layout/git_log_row_layout.xml
new file mode 100644
index 00000000..5a29f241
--- /dev/null
+++ b/app/src/main/res/layout/git_log_row_layout.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: GPL-3.0-only
+ -->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/activity_vertical_margin"
+ android:paddingVertical="@dimen/activity_horizontal_margin">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/git_log_row_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/normal_margin"
+ android:ellipsize="end"
+ android:maxLines="2"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/git_log_row_hash"
+ tools:text="Commit message" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/git_log_row_hash"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="?attr/colorSecondary"
+ android:textStyle="bold"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="Hash" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/git_log_row_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:alpha="0.5"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="Time" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index fd94c8a9..d5abea1a 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -11,6 +11,7 @@
<string name="dialog_delete">Ordner löschen</string>
<string name="dialog_do_not_delete">Abbruch</string>
<string name="title_activity_git_clone">Repository Informationen</string>
+ <string name="title_activity_git_log">Commit-Log</string>
<!-- Password Store -->
<string name="creation_dialog_text">Bitte klone oder erstelle ein neues Repository, bevor du versuchst ein Passwort hinzuzufügen oder jegliche Synchronisation-Operation durchführst.</string>
<string name="move">Verschieben</string>
@@ -121,6 +122,7 @@
<string name="git_sync">Synchronisiere Repository</string>
<string name="git_pull">Git Pull</string>
<string name="git_push">Git Push</string>
+ <string name="git_log">Commit-Log anzeigen</string>
<string name="show_password_pref_title">Zeige das Password</string>
<string name="show_password_pref_summary">Soll das entschlüsselte Passwort sichtbar sein? Dies deaktiviert nicht das Kopieren.</string>
<string name="show_extra_content_pref_title">Zeige weiteren Inhalt</string>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index ff04cf3e..03e153e9 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -178,7 +178,5 @@
<string name="git_push_generic_error">El envío fue rechazado por el servidor, la razón:</string>
<string name="jgit_error_push_dialog_text">Ocurrió un error durante el envío:</string>
<string name="git_operation_remember_passphrase">Recordar contraseñagit (inseguro)</string>
- <string name="hackish_tools">Hackish tools</string>
<string name="abort_rebase">Abortar rebase</string>
- <string name="commit_hash">Hash del commit</string>
</resources>
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 9f9e1768..db98bfd8 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -178,6 +178,4 @@
<string name="git_push_other_error">Pousser au dépôt distant sans avance rapide rejetée. Vérifiez la variable receive.denyNonFastForwards dans le fichier de configuration du répertoire de destination.</string>
<string name="jgit_error_push_dialog_text">Une erreur s\'est produite lors de l\'opération de poussée:</string>
<string name="git_operation_remember_passphrase">Se rappeler de la phrase secrète dans la configuration de l\'application (peu sûr)</string>
- <string name="hackish_tools">Outils de hack</string>
- <string name="commit_hash">Commettre la clé</string>
</resources>
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index a7f3e046..2e07190a 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -248,10 +248,8 @@
<string name="clear_saved_passphrase_ssh">Limpar a frase secreta salva para chave SSH local</string>
<string name="clear_saved_passphrase_https">Limpar senha HTTPS salva</string>
<string name="git_operation_remember_passphrase">Lembrar senha da chave</string>
- <string name="hackish_tools">Ferramentas de hackers</string>
<string name="abort_rebase">Abortar rebase e realizar push do novo branch</string>
<string name="reset_to_remote">Hard reset no branch remoto</string>
- <string name="commit_hash">Commit hash</string>
<string name="openkeychain_ssh_api_connect_fail">Falha ao conectar ao serviço de API SSH do OpenKeychain.</string>
<string name="no_ssh_api_provider">Nenhum provedor de API SSH encontrado. O OpenKeychain está instalado?</string>
<string name="ssh_api_pending_intent_failed">SSH API pendente falhou</string>
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 3fab8cf9..d1fbc215 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -233,10 +233,8 @@
<string name="git_push_other_error">Удаленный репозиторий отклонил запись изменений без быстрой перемотки вперед. Проверьте переменную receive.denyNonFastForwards в файле конфигурации репозитория назначения.</string>
<string name="jgit_error_push_dialog_text">В хоте операции записи изменений возникла ошибка:</string>
<string name="git_operation_remember_passphrase">Заполнить парольную фразу в конфигурации приложнеия (небезопасно)</string>
- <string name="hackish_tools">Костыльные инструменты</string>
<string name="abort_rebase">Прервать перебазирование и записать изменения в новую ветку</string>
<string name="reset_to_remote">Полный сброс до состояния удаленной ветки</string>
- <string name="commit_hash">Хэш-сумма изменений</string>
<string name="openkeychain_ssh_api_connect_fail">Ошибка при подключении к сервису OpenKeychain SSH API</string>
<string name="no_ssh_api_provider">Не найдено SSH API провайдеров. OpenKeychain установлен?</string>
<string name="ssh_api_pending_intent_failed">Ожидаемое намерение SSH API не удалось</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a6e33047..72d4d5db 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -20,6 +20,7 @@
<string name="dialog_do_not_delete">Cancel</string>
<string name="title_activity_git_clone">Repository information</string>
<string name="title_activity_git_config" translatable="false">Git configuration</string>
+ <string name="title_activity_git_log">Commit log</string>
<!-- Password Store -->
<string name="creation_dialog_text">Please clone or create a new repository below before trying to add a password or running any synchronization operation.</string>
@@ -117,8 +118,8 @@
<!-- Preferences -->
<string name="pref_repository_title">Repository</string>
- <string name="pref_edit_server_info">Edit git server settings</string>
- <string name="pref_edit_git_config">Git utils</string>
+ <string name="pref_edit_server_info">Edit Git server settings</string>
+ <string name="pref_edit_git_config">Local Git config &amp; utilities</string>
<string name="pref_ssh_title">Import SSH key</string>
<string name="pref_ssh_keygen_title">Generate SSH key pair</string>
<string name="pref_ssh_see_key_title">View generated public SSH key</string>
@@ -217,6 +218,7 @@
<string name="git_pull">Pull from remote</string>
<string name="git_push">Push to remote</string>
<string name="git_push_up_to_date">Everything up-to-date</string>
+ <string name="git_log">Show commit log</string>
<string name="show_password_pref_title">Show the password</string>
<string name="show_password_pref_summary">Control the visibility of the passwords once decrypted. This does not disable copying to clipboard.</string>
<string name="show_extra_content_pref_title">Show extra content</string>
@@ -281,10 +283,12 @@
<string name="clear_saved_passphrase_ssh">Clear saved passphrase for local SSH key</string>
<string name="clear_saved_passphrase_https">Clear saved HTTPS password</string>
<string name="git_operation_remember_passphrase">Remember key passphrase</string>
- <string name="hackish_tools">Hackish tools</string>
+ <string name="git_tools">Utilities</string>
<string name="abort_rebase">Abort rebase and push new branch</string>
<string name="reset_to_remote">Hard reset to remote branch</string>
- <string name="commit_hash">Commit hash</string>
+ <string name="git_head_on_branch">On branch %1$s</string>
+ <string name="git_head_detached">HEAD detached at %1$s</string>
+ <string name="git_head_missing">Unable to locate HEAD</string>
<string name="openkeychain_ssh_api_connect_fail">Failed to connect to OpenKeychain SSH API service.</string>
<string name="no_ssh_api_provider">No SSH API provider found. Is OpenKeychain installed?</string>
<string name="ssh_api_pending_intent_failed">SSH API pending intent failed</string>
@@ -393,6 +397,6 @@
<!-- GPG key selection in folder creation -->
<string name="folder_creation_err_file_exists">A file by that name already exists</string>
<string name="folder_creation_err_folder_exists">A folder by that name already exists</string>
- <string name="xkpwgen_extrachars_label" >Digits/Symbols (d/s)</string>
+ <string name="xkpwgen_extrachars_label">Digits/Symbols (d/s)</string>
<string name="xk_numbers_symbols_append_default">ds</string>
</resources>