Treewide codestyle cleanup (#765)
- Updated gitignore and checked in the IDE's codestyle config - Removed spotless as the underlying ktlint backend has failed to resolve the super frustrating import order bug[1] in nearly a year - Reformat the entire codebase based on the previously committed code style configuration. 1: https://github.com/pinterest/ktlint/issues/527
This commit is contained in:
parent
94dc92f8d7
commit
041cf00510
136 changed files with 1603 additions and 1255 deletions
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
## :pencil: Checklist
|
## :pencil: Checklist
|
||||||
<!--- Put an `x` in the boxes that apply -->
|
<!--- Put an `x` in the boxes that apply -->
|
||||||
- [ ] I ran `./gradlew spotlessApply` before submitting the PR
|
- [ ] I formatted the code with the IDE's reformat action (Ctrl + Shift + L/Cmd + Shift + L)
|
||||||
- [ ] I reviewed submitted code
|
- [ ] I reviewed submitted code
|
||||||
|
|
||||||
|
|
||||||
|
|
3
.github/workflows/deploy_snapshot.yml
vendored
3
.github/workflows/deploy_snapshot.yml
vendored
|
@ -28,9 +28,6 @@ jobs:
|
||||||
- name: Download gradle dependencies
|
- name: Download gradle dependencies
|
||||||
run: ./gradlew dependencies
|
run: ./gradlew dependencies
|
||||||
|
|
||||||
- name: Validate codestyle with Spotless
|
|
||||||
run: ./gradlew spotlessCheck
|
|
||||||
|
|
||||||
- name: Build release app
|
- name: Build release app
|
||||||
run: ./gradlew :app:assembleRelease
|
run: ./gradlew :app:assembleRelease
|
||||||
env:
|
env:
|
||||||
|
|
2
.github/workflows/pull_request.yml
vendored
2
.github/workflows/pull_request.yml
vendored
|
@ -52,7 +52,7 @@ jobs:
|
||||||
${{ runner.os }}-gradlebuildcache-
|
${{ runner.os }}-gradlebuildcache-
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: ./gradlew spotlessCheck test${{ matrix.variant }} lint${{ matrix.variant}} -Dpre-dex=false
|
run: ./gradlew test${{ matrix.variant }} lint${{ matrix.variant}} -Dpre-dex=false
|
||||||
|
|
||||||
- name: Run instrumentation tests
|
- name: Run instrumentation tests
|
||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
|
|
175
.gitignore
vendored
175
.gitignore
vendored
|
@ -1,42 +1,153 @@
|
||||||
#Android specific
|
|
||||||
bin
|
|
||||||
gen
|
|
||||||
obj
|
|
||||||
lint.xml
|
|
||||||
local.properties
|
|
||||||
release.properties
|
|
||||||
ant.properties
|
|
||||||
*.class
|
|
||||||
*.apk
|
|
||||||
!app-release.apk
|
|
||||||
!app-debug.apk
|
|
||||||
|
|
||||||
#Gradle
|
# Created by https://www.gitignore.io/api/androidstudio,gradle
|
||||||
|
# Edit at https://www.gitignore.io/?templates=androidstudio,gradle
|
||||||
|
|
||||||
|
### Gradle ###
|
||||||
.gradle
|
.gradle
|
||||||
build
|
build/
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
#Maven
|
# Ignore Gradle GUI config
|
||||||
target
|
gradle-app.setting
|
||||||
pom.xml.*
|
|
||||||
|
|
||||||
#Eclipse
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
.project
|
!gradle-wrapper.jar
|
||||||
.classpath
|
|
||||||
.settings
|
|
||||||
.metadata
|
|
||||||
|
|
||||||
#Eclipse/Gradle integration
|
# Cache of project
|
||||||
libs
|
.gradletasknamecache
|
||||||
project.properties
|
|
||||||
|
|
||||||
#IntelliJ IDEA
|
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||||
.idea
|
# gradle/wrapper/gradle-wrapper.properties
|
||||||
*.iml
|
|
||||||
|
|
||||||
# Visual Studio Code
|
### Gradle Patch ###
|
||||||
.vscode/
|
**/build/
|
||||||
|
|
||||||
captures/
|
### AndroidStudio ###
|
||||||
|
# Covers files to be ignored for android development using Android Studio.
|
||||||
|
|
||||||
|
# Built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle/
|
||||||
|
|
||||||
|
# Signing files
|
||||||
|
.signing/
|
||||||
keystore.*
|
keystore.*
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
proguard/
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
/*/build/
|
||||||
|
/*/local.properties
|
||||||
|
/*/out
|
||||||
|
/*/*/build
|
||||||
|
/*/*/production
|
||||||
|
captures/
|
||||||
|
.navigation/
|
||||||
|
*.ipr
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Android Patch
|
||||||
|
gen-external-apklibs
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
.externalNativeBuild
|
||||||
|
|
||||||
|
# NDK
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# IntelliJ IDEA
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# User-specific configurations
|
||||||
|
.idea/caches/
|
||||||
|
.idea/libraries/
|
||||||
|
.idea/shelf/
|
||||||
|
.idea/workspace.xml
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/.name
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/copyright/profiles_settings.xml
|
||||||
|
.idea/encodings.xml
|
||||||
|
.idea/misc.xml
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/scopes/scope_settings.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
.idea/vcs.xml
|
||||||
|
.idea/jsLibraryMappings.xml
|
||||||
|
.idea/datasources.xml
|
||||||
|
.idea/dataSources.ids
|
||||||
|
.idea/sqlDataSources.xml
|
||||||
|
.idea/dynamic.xml
|
||||||
|
.idea/uiDesigner.xml
|
||||||
|
.idea/assetWizardSettings.xml
|
||||||
|
|
||||||
|
# OS-specific files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Legacy Eclipse project files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
|
||||||
|
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/mongoSettings.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
### AndroidStudio Patch ###
|
||||||
|
|
||||||
|
!/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/androidstudio,gradle
|
||||||
|
|
168
.idea/codeStyles/Project.xml
generated
Normal file
168
.idea/codeStyles/Project.xml
generated
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="AUTODETECT_INDENTS" value="false" />
|
||||||
|
<option name="LINE_SEPARATOR" value=" " />
|
||||||
|
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
|
||||||
|
<option name="FORMATTER_TAGS_ENABLED" value="true" />
|
||||||
|
<option name="SOFT_MARGINS" value="100" />
|
||||||
|
<JavaCodeStyleSettings>
|
||||||
|
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
|
||||||
|
</JavaCodeStyleSettings>
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
|
<value />
|
||||||
|
</option>
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="true" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="true" />
|
||||||
|
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="true" />
|
||||||
|
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="true" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="true" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="true" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_ELVIS" value="true" />
|
||||||
|
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="0" />
|
||||||
|
<option name="IF_RPAREN_ON_NEW_LINE" value="false" />
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</JetCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="JAVA">
|
||||||
|
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="XML">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
<arrangement>
|
||||||
|
<rules>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:android</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:id</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:name</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>name</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>style</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
</rules>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
<option name="RIGHT_MARGIN" value="100" />
|
||||||
|
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
||||||
|
<option name="CALL_PARAMETERS_WRAP" value="0" />
|
||||||
|
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
|
||||||
|
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
|
||||||
|
<option name="METHOD_PARAMETERS_WRAP" value="0" />
|
||||||
|
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
|
||||||
|
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
|
||||||
|
<option name="EXTENDS_LIST_WRAP" value="0" />
|
||||||
|
<option name="METHOD_CALL_CHAIN_WRAP" value="0" />
|
||||||
|
<option name="ASSIGNMENT_WRAP" value="0" />
|
||||||
|
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<option name="WRAP_ON_TYPING" value="0" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
6
.idea/copyright/APS.xml
generated
Normal file
6
.idea/copyright/APS.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="CopyrightManager">
|
||||||
|
<copyright>
|
||||||
|
<option name="notice" value="/* * Copyright © 2014-&#36;today.year The Android Password Store Authors. All Rights Reserved. * SPDX-License-Identifier: GPL-3.0-only */ " />
|
||||||
|
<option name="myName" value="APS" />
|
||||||
|
</copyright>
|
||||||
|
</component>
|
22
.idea/gradle.xml
generated
Normal file
22
.idea/gradle.xml
generated
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
|
<component name="GradleSettings">
|
||||||
|
<option name="linkedExternalProjectsSettings">
|
||||||
|
<GradleProjectSettings>
|
||||||
|
<option name="testRunner" value="PLATFORM" />
|
||||||
|
<option name="distributionType" value="LOCAL" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="gradleHome" value="$USER_HOME$/.sdkman/candidates/gradle/current" />
|
||||||
|
<option name="modules">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
<option value="$PROJECT_DIR$/app" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
<option name="useQualifiedModuleNames" value="true" />
|
||||||
|
</GradleProjectSettings>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
12
.idea/runConfigurations.xml
generated
Normal file
12
.idea/runConfigurations.xml
generated
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RunConfigurationProducerService">
|
||||||
|
<option name="ignoredProducers">
|
||||||
|
<set>
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -4,11 +4,11 @@
|
||||||
*/
|
*/
|
||||||
package com.zeapo.pwdstore
|
package com.zeapo.pwdstore
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class PasswordEntryTest {
|
class PasswordEntryTest {
|
||||||
@Test fun testGetPassword() {
|
@Test fun testGetPassword() {
|
||||||
|
@ -39,13 +39,13 @@ class PasswordEntryTest {
|
||||||
assertEquals("username", PasswordEntry("\n${field.toUpperCase()} username").username)
|
assertEquals("username", PasswordEntry("\n${field.toUpperCase()} username").username)
|
||||||
}
|
}
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"username",
|
"username",
|
||||||
PasswordEntry("secret\nextra\nlogin: username\ncontent\n").username)
|
PasswordEntry("secret\nextra\nlogin: username\ncontent\n").username)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"username",
|
"username",
|
||||||
PasswordEntry("\nextra\nusername: username\ncontent\n").username)
|
PasswordEntry("\nextra\nusername: username\ncontent\n").username)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"username", PasswordEntry("\nUSERNaMe: username\ncontent\n").username)
|
"username", PasswordEntry("\nUSERNaMe: username\ncontent\n").username)
|
||||||
assertEquals("username", PasswordEntry("\nlogin: username").username)
|
assertEquals("username", PasswordEntry("\nlogin: username").username)
|
||||||
assertEquals("foo@example.com", PasswordEntry("\nemail: foo@example.com").username)
|
assertEquals("foo@example.com", PasswordEntry("\nemail: foo@example.com").username)
|
||||||
assertEquals("username", PasswordEntry("\nidentity: username\nlogin: another_username").username)
|
assertEquals("username", PasswordEntry("\nidentity: username\nlogin: another_username").username)
|
||||||
|
@ -75,7 +75,7 @@ class PasswordEntryTest {
|
||||||
|
|
||||||
@Test fun testTotpUriInContent() {
|
@Test fun testTotpUriInContent() {
|
||||||
val entry = PasswordEntry(
|
val entry = PasswordEntry(
|
||||||
"secret\nusername: test\notpauth://totp/test?secret=JBSWY3DPEHPK3PXP")
|
"secret\nusername: test\notpauth://totp/test?secret=JBSWY3DPEHPK3PXP")
|
||||||
assertTrue(entry.hasTotp())
|
assertTrue(entry.hasTotp())
|
||||||
assertEquals("JBSWY3DPEHPK3PXP", entry.totpSecret)
|
assertEquals("JBSWY3DPEHPK3PXP", entry.totpSecret)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ class PasswordEntryTest {
|
||||||
|
|
||||||
@Test fun testHotpUriInContent() {
|
@Test fun testHotpUriInContent() {
|
||||||
val entry = PasswordEntry(
|
val entry = PasswordEntry(
|
||||||
"secret\nusername: test\notpauth://hotp/test?secret=JBSWY3DPEHPK3PXP&counter=25")
|
"secret\nusername: test\notpauth://hotp/test?secret=JBSWY3DPEHPK3PXP&counter=25")
|
||||||
assertTrue(entry.hasHotp())
|
assertTrue(entry.hasHotp())
|
||||||
assertEquals("JBSWY3DPEHPK3PXP", entry.hotpSecret)
|
assertEquals("JBSWY3DPEHPK3PXP", entry.hotpSecret)
|
||||||
assertEquals(25, entry.hotpCounter)
|
assertEquals(25, entry.hotpCounter)
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
*/
|
*/
|
||||||
package com.zeapo.pwdstore
|
package com.zeapo.pwdstore
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
private infix fun String.matchedForDomain(domain: String) =
|
private infix fun String.matchedForDomain(domain: String) =
|
||||||
SearchableRepositoryViewModel.generateStrictDomainRegex(domain)?.containsMatchIn(this) == true
|
SearchableRepositoryViewModel.generateStrictDomainRegex(domain)?.containsMatchIn(this) == true
|
||||||
|
|
|
@ -3,23 +3,24 @@
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="110.34687"
|
android:viewportWidth="110.34687"
|
||||||
android:viewportHeight="110.34687">
|
android:viewportHeight="110.34687">
|
||||||
<group android:translateX="24.828047"
|
<group
|
||||||
android:translateY="24.828047">
|
android:translateX="24.828047"
|
||||||
<path
|
android:translateY="24.828047">
|
||||||
android:pathData="m18.8,30.2129v-11.546c0,-6.4144 5.1315,-11.546 11.546,-11.546 6.4144,0 11.546,5.1315 11.546,11.546v11.546"
|
<path
|
||||||
android:strokeWidth="5.349"
|
android:fillColor="#00000000"
|
||||||
android:fillColor="#00000000"
|
android:pathData="m18.8,30.2129v-11.546c0,-6.4144 5.1315,-11.546 11.546,-11.546 6.4144,0 11.546,5.1315 11.546,11.546v11.546"
|
||||||
android:strokeColor="#013e5b"/>
|
android:strokeWidth="5.349"
|
||||||
<path
|
android:strokeColor="#013e5b" />
|
||||||
android:pathData="M15.4099,21.8429L45.2811,21.8429A2.2639,2.2639 0,0 1,47.545 24.1068L47.545,53.977A2.2639,2.2639 0,0 1,45.2811 56.2409L15.4099,56.2409A2.2639,2.2639 0,0 1,13.146 53.977L13.146,24.1068A2.2639,2.2639 0,0 1,15.4099 21.8429z"
|
<path
|
||||||
android:fillColor="#c74c00"/>
|
android:fillColor="#c74c00"
|
||||||
<path
|
android:pathData="M15.4099,21.8429L45.2811,21.8429A2.2639,2.2639 0,0 1,47.545 24.1068L47.545,53.977A2.2639,2.2639 0,0 1,45.2811 56.2409L15.4099,56.2409A2.2639,2.2639 0,0 1,13.146 53.977L13.146,24.1068A2.2639,2.2639 0,0 1,15.4099 21.8429z" />
|
||||||
android:pathData="m44.8267,37.6961 l-13.1408,-13.1393c-0.7569,-0.7566 -1.9838,-0.7566 -2.7408,0l-13.08,13.0785c-0.7567,0.7573 -0.7567,1.9846 0,2.7419l13.1415,13.14c0.7572,0.7567 1.9842,0.7567 2.7414,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421"
|
<path
|
||||||
android:strokeWidth=".35344"
|
android:fillColor="#fff"
|
||||||
android:fillColor="#fff"/>
|
android:pathData="m44.8267,37.6961 l-13.1408,-13.1393c-0.7569,-0.7566 -1.9838,-0.7566 -2.7408,0l-13.08,13.0785c-0.7567,0.7573 -0.7567,1.9846 0,2.7419l13.1415,13.14c0.7572,0.7567 1.9842,0.7567 2.7414,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421"
|
||||||
<path
|
android:strokeWidth=".35344" />
|
||||||
android:pathData="m30.3156,23.9881c-0.496,0 -0.992,0.1893 -1.3705,0.5676l-2.7282,2.7288 3.4612,3.4606c0.8044,-0.2715 1.727,-0.0892 2.368,0.5517 0.6237,0.624 0.8361,1.5493 0.5471,2.3828l3.3357,3.3357c0.8076,-0.2777 1.738,-0.098 2.3828,0.5476 0.9008,0.9005 0.9008,2.361 0,3.2615 -1.7823,1.7848 -4.7253,-0.1767 -3.7641,-2.5087l-3.1111,-3.1106c-2.2315,0.5285 -3.8934,-1.2655 -3.149,-3.1674l-0.6863,-0.6863l0,15.9165l5.4913,0l0,-5.8608c-0.0315,-0.7566 1.1201,-0.7566 1.0886,0l0,6.4043c0.0005,0.3013 -0.2438,0.5457 -0.545,0.5455l-6.5804,0c-0.3015,0.0005 -0.546,-0.2441 -0.5456,-0.5455l0,-17.4333c-0.0005,-0.0363 0.0029,-0.0728 0.0097,-0.1085l-1.6444,-1.6444 -9.0106,9.0084c-0.7567,0.7573 -0.7567,1.9848 0,2.7421l13.1415,13.14c0.7572,0.7567 1.9844,0.7567 2.7416,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421l-13.14,-13.1393c-0.3785,-0.3783 -0.8746,-0.5676 -1.3705,-0.5676zM29.9512,39.1825c0.1001,0 0.1808,0.0381 0.2426,0.1146 0.0648,0.0736 0.1326,0.1975 0.2032,0.371 0.0705,0.1706 0.1089,0.2615 0.1146,0.2733 0.0059,-0.0119 0.0424,-0.1026 0.11,-0.2733 0.0707,-0.1705 0.1401,-0.2946 0.2078,-0.371 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2103 0.1592,0.3485 0,0.0676 -0.0179,0.1368 -0.0532,0.2073 -0.0323,0.0707 -0.0777,0.1444 -0.1366,0.2211 -0.056,0.0734 -0.1164,0.1571 -0.1812,0.2513 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0354 0.3004,-0.0354 0.0969,0 0.1762,0.0224 0.238,0.0666 0.0648,0.0442 0.1118,0.1042 0.1413,0.1807 0.0294,0.0734 0.044,0.1544 0.044,0.2426 0,0.1384 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1372 -0.3219,0.1372 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.0386 -0.3045,-0.0446 0.1531,0.2177 0.2534,0.3652 0.3004,0.4417 0.047,0.0736 0.0706,0.1544 0.0706,0.2426 0,0.1412 -0.0533,0.2556 -0.1592,0.3439 -0.1028,0.0853 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0366 -0.2559,-0.11 -0.0646,-0.0767 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0235 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1646 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.11 -0.2513,0.11 -0.15,0 -0.2779,-0.0427 -0.3838,-0.1279 -0.1059,-0.0883 -0.1587,-0.2027 -0.1587,-0.3439 0,-0.0618 0.0156,-0.1263 0.0481,-0.194 0.0323,-0.0707 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1532 0.2206,-0.3091 -0.0736,0.0059 -0.1751,0.021 -0.3045,0.0446 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.046 -0.3311,-0.1372 -0.0707,-0.0941 -0.1059,-0.2101 -0.1059,-0.3485 0,-0.1411 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0107 0.2687,0.0312 0.1059,0.0206 0.2062,0.038 0.3004,0.0527 -0.0824,-0.1177 -0.1648,-0.2366 -0.2472,-0.3572 -0.0824,-0.1206 -0.1233,-0.2282 -0.1233,-0.3224 0,-0.1382 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412zM29.9512,43.2235c0.1001,0 0.1808,0.0383 0.2426,0.1146 0.0648,0.0735 0.1326,0.197 0.2032,0.3705 0.0705,0.1707 0.1089,0.262 0.1146,0.2738 0.0059,-0.0119 0.0424,-0.1031 0.11,-0.2738 0.0707,-0.1705 0.1401,-0.2941 0.2078,-0.3705 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2102 0.1592,0.3485 0,0.0675 -0.0179,0.1366 -0.0532,0.2073 -0.0323,0.0705 -0.0777,0.1441 -0.1366,0.2206 -0.056,0.0735 -0.1164,0.1576 -0.1812,0.2518 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0353 0.3004,-0.0353 0.0969,0 0.1762,0.0219 0.238,0.0661 0.0648,0.0442 0.1118,0.1047 0.1413,0.1812 0.0294,0.0736 0.044,0.1542 0.044,0.2426 0,0.1382 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1366 -0.3219,0.1366 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.038 -0.3045,-0.044 0.1531,0.2177 0.2534,0.3647 0.3004,0.4411 0.047,0.0736 0.0706,0.1549 0.0706,0.2431 0,0.1411 -0.0533,0.2558 -0.1592,0.3439 -0.1028,0.0854 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0371 -0.2559,-0.1105 -0.0646,-0.0765 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0236 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1648 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.1105 -0.2513,0.1105 -0.15,0 -0.2779,-0.0425 -0.3838,-0.1279 -0.1059,-0.0881 -0.1587,-0.2028 -0.1587,-0.3439 0,-0.0617 0.0156,-0.1268 0.0481,-0.1945 0.0323,-0.0705 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1527 0.2206,-0.3086 -0.0736,0.0059 -0.1751,0.0205 -0.3045,0.044 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.0454 -0.3311,-0.1366 -0.0707,-0.0941 -0.1059,-0.2103 -0.1059,-0.3485 0,-0.1412 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0101 0.2687,0.0307 0.1059,0.0204 0.2062,0.0384 0.3004,0.0532 -0.0824,-0.1177 -0.1648,-0.2371 -0.2472,-0.3577 -0.0824,-0.1206 -0.1233,-0.2278 -0.1233,-0.3219 0,-0.1384 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412z"
|
<path
|
||||||
android:strokeWidth="1.3358"
|
android:fillColor="#f47a68"
|
||||||
android:fillColor="#f47a68"/>
|
android:pathData="m30.3156,23.9881c-0.496,0 -0.992,0.1893 -1.3705,0.5676l-2.7282,2.7288 3.4612,3.4606c0.8044,-0.2715 1.727,-0.0892 2.368,0.5517 0.6237,0.624 0.8361,1.5493 0.5471,2.3828l3.3357,3.3357c0.8076,-0.2777 1.738,-0.098 2.3828,0.5476 0.9008,0.9005 0.9008,2.361 0,3.2615 -1.7823,1.7848 -4.7253,-0.1767 -3.7641,-2.5087l-3.1111,-3.1106c-2.2315,0.5285 -3.8934,-1.2655 -3.149,-3.1674l-0.6863,-0.6863l0,15.9165l5.4913,0l0,-5.8608c-0.0315,-0.7566 1.1201,-0.7566 1.0886,0l0,6.4043c0.0005,0.3013 -0.2438,0.5457 -0.545,0.5455l-6.5804,0c-0.3015,0.0005 -0.546,-0.2441 -0.5456,-0.5455l0,-17.4333c-0.0005,-0.0363 0.0029,-0.0728 0.0097,-0.1085l-1.6444,-1.6444 -9.0106,9.0084c-0.7567,0.7573 -0.7567,1.9848 0,2.7421l13.1415,13.14c0.7572,0.7567 1.9844,0.7567 2.7416,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421l-13.14,-13.1393c-0.3785,-0.3783 -0.8746,-0.5676 -1.3705,-0.5676zM29.9512,39.1825c0.1001,0 0.1808,0.0381 0.2426,0.1146 0.0648,0.0736 0.1326,0.1975 0.2032,0.371 0.0705,0.1706 0.1089,0.2615 0.1146,0.2733 0.0059,-0.0119 0.0424,-0.1026 0.11,-0.2733 0.0707,-0.1705 0.1401,-0.2946 0.2078,-0.371 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2103 0.1592,0.3485 0,0.0676 -0.0179,0.1368 -0.0532,0.2073 -0.0323,0.0707 -0.0777,0.1444 -0.1366,0.2211 -0.056,0.0734 -0.1164,0.1571 -0.1812,0.2513 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0354 0.3004,-0.0354 0.0969,0 0.1762,0.0224 0.238,0.0666 0.0648,0.0442 0.1118,0.1042 0.1413,0.1807 0.0294,0.0734 0.044,0.1544 0.044,0.2426 0,0.1384 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1372 -0.3219,0.1372 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.0386 -0.3045,-0.0446 0.1531,0.2177 0.2534,0.3652 0.3004,0.4417 0.047,0.0736 0.0706,0.1544 0.0706,0.2426 0,0.1412 -0.0533,0.2556 -0.1592,0.3439 -0.1028,0.0853 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0366 -0.2559,-0.11 -0.0646,-0.0767 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0235 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1646 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.11 -0.2513,0.11 -0.15,0 -0.2779,-0.0427 -0.3838,-0.1279 -0.1059,-0.0883 -0.1587,-0.2027 -0.1587,-0.3439 0,-0.0618 0.0156,-0.1263 0.0481,-0.194 0.0323,-0.0707 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1532 0.2206,-0.3091 -0.0736,0.0059 -0.1751,0.021 -0.3045,0.0446 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.046 -0.3311,-0.1372 -0.0707,-0.0941 -0.1059,-0.2101 -0.1059,-0.3485 0,-0.1411 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0107 0.2687,0.0312 0.1059,0.0206 0.2062,0.038 0.3004,0.0527 -0.0824,-0.1177 -0.1648,-0.2366 -0.2472,-0.3572 -0.0824,-0.1206 -0.1233,-0.2282 -0.1233,-0.3224 0,-0.1382 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412zM29.9512,43.2235c0.1001,0 0.1808,0.0383 0.2426,0.1146 0.0648,0.0735 0.1326,0.197 0.2032,0.3705 0.0705,0.1707 0.1089,0.262 0.1146,0.2738 0.0059,-0.0119 0.0424,-0.1031 0.11,-0.2738 0.0707,-0.1705 0.1401,-0.2941 0.2078,-0.3705 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2102 0.1592,0.3485 0,0.0675 -0.0179,0.1366 -0.0532,0.2073 -0.0323,0.0705 -0.0777,0.1441 -0.1366,0.2206 -0.056,0.0735 -0.1164,0.1576 -0.1812,0.2518 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0353 0.3004,-0.0353 0.0969,0 0.1762,0.0219 0.238,0.0661 0.0648,0.0442 0.1118,0.1047 0.1413,0.1812 0.0294,0.0736 0.044,0.1542 0.044,0.2426 0,0.1382 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1366 -0.3219,0.1366 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.038 -0.3045,-0.044 0.1531,0.2177 0.2534,0.3647 0.3004,0.4411 0.047,0.0736 0.0706,0.1549 0.0706,0.2431 0,0.1411 -0.0533,0.2558 -0.1592,0.3439 -0.1028,0.0854 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0371 -0.2559,-0.1105 -0.0646,-0.0765 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0236 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1648 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.1105 -0.2513,0.1105 -0.15,0 -0.2779,-0.0425 -0.3838,-0.1279 -0.1059,-0.0881 -0.1587,-0.2028 -0.1587,-0.3439 0,-0.0617 0.0156,-0.1268 0.0481,-0.1945 0.0323,-0.0705 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1527 0.2206,-0.3086 -0.0736,0.0059 -0.1751,0.0205 -0.3045,0.044 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.0454 -0.3311,-0.1366 -0.0707,-0.0941 -0.1059,-0.2103 -0.1059,-0.3485 0,-0.1412 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0101 0.2687,0.0307 0.1059,0.0204 0.2062,0.0384 0.3004,0.0532 -0.0824,-0.1177 -0.1648,-0.2371 -0.2472,-0.3577 -0.0824,-0.1206 -0.1233,-0.2278 -0.1233,-0.3219 0,-0.1384 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412z"
|
||||||
|
android:strokeWidth="1.3358" />
|
||||||
</group>
|
</group>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:requestLegacyExternalStorage="true"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:requestLegacyExternalStorage="true"
|
|
||||||
tools:ignore="GoogleAppIndexingWarning">
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -31,30 +31,35 @@
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/app_name" />
|
android:label="@string/app_name" />
|
||||||
|
|
||||||
<activity android:name=".LaunchActivity"
|
<activity
|
||||||
android:label="@string/app_name"
|
android:name=".LaunchActivity"
|
||||||
android:configChanges="orientation|screenSize">
|
android:configChanges="orientation|screenSize"
|
||||||
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".git.GitOperationActivity"
|
<activity
|
||||||
|
android:name=".git.GitOperationActivity"
|
||||||
android:theme="@style/NoBackgroundTheme" />
|
android:theme="@style/NoBackgroundTheme" />
|
||||||
|
|
||||||
<activity android:name=".git.GitServerConfigActivity"
|
<activity
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:name=".git.GitServerConfigActivity"
|
||||||
android:label="@string/title_activity_git_clone" />
|
android:label="@string/title_activity_git_clone"
|
||||||
|
android:windowSoftInputMode="adjustResize" />
|
||||||
|
|
||||||
<activity android:name=".git.GitConfigActivity"
|
<activity
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:name=".git.GitConfigActivity"
|
||||||
android:label="@string/title_activity_git_config" />
|
android:label="@string/title_activity_git_config"
|
||||||
|
android:windowSoftInputMode="adjustResize" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".UserPreference"
|
android:name=".UserPreference"
|
||||||
android:parentActivityName=".PasswordStore"
|
android:label="@string/action_settings"
|
||||||
android:label="@string/action_settings" />
|
android:parentActivityName=".PasswordStore" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".autofill.AutofillService"
|
android:name=".autofill.AutofillService"
|
||||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||||
|
@ -66,14 +71,17 @@
|
||||||
android:resource="@xml/autofill_config" />
|
android:resource="@xml/autofill_config" />
|
||||||
</service>
|
</service>
|
||||||
<service
|
<service
|
||||||
android:name=".ClipboardService"
|
android:name=".ClipboardService"
|
||||||
android:process=":clipboard_service_process" />
|
android:process=":clipboard_service_process" />
|
||||||
<service android:name=".autofill.oreo.OreoAutofillService"
|
<service
|
||||||
|
android:name=".autofill.oreo.OreoAutofillService"
|
||||||
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
|
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.autofill.AutofillService" />
|
<action android:name="android.service.autofill.AutofillService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data android:name="android.autofill" android:resource="@xml/oreo_autofill_service" />
|
<meta-data
|
||||||
|
android:name="android.autofill"
|
||||||
|
android:resource="@xml/oreo_autofill_service" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -87,13 +95,13 @@
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".crypto.PgpActivity"
|
android:name=".crypto.PgpActivity"
|
||||||
|
android:configChanges="orientation|screenSize"
|
||||||
android:parentActivityName=".PasswordStore"
|
android:parentActivityName=".PasswordStore"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize" />
|
||||||
android:configChanges="orientation|screenSize" />
|
|
||||||
<activity android:name=".SelectFolderActivity" />
|
<activity android:name=".SelectFolderActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:label="@string/pref_ssh_keygen_title"
|
|
||||||
android:name=".sshkeygen.SshKeyGenActivity"
|
android:name=".sshkeygen.SshKeyGenActivity"
|
||||||
|
android:label="@string/pref_ssh_keygen_title"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".autofill.oreo.ui.AutofillDecryptActivity"
|
android:name=".autofill.oreo.ui.AutofillDecryptActivity"
|
||||||
|
@ -101,16 +109,16 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".autofill.oreo.ui.AutofillFilterView"
|
android:name=".autofill.oreo.ui.AutofillFilterView"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:windowSoftInputMode="adjustNothing"
|
android:theme="@style/DialogLikeTheme"
|
||||||
android:theme="@style/DialogLikeTheme" />
|
android:windowSoftInputMode="adjustNothing" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".autofill.oreo.ui.AutofillSaveActivity"
|
android:name=".autofill.oreo.ui.AutofillSaveActivity"
|
||||||
android:theme="@style/NoBackgroundTheme"/>
|
android:theme="@style/NoBackgroundTheme" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".autofill.oreo.ui.AutofillPublisherChangedActivity"
|
android:name=".autofill.oreo.ui.AutofillPublisherChangedActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:windowSoftInputMode="adjustNothing"
|
android:theme="@style/DialogLikeTheme"
|
||||||
android:theme="@style/DialogLikeTheme" />
|
android:windowSoftInputMode="adjustNothing" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.haroldadmin.whatthestack.WhatTheStack
|
||||||
|
|
||||||
@Suppress("Unused")
|
@Suppress("Unused")
|
||||||
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
|
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
private var prefs: SharedPreferences? = null
|
private var prefs: SharedPreferences? = null
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
|
|
@ -122,13 +122,13 @@ class ClipboardService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
.setContentTitle(getString(R.string.app_name))
|
.setContentTitle(getString(R.string.app_name))
|
||||||
.setContentText(getString(R.string.tap_clear_clipboard))
|
.setContentText(getString(R.string.tap_clear_clipboard))
|
||||||
.setSmallIcon(R.drawable.ic_action_secure_24dp)
|
.setSmallIcon(R.drawable.ic_action_secure_24dp)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.setUsesChronometer(true)
|
.setUsesChronometer(true)
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
startForeground(1, notification)
|
startForeground(1, notification)
|
||||||
}
|
}
|
||||||
|
@ -136,9 +136,9 @@ class ClipboardService : Service() {
|
||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val serviceChannel = NotificationChannel(
|
val serviceChannel = NotificationChannel(
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
getString(R.string.app_name),
|
getString(R.string.app_name),
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_LOW
|
||||||
)
|
)
|
||||||
val manager = getSystemService<NotificationManager>()
|
val manager = getSystemService<NotificationManager>()
|
||||||
if (manager != null) {
|
if (manager != null) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.io.UnsupportedEncodingException
|
||||||
* A single entry in password store.
|
* A single entry in password store.
|
||||||
*/
|
*/
|
||||||
class PasswordEntry(private val content: String) {
|
class PasswordEntry(private val content: String) {
|
||||||
|
|
||||||
val password: String
|
val password: String
|
||||||
val username: String?
|
val username: String?
|
||||||
val digits: String
|
val digits: String
|
||||||
|
@ -109,8 +110,8 @@ class PasswordEntry(private val content: String) {
|
||||||
private fun findOtpDigits(decryptedContent: String): String {
|
private fun findOtpDigits(decryptedContent: String): String {
|
||||||
decryptedContent.split("\n".toRegex()).forEach { line ->
|
decryptedContent.split("\n".toRegex()).forEach { line ->
|
||||||
if ((line.startsWith("otpauth://totp/") ||
|
if ((line.startsWith("otpauth://totp/") ||
|
||||||
line.startsWith("otpauth://hotp/")) &&
|
line.startsWith("otpauth://hotp/")) &&
|
||||||
Uri.parse(line).getQueryParameter("digits") != null) {
|
Uri.parse(line).getQueryParameter("digits") != null) {
|
||||||
return Uri.parse(line).getQueryParameter("digits")!!
|
return Uri.parse(line).getQueryParameter("digits")!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ class PasswordEntry(private val content: String) {
|
||||||
private fun findTotpPeriod(decryptedContent: String): Long {
|
private fun findTotpPeriod(decryptedContent: String): Long {
|
||||||
decryptedContent.split("\n".toRegex()).forEach { line ->
|
decryptedContent.split("\n".toRegex()).forEach { line ->
|
||||||
if (line.startsWith("otpauth://totp/") &&
|
if (line.startsWith("otpauth://totp/") &&
|
||||||
Uri.parse(line).getQueryParameter("period") != null) {
|
Uri.parse(line).getQueryParameter("period") != null) {
|
||||||
return java.lang.Long.parseLong(Uri.parse(line).getQueryParameter("period")!!)
|
return java.lang.Long.parseLong(Uri.parse(line).getQueryParameter("period")!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +131,7 @@ class PasswordEntry(private val content: String) {
|
||||||
private fun findTotpAlgorithm(decryptedContent: String): String {
|
private fun findTotpAlgorithm(decryptedContent: String): String {
|
||||||
decryptedContent.split("\n".toRegex()).forEach { line ->
|
decryptedContent.split("\n".toRegex()).forEach { line ->
|
||||||
if (line.startsWith("otpauth://totp/") &&
|
if (line.startsWith("otpauth://totp/") &&
|
||||||
Uri.parse(line).getQueryParameter("algorithm") != null) {
|
Uri.parse(line).getQueryParameter("algorithm") != null) {
|
||||||
return Uri.parse(line).getQueryParameter("algorithm")!!
|
return Uri.parse(line).getQueryParameter("algorithm")!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,15 +167,15 @@ class PasswordEntry(private val content: String) {
|
||||||
companion object {
|
companion object {
|
||||||
@VisibleForTesting(otherwise = PRIVATE)
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
val USERNAME_FIELDS = arrayOf(
|
val USERNAME_FIELDS = arrayOf(
|
||||||
"login:",
|
"login:",
|
||||||
"username:",
|
"username:",
|
||||||
"user:",
|
"user:",
|
||||||
"account:",
|
"account:",
|
||||||
"email:",
|
"email:",
|
||||||
"name:",
|
"name:",
|
||||||
"handle:",
|
"handle:",
|
||||||
"id:",
|
"id:",
|
||||||
"identity:"
|
"identity:"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ import com.zeapo.pwdstore.ui.adapters.PasswordItemRecyclerAdapter
|
||||||
import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet
|
import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet
|
||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Stack
|
import java.util.Stack
|
||||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
|
||||||
|
|
||||||
class PasswordFragment : Fragment() {
|
class PasswordFragment : Fragment() {
|
||||||
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
|
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
|
||||||
|
@ -74,12 +74,12 @@ class PasswordFragment : Fragment() {
|
||||||
binding.swipeRefresher.setOnRefreshListener {
|
binding.swipeRefresher.setOnRefreshListener {
|
||||||
if (!PasswordRepository.isGitRepo()) {
|
if (!PasswordRepository.isGitRepo()) {
|
||||||
Snackbar.make(binding.root, getString(R.string.clone_git_repo), Snackbar.LENGTH_INDEFINITE)
|
Snackbar.make(binding.root, getString(R.string.clone_git_repo), Snackbar.LENGTH_INDEFINITE)
|
||||||
.setAction(R.string.clone_button) {
|
.setAction(R.string.clone_button) {
|
||||||
val intent = Intent(context, GitServerConfigActivity::class.java)
|
val intent = Intent(context, GitServerConfigActivity::class.java)
|
||||||
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
|
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
|
||||||
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
|
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
binding.swipeRefresher.isRefreshing = false
|
binding.swipeRefresher.isRefreshing = false
|
||||||
} else {
|
} else {
|
||||||
// When authentication is set to ConnectionMode.None then the only git operation we
|
// When authentication is set to ConnectionMode.None then the only git operation we
|
||||||
|
@ -211,7 +211,7 @@ class PasswordFragment : Fragment() {
|
||||||
|
|
||||||
private fun animateFab(show: Boolean) = with(binding.fab) {
|
private fun animateFab(show: Boolean) = with(binding.fab) {
|
||||||
val animation = AnimationUtils.loadAnimation(
|
val animation = AnimationUtils.loadAnimation(
|
||||||
context, if (show) R.anim.scale_up else R.anim.scale_down
|
context, if (show) R.anim.scale_up else R.anim.scale_down
|
||||||
)
|
)
|
||||||
animation.setAnimationListener(object : Animation.AnimationListener {
|
animation.setAnimationListener(object : Animation.AnimationListener {
|
||||||
override fun onAnimationRepeat(animation: Animation?) {
|
override fun onAnimationRepeat(animation: Animation?) {
|
||||||
|
@ -226,9 +226,9 @@ class PasswordFragment : Fragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
animate().rotationBy(if (show) -90f else 90f)
|
animate().rotationBy(if (show) -90f else 90f)
|
||||||
.setStartDelay(if (show) 100 else 0)
|
.setStartDelay(if (show) 100 else 0)
|
||||||
.setDuration(100)
|
.setDuration(100)
|
||||||
.start()
|
.start()
|
||||||
startAnimation(animation)
|
startAnimation(animation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,14 +65,14 @@ import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepositoryDirect
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.initialize
|
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.initialize
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.isInitialized
|
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.isInitialized
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository.PasswordSortOrder.Companion.getSortOrder
|
import com.zeapo.pwdstore.utils.PasswordRepository.PasswordSortOrder.Companion.getSortOrder
|
||||||
import java.io.File
|
|
||||||
import java.lang.Character.UnicodeBlock
|
|
||||||
import java.util.Stack
|
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import org.apache.commons.io.FilenameUtils
|
import org.apache.commons.io.FilenameUtils
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException
|
import org.eclipse.jgit.api.errors.GitAPIException
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.Character.UnicodeBlock
|
||||||
|
import java.util.Stack
|
||||||
|
|
||||||
class PasswordStore : AppCompatActivity() {
|
class PasswordStore : AppCompatActivity() {
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class PasswordStore : AppCompatActivity() {
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
// open search view on search key, or Ctr+F
|
// open search view on search key, or Ctr+F
|
||||||
if ((keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_F && event.isCtrlPressed) &&
|
if ((keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_F && event.isCtrlPressed) &&
|
||||||
!searchItem.isActionViewExpanded) {
|
!searchItem.isActionViewExpanded) {
|
||||||
searchItem.expandActionView()
|
searchItem.expandActionView()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -118,9 +118,9 @@ class PasswordStore : AppCompatActivity() {
|
||||||
// prevent attempt to create password list fragment
|
// prevent attempt to create password list fragment
|
||||||
var savedInstance = savedInstanceState
|
var savedInstance = savedInstanceState
|
||||||
if (savedInstanceState != null && (!settings.getBoolean("git_external", false) ||
|
if (savedInstanceState != null && (!settings.getBoolean("git_external", false) ||
|
||||||
ContextCompat.checkSelfPermission(
|
ContextCompat.checkSelfPermission(
|
||||||
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
!= PackageManager.PERMISSION_GRANTED)) {
|
!= PackageManager.PERMISSION_GRANTED)) {
|
||||||
savedInstance = null
|
savedInstance = null
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstance)
|
super.onCreate(savedInstance)
|
||||||
|
@ -128,28 +128,28 @@ class PasswordStore : AppCompatActivity() {
|
||||||
|
|
||||||
// If user is eligible for Oreo autofill, prompt them to switch.
|
// If user is eligible for Oreo autofill, prompt them to switch.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
||||||
!settings.getBoolean(PREFERENCE_SEEN_AUTOFILL_ONBOARDING, false)) {
|
!settings.getBoolean(PREFERENCE_SEEN_AUTOFILL_ONBOARDING, false)) {
|
||||||
MaterialAlertDialogBuilder(this).run {
|
MaterialAlertDialogBuilder(this).run {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
val layout =
|
val layout =
|
||||||
layoutInflater.inflate(R.layout.oreo_autofill_instructions, null)
|
layoutInflater.inflate(R.layout.oreo_autofill_instructions, null)
|
||||||
layout.findViewById<AppCompatTextView>(R.id.intro_text).setText(R.string.autofill_onboarding_dialog_message)
|
layout.findViewById<AppCompatTextView>(R.id.intro_text).setText(R.string.autofill_onboarding_dialog_message)
|
||||||
val supportedBrowsersTextView =
|
val supportedBrowsersTextView =
|
||||||
layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers)
|
layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers)
|
||||||
supportedBrowsersTextView.text =
|
supportedBrowsersTextView.text =
|
||||||
getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(
|
getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(
|
||||||
separator = "\n"
|
separator = "\n"
|
||||||
) {
|
) {
|
||||||
val appLabel = it.first
|
val appLabel = it.first
|
||||||
val supportDescription = when (it.second) {
|
val supportDescription = when (it.second) {
|
||||||
BrowserAutofillSupportLevel.None -> getString(R.string.oreo_autofill_no_support)
|
BrowserAutofillSupportLevel.None -> getString(R.string.oreo_autofill_no_support)
|
||||||
BrowserAutofillSupportLevel.FlakyFill -> getString(R.string.oreo_autofill_flaky_fill_support)
|
BrowserAutofillSupportLevel.FlakyFill -> getString(R.string.oreo_autofill_flaky_fill_support)
|
||||||
BrowserAutofillSupportLevel.PasswordFill -> getString(R.string.oreo_autofill_password_fill_support)
|
BrowserAutofillSupportLevel.PasswordFill -> getString(R.string.oreo_autofill_password_fill_support)
|
||||||
BrowserAutofillSupportLevel.GeneralFill -> getString(R.string.oreo_autofill_general_fill_support)
|
BrowserAutofillSupportLevel.GeneralFill -> getString(R.string.oreo_autofill_general_fill_support)
|
||||||
BrowserAutofillSupportLevel.GeneralFillAndSave -> getString(R.string.oreo_autofill_general_fill_and_save_support)
|
BrowserAutofillSupportLevel.GeneralFillAndSave -> getString(R.string.oreo_autofill_general_fill_and_save_support)
|
||||||
}
|
|
||||||
"$appLabel: $supportDescription"
|
|
||||||
}
|
}
|
||||||
|
"$appLabel: $supportDescription"
|
||||||
|
}
|
||||||
setView(layout)
|
setView(layout)
|
||||||
setTitle(R.string.autofill_onboarding_dialog_title)
|
setTitle(R.string.autofill_onboarding_dialog_title)
|
||||||
setPositiveButton(R.string.dialog_ok) { _, _ ->
|
setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||||
|
@ -204,7 +204,7 @@ class PasswordStore : AppCompatActivity() {
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
val menuRes = when {
|
val menuRes = when {
|
||||||
ConnectionMode.fromString(settings.getString("git_remote_auth", null))
|
ConnectionMode.fromString(settings.getString("git_remote_auth", null))
|
||||||
== ConnectionMode.None -> R.menu.main_menu_no_auth
|
== ConnectionMode.None -> R.menu.main_menu_no_auth
|
||||||
PasswordRepository.isGitRepo() -> R.menu.main_menu_git
|
PasswordRepository.isGitRepo() -> R.menu.main_menu_git
|
||||||
else -> R.menu.main_menu_non_git
|
else -> R.menu.main_menu_non_git
|
||||||
}
|
}
|
||||||
|
@ -219,40 +219,40 @@ class PasswordStore : AppCompatActivity() {
|
||||||
searchItem = menu.findItem(R.id.action_search)
|
searchItem = menu.findItem(R.id.action_search)
|
||||||
searchView = searchItem.actionView as SearchView
|
searchView = searchItem.actionView as SearchView
|
||||||
searchView.setOnQueryTextListener(
|
searchView.setOnQueryTextListener(
|
||||||
object : OnQueryTextListener {
|
object : OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(s: String): Boolean {
|
override fun onQueryTextSubmit(s: String): Boolean {
|
||||||
searchView.clearFocus()
|
searchView.clearFocus()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueryTextChange(s: String): Boolean {
|
override fun onQueryTextChange(s: String): Boolean {
|
||||||
val filter = s.trim()
|
val filter = s.trim()
|
||||||
// List the contents of the current directory if the user enters a blank
|
// List the contents of the current directory if the user enters a blank
|
||||||
// search term.
|
// search term.
|
||||||
if (filter.isEmpty())
|
if (filter.isEmpty())
|
||||||
model.navigateTo(
|
model.navigateTo(
|
||||||
newDirectory = model.currentDir.value!!,
|
newDirectory = model.currentDir.value!!,
|
||||||
pushPreviousLocation = false
|
pushPreviousLocation = false
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
model.search(filter)
|
model.search(filter)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// When using the support library, the setOnActionExpandListener() method is
|
// When using the support library, the setOnActionExpandListener() method is
|
||||||
// static and accepts the MenuItem object as an argument
|
// static and accepts the MenuItem object as an argument
|
||||||
searchItem.setOnActionExpandListener(
|
searchItem.setOnActionExpandListener(
|
||||||
object : OnActionExpandListener {
|
object : OnActionExpandListener {
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||||
refreshPasswordList()
|
refreshPasswordList()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (settings.getBoolean("search_on_start", false)) {
|
if (settings.getBoolean("search_on_start", false)) {
|
||||||
searchItem.expandActionView()
|
searchItem.expandActionView()
|
||||||
}
|
}
|
||||||
|
@ -266,8 +266,8 @@ class PasswordStore : AppCompatActivity() {
|
||||||
val id = item.itemId
|
val id = item.itemId
|
||||||
val intent: Intent
|
val intent: Intent
|
||||||
val initBefore = MaterialAlertDialogBuilder(this)
|
val initBefore = MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(resources.getString(R.string.creation_dialog_text))
|
.setMessage(resources.getString(R.string.creation_dialog_text))
|
||||||
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
||||||
when (id) {
|
when (id) {
|
||||||
R.id.user_pref -> {
|
R.id.user_pref -> {
|
||||||
try {
|
try {
|
||||||
|
@ -379,7 +379,7 @@ class PasswordStore : AppCompatActivity() {
|
||||||
if (externalRepo && externalRepoPath != null) {
|
if (externalRepo && externalRepoPath != null) {
|
||||||
val dir = File(externalRepoPath)
|
val dir = File(externalRepoPath)
|
||||||
if (dir.exists() && dir.isDirectory &&
|
if (dir.exists() && dir.isDirectory &&
|
||||||
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
||||||
closeRepository()
|
closeRepository()
|
||||||
checkLocalRepository()
|
checkLocalRepository()
|
||||||
return // if not empty, just show me the passwords!
|
return // if not empty, just show me the passwords!
|
||||||
|
@ -388,13 +388,13 @@ class PasswordStore : AppCompatActivity() {
|
||||||
val keyIds = settings.getStringSet("openpgp_key_ids_set", HashSet())
|
val keyIds = settings.getStringSet("openpgp_key_ids_set", HashSet())
|
||||||
if (keyIds != null && keyIds.isEmpty()) {
|
if (keyIds != null && keyIds.isEmpty()) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(resources.getString(R.string.key_dialog_text))
|
.setMessage(resources.getString(R.string.key_dialog_text))
|
||||||
.setPositiveButton(resources.getString(R.string.dialog_positive)) { _, _ ->
|
.setPositiveButton(resources.getString(R.string.dialog_positive)) { _, _ ->
|
||||||
val intent = Intent(activity, UserPreference::class.java)
|
val intent = Intent(activity, UserPreference::class.java)
|
||||||
startActivityForResult(intent, BaseGitActivity.REQUEST_INIT)
|
startActivityForResult(intent, BaseGitActivity.REQUEST_INIT)
|
||||||
}
|
}
|
||||||
.setNegativeButton(resources.getString(R.string.dialog_negative), null)
|
.setNegativeButton(resources.getString(R.string.dialog_negative), null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
createRepository()
|
createRepository()
|
||||||
}
|
}
|
||||||
|
@ -407,15 +407,15 @@ class PasswordStore : AppCompatActivity() {
|
||||||
return if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
return if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
findViewById(R.id.main_layout),
|
findViewById(R.id.main_layout),
|
||||||
getString(R.string.access_sdcard_text),
|
getString(R.string.access_sdcard_text),
|
||||||
Snackbar.LENGTH_INDEFINITE
|
Snackbar.LENGTH_INDEFINITE
|
||||||
).run {
|
).run {
|
||||||
setAction(getString(R.string.snackbar_action_grant)) {
|
setAction(getString(R.string.snackbar_action_grant)) {
|
||||||
ActivityCompat.requestPermissions(
|
ActivityCompat.requestPermissions(
|
||||||
activity,
|
activity,
|
||||||
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||||
REQUEST_EXTERNAL_STORAGE
|
REQUEST_EXTERNAL_STORAGE
|
||||||
)
|
)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
@ -447,7 +447,7 @@ class PasswordStore : AppCompatActivity() {
|
||||||
tag(TAG).d { "Check, dir: ${localDir.absolutePath}" }
|
tag(TAG).d { "Check, dir: ${localDir.absolutePath}" }
|
||||||
// do not push the fragment if we already have it
|
// do not push the fragment if we already have it
|
||||||
if (fragmentManager.findFragmentByTag("PasswordsList") == null ||
|
if (fragmentManager.findFragmentByTag("PasswordsList") == null ||
|
||||||
settings.getBoolean("repo_changed", false)) {
|
settings.getBoolean("repo_changed", false)) {
|
||||||
settings.edit { putBoolean("repo_changed", false) }
|
settings.edit { putBoolean("repo_changed", false) }
|
||||||
plist = PasswordFragment()
|
plist = PasswordFragment()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
|
@ -520,11 +520,11 @@ class PasswordStore : AppCompatActivity() {
|
||||||
// Adds shortcut
|
// Adds shortcut
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
val shortcut = Builder(this, item.fullPathToParent)
|
val shortcut = Builder(this, item.fullPathToParent)
|
||||||
.setShortLabel(item.toString())
|
.setShortLabel(item.toString())
|
||||||
.setLongLabel(item.fullPathToParent + item.toString())
|
.setLongLabel(item.fullPathToParent + item.toString())
|
||||||
.setIcon(Icon.createWithResource(this, R.mipmap.ic_launcher))
|
.setIcon(Icon.createWithResource(this, R.mipmap.ic_launcher))
|
||||||
.setIntent(authDecryptIntent.setAction("DECRYPT_PASS")) // Needs action
|
.setIntent(authDecryptIntent.setAction("DECRYPT_PASS")) // Needs action
|
||||||
.build()
|
.build()
|
||||||
val shortcuts = shortcutManager!!.dynamicShortcuts
|
val shortcuts = shortcutManager!!.dynamicShortcuts
|
||||||
if (shortcuts.size >= shortcutManager!!.maxShortcutCountPerActivity && shortcuts.size > 0) {
|
if (shortcuts.size >= shortcutManager!!.maxShortcutCountPerActivity && shortcuts.size > 0) {
|
||||||
shortcuts.removeAt(shortcuts.size - 1)
|
shortcuts.removeAt(shortcuts.size - 1)
|
||||||
|
@ -550,20 +550,20 @@ class PasswordStore : AppCompatActivity() {
|
||||||
private fun validateState(): Boolean {
|
private fun validateState(): Boolean {
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(resources.getString(R.string.creation_dialog_text))
|
.setMessage(resources.getString(R.string.creation_dialog_text))
|
||||||
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
||||||
.show()
|
.show()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (settings.getStringSet("openpgp_key_ids_set", HashSet()).isNullOrEmpty()) {
|
if (settings.getStringSet("openpgp_key_ids_set", HashSet()).isNullOrEmpty()) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(resources.getString(R.string.no_key_selected_dialog_title))
|
.setTitle(resources.getString(R.string.no_key_selected_dialog_title))
|
||||||
.setMessage(resources.getString(R.string.no_key_selected_dialog_text))
|
.setMessage(resources.getString(R.string.no_key_selected_dialog_text))
|
||||||
.setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ ->
|
.setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ ->
|
||||||
val intent = Intent(activity, UserPreference::class.java)
|
val intent = Intent(activity, UserPreference::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -593,22 +593,22 @@ class PasswordStore : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
val item = selectedItems.pop()
|
val item = selectedItems.pop()
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(resources.getString(R.string.delete_dialog_text, item.longName))
|
.setMessage(resources.getString(R.string.delete_dialog_text, item.longName))
|
||||||
.setPositiveButton(resources.getString(R.string.dialog_yes)) { _, _ ->
|
.setPositiveButton(resources.getString(R.string.dialog_yes)) { _, _ ->
|
||||||
val filesToDelete = if (item.file.isDirectory) {
|
val filesToDelete = if (item.file.isDirectory) {
|
||||||
FileUtils.listFiles(item.file, null, true)
|
FileUtils.listFiles(item.file, null, true)
|
||||||
} else {
|
} else {
|
||||||
listOf(item.file)
|
listOf(item.file)
|
||||||
}
|
|
||||||
AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete)
|
|
||||||
item.file.deleteRecursively()
|
|
||||||
commitChange(resources.getString(R.string.git_commit_remove_text, item.longName))
|
|
||||||
deletePasswords(selectedItems)
|
|
||||||
}
|
}
|
||||||
.setNegativeButton(resources.getString(R.string.dialog_no)) { _, _ ->
|
AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete)
|
||||||
deletePasswords(selectedItems)
|
item.file.deleteRecursively()
|
||||||
}
|
commitChange(resources.getString(R.string.git_commit_remove_text, item.longName))
|
||||||
.show()
|
deletePasswords(selectedItems)
|
||||||
|
}
|
||||||
|
.setNegativeButton(resources.getString(R.string.dialog_no)) { _, _ ->
|
||||||
|
deletePasswords(selectedItems)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun movePasswords(values: List<PasswordItem>) {
|
fun movePasswords(values: List<PasswordItem>) {
|
||||||
|
@ -661,22 +661,22 @@ class PasswordStore : AppCompatActivity() {
|
||||||
if (data != null && data.getBooleanExtra("needCommit", false)) {
|
if (data != null && data.getBooleanExtra("needCommit", false)) {
|
||||||
if (data.getStringExtra("OPERATION") == "EDIT") {
|
if (data.getStringExtra("OPERATION") == "EDIT") {
|
||||||
commitChange(resources.getString(R.string.git_commit_edit_text,
|
commitChange(resources.getString(R.string.git_commit_edit_text,
|
||||||
data.extras!!.getString("LONG_NAME")))
|
data.extras!!.getString("LONG_NAME")))
|
||||||
} else {
|
} else {
|
||||||
commitChange(resources.getString(R.string.git_commit_increment_text,
|
commitChange(resources.getString(R.string.git_commit_increment_text,
|
||||||
data.extras!!.getString("LONG_NAME")))
|
data.extras!!.getString("LONG_NAME")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
refreshPasswordList()
|
refreshPasswordList()
|
||||||
}
|
}
|
||||||
REQUEST_CODE_ENCRYPT -> {
|
REQUEST_CODE_ENCRYPT -> {
|
||||||
commitChange(resources.getString(R.string.git_commit_add_text,
|
commitChange(resources.getString(R.string.git_commit_add_text,
|
||||||
data!!.extras!!.getString("LONG_NAME")))
|
data!!.extras!!.getString("LONG_NAME")))
|
||||||
refreshPasswordList()
|
refreshPasswordList()
|
||||||
}
|
}
|
||||||
REQUEST_CODE_EDIT -> {
|
REQUEST_CODE_EDIT -> {
|
||||||
commitChange(resources.getString(R.string.git_commit_edit_text,
|
commitChange(resources.getString(R.string.git_commit_edit_text,
|
||||||
data!!.extras!!.getString("LONG_NAME")))
|
data!!.extras!!.getString("LONG_NAME")))
|
||||||
refreshPasswordList()
|
refreshPasswordList()
|
||||||
}
|
}
|
||||||
BaseGitActivity.REQUEST_INIT, NEW_REPO_BUTTON -> initializeRepositoryInfo()
|
BaseGitActivity.REQUEST_INIT, NEW_REPO_BUTTON -> initializeRepositoryInfo()
|
||||||
|
@ -685,14 +685,14 @@ class PasswordStore : AppCompatActivity() {
|
||||||
// duplicate code
|
// duplicate code
|
||||||
CLONE_REPO_BUTTON -> {
|
CLONE_REPO_BUTTON -> {
|
||||||
if (settings.getBoolean("git_external", false) &&
|
if (settings.getBoolean("git_external", false) &&
|
||||||
settings.getString("git_external_repo", null) != null) {
|
settings.getString("git_external_repo", null) != null) {
|
||||||
val externalRepoPath = settings.getString("git_external_repo", null)
|
val externalRepoPath = settings.getString("git_external_repo", null)
|
||||||
val dir = externalRepoPath?.let { File(it) }
|
val dir = externalRepoPath?.let { File(it) }
|
||||||
if (dir != null &&
|
if (dir != null &&
|
||||||
dir.exists() &&
|
dir.exists() &&
|
||||||
dir.isDirectory &&
|
dir.isDirectory &&
|
||||||
!FileUtils.listFiles(dir, null, true).isEmpty() &&
|
!FileUtils.listFiles(dir, null, true).isEmpty() &&
|
||||||
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
||||||
closeRepository()
|
closeRepository()
|
||||||
checkLocalRepository()
|
checkLocalRepository()
|
||||||
return // if not empty, just show me the passwords!
|
return // if not empty, just show me the passwords!
|
||||||
|
@ -732,17 +732,17 @@ class PasswordStore : AppCompatActivity() {
|
||||||
if (destinationFile.exists()) {
|
if (destinationFile.exists()) {
|
||||||
e { "Trying to move a file that already exists." }
|
e { "Trying to move a file that already exists." }
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(resources.getString(R.string.password_exists_title))
|
.setTitle(resources.getString(R.string.password_exists_title))
|
||||||
.setMessage(resources.getString(
|
.setMessage(resources.getString(
|
||||||
R.string.password_exists_message,
|
R.string.password_exists_message,
|
||||||
destinationLongName,
|
destinationLongName,
|
||||||
sourceLongName)
|
sourceLongName)
|
||||||
)
|
)
|
||||||
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||||
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
|
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_cancel, null)
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
|
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
|
||||||
}
|
}
|
||||||
|
@ -773,66 +773,66 @@ class PasswordStore : AppCompatActivity() {
|
||||||
} else {
|
} else {
|
||||||
AutofillMatcher.updateMatches(this, sourceDestinationMap)
|
AutofillMatcher.updateMatches(this, sourceDestinationMap)
|
||||||
commitChange(resources
|
commitChange(resources
|
||||||
.getString(
|
.getString(
|
||||||
R.string.git_commit_move_text,
|
R.string.git_commit_move_text,
|
||||||
sourceLongName,
|
sourceLongName,
|
||||||
destinationLongName))
|
destinationLongName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initRepository(operation: Int) {
|
private fun initRepository(operation: Int) {
|
||||||
closeRepository()
|
closeRepository()
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(resources.getString(R.string.location_dialog_title))
|
.setTitle(resources.getString(R.string.location_dialog_title))
|
||||||
.setMessage(resources.getString(R.string.location_dialog_text))
|
.setMessage(resources.getString(R.string.location_dialog_text))
|
||||||
.setPositiveButton(resources.getString(R.string.location_hidden)) { _, _ ->
|
.setPositiveButton(resources.getString(R.string.location_hidden)) { _, _ ->
|
||||||
settings.edit { putBoolean("git_external", false) }
|
settings.edit { putBoolean("git_external", false) }
|
||||||
when (operation) {
|
when (operation) {
|
||||||
NEW_REPO_BUTTON -> initializeRepositoryInfo()
|
NEW_REPO_BUTTON -> initializeRepositoryInfo()
|
||||||
CLONE_REPO_BUTTON -> {
|
CLONE_REPO_BUTTON -> {
|
||||||
val intent = Intent(activity, GitServerConfigActivity::class.java)
|
val intent = Intent(activity, GitServerConfigActivity::class.java)
|
||||||
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
|
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
|
||||||
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
|
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setNegativeButton(resources.getString(R.string.location_sdcard)) { _, _ ->
|
||||||
|
settings.edit { putBoolean("git_external", true) }
|
||||||
|
val externalRepo = settings.getString("git_external_repo", null)
|
||||||
|
if (externalRepo == null) {
|
||||||
|
val intent = Intent(activity, UserPreference::class.java)
|
||||||
|
intent.putExtra("operation", "git_external")
|
||||||
|
startActivityForResult(intent, operation)
|
||||||
|
} else {
|
||||||
|
MaterialAlertDialogBuilder(activity)
|
||||||
|
.setTitle(resources.getString(R.string.directory_selected_title))
|
||||||
|
.setMessage(resources.getString(R.string.directory_selected_message, externalRepo))
|
||||||
|
.setPositiveButton(resources.getString(R.string.use)) { _, _ ->
|
||||||
|
when (operation) {
|
||||||
|
NEW_REPO_BUTTON -> initializeRepositoryInfo()
|
||||||
|
CLONE_REPO_BUTTON -> {
|
||||||
|
val intent = Intent(activity, GitServerConfigActivity::class.java)
|
||||||
|
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
|
||||||
|
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.setNegativeButton(resources.getString(R.string.change)) { _, _ ->
|
||||||
|
val intent = Intent(activity, UserPreference::class.java)
|
||||||
|
intent.putExtra("operation", "git_external")
|
||||||
|
startActivityForResult(intent, operation)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
.setNegativeButton(resources.getString(R.string.location_sdcard)) { _, _ ->
|
}
|
||||||
settings.edit { putBoolean("git_external", true) }
|
.show()
|
||||||
val externalRepo = settings.getString("git_external_repo", null)
|
|
||||||
if (externalRepo == null) {
|
|
||||||
val intent = Intent(activity, UserPreference::class.java)
|
|
||||||
intent.putExtra("operation", "git_external")
|
|
||||||
startActivityForResult(intent, operation)
|
|
||||||
} else {
|
|
||||||
MaterialAlertDialogBuilder(activity)
|
|
||||||
.setTitle(resources.getString(R.string.directory_selected_title))
|
|
||||||
.setMessage(resources.getString(R.string.directory_selected_message, externalRepo))
|
|
||||||
.setPositiveButton(resources.getString(R.string.use)) { _, _ ->
|
|
||||||
when (operation) {
|
|
||||||
NEW_REPO_BUTTON -> initializeRepositoryInfo()
|
|
||||||
CLONE_REPO_BUTTON -> {
|
|
||||||
val intent = Intent(activity, GitServerConfigActivity::class.java)
|
|
||||||
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
|
|
||||||
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setNegativeButton(resources.getString(R.string.change)) { _, _ ->
|
|
||||||
val intent = Intent(activity, UserPreference::class.java)
|
|
||||||
intent.putExtra("operation", "git_external")
|
|
||||||
startActivityForResult(intent, operation)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun matchPasswordWithApp(item: PasswordItem) {
|
fun matchPasswordWithApp(item: PasswordItem) {
|
||||||
val path = item.file
|
val path = item.file
|
||||||
.absolutePath
|
.absolutePath
|
||||||
.replace(getRepositoryDirectory(applicationContext).toString() + "/", "")
|
.replace(getRepositoryDirectory(applicationContext).toString() + "/", "")
|
||||||
.replace(".gpg", "")
|
.replace(".gpg", "")
|
||||||
val data = Intent()
|
val data = Intent()
|
||||||
data.putExtra("path", path)
|
data.putExtra("path", path)
|
||||||
setResult(Activity.RESULT_OK, data)
|
setResult(Activity.RESULT_OK, data)
|
||||||
|
@ -860,7 +860,7 @@ class PasswordStore : AppCompatActivity() {
|
||||||
private fun isPrintable(c: Char): Boolean {
|
private fun isPrintable(c: Char): Boolean {
|
||||||
val block = UnicodeBlock.of(c)
|
val block = UnicodeBlock.of(c)
|
||||||
return (!Character.isISOControl(c) &&
|
return (!Character.isISOControl(c) &&
|
||||||
block != null && block !== UnicodeBlock.SPECIALS)
|
block != null && block !== UnicodeBlock.SPECIALS)
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val PREFERENCE_SEEN_AUTOFILL_ONBOARDING = "seen_autofill_onboarding"
|
private const val PREFERENCE_SEEN_AUTOFILL_ONBOARDING = "seen_autofill_onboarding"
|
||||||
|
|
|
@ -30,10 +30,6 @@ import com.zeapo.pwdstore.autofill.oreo.AutofillPreferences
|
||||||
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import java.io.File
|
|
||||||
import java.text.Collator
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.Stack
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
|
@ -48,6 +44,10 @@ import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.toList
|
import kotlinx.coroutines.flow.toList
|
||||||
import kotlinx.coroutines.yield
|
import kotlinx.coroutines.yield
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
|
import java.io.File
|
||||||
|
import java.text.Collator
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.Stack
|
||||||
|
|
||||||
private fun File.toPasswordItem(root: File) = if (isFile)
|
private fun File.toPasswordItem(root: File) = if (isFile)
|
||||||
PasswordItem.newPassword(name, this, root)
|
PasswordItem.newPassword(name, this, root)
|
||||||
|
|
|
@ -18,8 +18,8 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import com.zeapo.pwdstore.ui.adapters.PasswordItemRecyclerAdapter
|
import com.zeapo.pwdstore.ui.adapters.PasswordItemRecyclerAdapter
|
||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import java.io.File
|
|
||||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class SelectFolderFragment : Fragment() {
|
class SelectFolderFragment : Fragment() {
|
||||||
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
|
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
|
||||||
|
@ -75,7 +75,7 @@ class SelectFolderFragment : Fragment() {
|
||||||
}
|
}
|
||||||
} catch (e: ClassCastException) {
|
} catch (e: ClassCastException) {
|
||||||
throw ClassCastException(
|
throw ClassCastException(
|
||||||
"$context must implement OnFragmentInteractionListener")
|
"$context must implement OnFragmentInteractionListener")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ import com.zeapo.pwdstore.utils.BiometricAuthenticator
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.autofillManager
|
import com.zeapo.pwdstore.utils.autofillManager
|
||||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||||
|
import me.msfjarvis.openpgpktx.util.OpenPgpUtils
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
@ -57,8 +59,6 @@ import java.time.format.DateTimeFormatter
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
import me.msfjarvis.openpgpktx.util.OpenPgpUtils
|
|
||||||
import org.apache.commons.io.FileUtils
|
|
||||||
|
|
||||||
typealias ClickListener = Preference.OnPreferenceClickListener
|
typealias ClickListener = Preference.OnPreferenceClickListener
|
||||||
typealias ChangeListener = Preference.OnPreferenceChangeListener
|
typealias ChangeListener = Preference.OnPreferenceChangeListener
|
||||||
|
@ -98,8 +98,8 @@ class UserPreference : AppCompatActivity() {
|
||||||
|
|
||||||
if (!PasswordRepository.isGitRepo()) {
|
if (!PasswordRepository.isGitRepo()) {
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
gitServerPreference, gitConfigPreference, sshKeyPreference,
|
gitServerPreference, gitConfigPreference, sshKeyPreference,
|
||||||
sshKeygenPreference, viewSshKeyPreference, clearSavedPassPreference
|
sshKeygenPreference, viewSshKeyPreference, clearSavedPassPreference
|
||||||
).forEach {
|
).forEach {
|
||||||
it.parent?.removePreference(it)
|
it.parent?.removePreference(it)
|
||||||
}
|
}
|
||||||
|
@ -121,10 +121,10 @@ class UserPreference : AppCompatActivity() {
|
||||||
val autoFillShowFullNamePreference =
|
val autoFillShowFullNamePreference =
|
||||||
findPreference<CheckBoxPreference>("autofill_full_path")!!
|
findPreference<CheckBoxPreference>("autofill_full_path")!!
|
||||||
autofillDependencies = listOf(
|
autofillDependencies = listOf(
|
||||||
autoFillAppsPreference,
|
autoFillAppsPreference,
|
||||||
autoFillDefaultPreference,
|
autoFillDefaultPreference,
|
||||||
autoFillAlwaysShowDialogPreference,
|
autoFillAlwaysShowDialogPreference,
|
||||||
autoFillShowFullNamePreference
|
autoFillShowFullNamePreference
|
||||||
)
|
)
|
||||||
val oreoAutofillDirectoryStructurePreference =
|
val oreoAutofillDirectoryStructurePreference =
|
||||||
findPreference<ListPreference>("oreo_autofill_directory_structure")!!
|
findPreference<ListPreference>("oreo_autofill_directory_structure")!!
|
||||||
|
@ -139,7 +139,7 @@ class UserPreference : AppCompatActivity() {
|
||||||
clearHotpIncrementPreference?.isVisible = sharedPreferences.getBoolean("hotp_remember_check", false)
|
clearHotpIncrementPreference?.isVisible = sharedPreferences.getBoolean("hotp_remember_check", false)
|
||||||
clearClipboard20xPreference?.isVisible = sharedPreferences.getString("general_show_time", "45")?.toInt() != 0
|
clearClipboard20xPreference?.isVisible = sharedPreferences.getString("general_show_time", "45")?.toInt() != 0
|
||||||
val selectedKeys = (sharedPreferences.getStringSet("openpgp_key_ids_set", null)
|
val selectedKeys = (sharedPreferences.getStringSet("openpgp_key_ids_set", null)
|
||||||
?: HashSet()).toTypedArray()
|
?: HashSet()).toTypedArray()
|
||||||
keyPreference?.summary = if (selectedKeys.isEmpty()) {
|
keyPreference?.summary = if (selectedKeys.isEmpty()) {
|
||||||
this.resources.getString(R.string.pref_no_key_selected)
|
this.resources.getString(R.string.pref_no_key_selected)
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,7 +148,7 @@ class UserPreference : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
openkeystoreIdPreference?.isVisible = sharedPreferences.getString("ssh_openkeystore_keyid", null)?.isNotEmpty()
|
openkeystoreIdPreference?.isVisible = sharedPreferences.getString("ssh_openkeystore_keyid", null)?.isNotEmpty()
|
||||||
?: false
|
?: false
|
||||||
|
|
||||||
updateAutofillSettings()
|
updateAutofillSettings()
|
||||||
updateClearSavedPassphrasePrefs()
|
updateClearSavedPassphrasePrefs()
|
||||||
|
@ -220,29 +220,29 @@ class UserPreference : AppCompatActivity() {
|
||||||
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
|
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
|
||||||
val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext)
|
val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext)
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(R.string.pref_dialog_delete_title)
|
.setTitle(R.string.pref_dialog_delete_title)
|
||||||
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
|
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
|
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
|
||||||
try {
|
try {
|
||||||
FileUtils.cleanDirectory(PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext))
|
FileUtils.cleanDirectory(PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext))
|
||||||
PasswordRepository.closeRepository()
|
PasswordRepository.closeRepository()
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
// TODO Handle the different cases of exceptions
|
// TODO Handle the different cases of exceptions
|
||||||
}
|
|
||||||
|
|
||||||
sharedPreferences.edit { putBoolean("repository_initialized", false) }
|
|
||||||
dialogInterface.cancel()
|
|
||||||
callingActivity.finish()
|
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
|
|
||||||
.show()
|
sharedPreferences.edit { putBoolean("repository_initialized", false) }
|
||||||
|
dialogInterface.cancel()
|
||||||
|
callingActivity.finish()
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
|
||||||
|
.show()
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExternalGitRepositoryPreference?.summary =
|
selectExternalGitRepositoryPreference?.summary =
|
||||||
sharedPreferences.getString("git_external_repo", context.getString(R.string.no_repo_selected))
|
sharedPreferences.getString("git_external_repo", context.getString(R.string.no_repo_selected))
|
||||||
selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener {
|
selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener {
|
||||||
callingActivity.selectExternalGitRepository()
|
callingActivity.selectExternalGitRepository()
|
||||||
true
|
true
|
||||||
|
@ -484,23 +484,23 @@ class UserPreference : AppCompatActivity() {
|
||||||
prefsFragment = PrefsFragment()
|
prefsFragment = PrefsFragment()
|
||||||
|
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.replace(android.R.id.content, prefsFragment)
|
.replace(android.R.id.content, prefsFragment)
|
||||||
.commit()
|
.commit()
|
||||||
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectExternalGitRepository() {
|
fun selectExternalGitRepository() {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
|
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
|
||||||
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
|
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
|
||||||
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
startActivityForResult(Intent.createChooser(i, "Choose Directory"), SELECT_GIT_DIRECTORY)
|
startActivityForResult(Intent.createChooser(i, "Choose Directory"), SELECT_GIT_DIRECTORY)
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_cancel, null)
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -630,9 +630,9 @@ class UserPreference : AppCompatActivity() {
|
||||||
copySshKey(uri)
|
copySshKey(uri)
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
this.resources.getString(R.string.ssh_key_success_dialog_title),
|
this.resources.getString(R.string.ssh_key_success_dialog_title),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
|
|
||||||
|
@ -668,13 +668,13 @@ class UserPreference : AppCompatActivity() {
|
||||||
|
|
||||||
if (Environment.getExternalStorageDirectory().path == repoPath) {
|
if (Environment.getExternalStorageDirectory().path == repoPath) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(getString(R.string.sdcard_root_warning_title))
|
.setTitle(getString(R.string.sdcard_root_warning_title))
|
||||||
.setMessage(getString(R.string.sdcard_root_warning_message))
|
.setMessage(getString(R.string.sdcard_root_warning_message))
|
||||||
.setPositiveButton("Remove everything") { _, _ ->
|
.setPositiveButton("Remove everything") { _, _ ->
|
||||||
prefs.edit { putString("git_external_repo", uri?.path) }
|
prefs.edit { putString("git_external_repo", uri?.path) }
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_cancel, null)
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
prefs.edit { putString("git_external_repo", repoPath) }
|
prefs.edit { putString("git_external_repo", repoPath) }
|
||||||
}
|
}
|
||||||
|
@ -693,9 +693,9 @@ class UserPreference : AppCompatActivity() {
|
||||||
val uri: Uri = data.data ?: throw IOException("Unable to open file")
|
val uri: Uri = data.data ?: throw IOException("Unable to open file")
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
|
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
|
|
||||||
|
@ -731,8 +731,8 @@ class UserPreference : AppCompatActivity() {
|
||||||
|
|
||||||
val dateString = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val dateString = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
LocalDateTime
|
LocalDateTime
|
||||||
.now()
|
.now()
|
||||||
.format(DateTimeFormatter.ISO_DATE_TIME)
|
.format(DateTimeFormatter.ISO_DATE_TIME)
|
||||||
} else {
|
} else {
|
||||||
String.format("%tFT%<tRZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))
|
String.format("%tFT%<tRZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,11 +60,11 @@ class AutofillFragment : DialogFragment() {
|
||||||
} else {
|
} else {
|
||||||
val browserIntent = Intent("android.intent.action.VIEW", Uri.parse("http://"))
|
val browserIntent = Intent("android.intent.action.VIEW", Uri.parse("http://"))
|
||||||
val resolveInfo = requireContext().packageManager
|
val resolveInfo = requireContext().packageManager
|
||||||
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
|
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
|
||||||
iconPackageName = resolveInfo?.activityInfo?.packageName
|
iconPackageName = resolveInfo?.activityInfo?.packageName
|
||||||
builder.setTitle("Website")
|
builder.setTitle("Website")
|
||||||
(view.findViewById<View>(R.id.webURL) as EditText).setText(packageName
|
(view.findViewById<View>(R.id.webURL) as EditText).setText(packageName
|
||||||
?: "com.android.browser")
|
?: "com.android.browser")
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (iconPackageName != null) {
|
if (iconPackageName != null) {
|
||||||
|
@ -86,9 +86,9 @@ class AutofillFragment : DialogFragment() {
|
||||||
(view.findViewById<View>(R.id.matched) as ListView).adapter = adapter
|
(view.findViewById<View>(R.id.matched) as ListView).adapter = adapter
|
||||||
// delete items by clicking them
|
// delete items by clicking them
|
||||||
(view.findViewById<View>(R.id.matched) as ListView).onItemClickListener =
|
(view.findViewById<View>(R.id.matched) as ListView).onItemClickListener =
|
||||||
AdapterView.OnItemClickListener { _, _, position, _ ->
|
AdapterView.OnItemClickListener { _, _, position, _ ->
|
||||||
adapter!!.remove(adapter!!.getItem(position))
|
adapter!!.remove(adapter!!.getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the existing preference, if any
|
// set the existing preference, if any
|
||||||
val prefs: SharedPreferences = if (!isWeb) {
|
val prefs: SharedPreferences = if (!isWeb) {
|
||||||
|
@ -122,7 +122,7 @@ class AutofillFragment : DialogFragment() {
|
||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
builder.setNeutralButton(R.string.autofill_apps_delete) { _, _ ->
|
builder.setNeutralButton(R.string.autofill_apps_delete) { _, _ ->
|
||||||
if (callingActivity.recyclerAdapter != null &&
|
if (callingActivity.recyclerAdapter != null &&
|
||||||
packageName != null && packageName != "") {
|
packageName != null && packageName != "") {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
remove(packageName)
|
remove(packageName)
|
||||||
callingActivity.recyclerAdapter?.removeWebsite(packageName)
|
callingActivity.recyclerAdapter?.removeWebsite(packageName)
|
||||||
|
|
|
@ -19,9 +19,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
|
||||||
|
|
||||||
class AutofillPreferenceActivity : AppCompatActivity() {
|
class AutofillPreferenceActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@ import androidx.recyclerview.widget.SortedList
|
||||||
import androidx.recyclerview.widget.SortedListAdapterCallback
|
import androidx.recyclerview.widget.SortedListAdapterCallback
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import com.zeapo.pwdstore.utils.splitLines
|
import com.zeapo.pwdstore.utils.splitLines
|
||||||
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
|
||||||
|
|
||||||
internal class AutofillRecyclerAdapter(
|
internal class AutofillRecyclerAdapter(
|
||||||
allApps: List<AppInfo>,
|
allApps: List<AppInfo>,
|
||||||
|
@ -63,7 +63,7 @@ internal class AutofillRecyclerAdapter(
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val v = LayoutInflater.from(parent.context)
|
val v = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.autofill_row_layout, parent, false)
|
.inflate(R.layout.autofill_row_layout, parent, false)
|
||||||
return ViewHolder(v)
|
return ViewHolder(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ internal class AutofillRecyclerAdapter(
|
||||||
holder.secondary.append(" " + preference!!.splitLines()[0])
|
holder.secondary.append(" " + preference!!.splitLines()[0])
|
||||||
if (preference.trim { it <= ' ' }.splitLines().size - 1 > 0) {
|
if (preference.trim { it <= ' ' }.splitLines().size - 1 > 0) {
|
||||||
holder.secondary.append(" and " +
|
holder.secondary.append(" and " +
|
||||||
(preference.trim { it <= ' ' }.splitLines().size - 1) + " more")
|
(preference.trim { it <= ' ' }.splitLines().size - 1) + " more")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,15 +32,6 @@ import com.zeapo.pwdstore.PasswordEntry
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.splitLines
|
import com.zeapo.pwdstore.utils.splitLines
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.UnsupportedEncodingException
|
|
||||||
import java.net.MalformedURLException
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.Locale
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
@ -51,6 +42,15 @@ import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import org.openintents.openpgp.IOpenPgpService2
|
import org.openintents.openpgp.IOpenPgpService2
|
||||||
import org.openintents.openpgp.OpenPgpError
|
import org.openintents.openpgp.OpenPgpError
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.UnsupportedEncodingException
|
||||||
|
import java.net.MalformedURLException
|
||||||
|
import java.net.URL
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope(Dispatchers.Default) {
|
class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope(Dispatchers.Default) {
|
||||||
private var serviceConnection: OpenPgpServiceConnection? = null
|
private var serviceConnection: OpenPgpServiceConnection? = null
|
||||||
|
@ -103,16 +103,16 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
||||||
|
|
||||||
// if returning to the source app from a successful AutofillActivity
|
// if returning to the source app from a successful AutofillActivity
|
||||||
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
|
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
|
||||||
event.packageName != null && event.packageName == packageName &&
|
event.packageName != null && event.packageName == packageName &&
|
||||||
resultData != null) {
|
resultData != null) {
|
||||||
bindDecryptAndVerify()
|
bindDecryptAndVerify()
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for webView and trigger accessibility events if window changes
|
// look for webView and trigger accessibility events if window changes
|
||||||
// or if page changes in chrome
|
// or if page changes in chrome
|
||||||
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED &&
|
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED &&
|
||||||
event.packageName != null &&
|
event.packageName != null &&
|
||||||
(event.packageName == "com.android.chrome" || event.packageName == "com.android.browser"))) {
|
(event.packageName == "com.android.chrome" || event.packageName == "com.android.browser"))) {
|
||||||
// there is a chance for getRootInActiveWindow() to return null at any time. save it.
|
// there is a chance for getRootInActiveWindow() to return null at any time. save it.
|
||||||
try {
|
try {
|
||||||
val root = rootInActiveWindow
|
val root = rootInActiveWindow
|
||||||
|
@ -145,8 +145,8 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
||||||
|
|
||||||
// nothing to do if field is keychain app or system ui
|
// nothing to do if field is keychain app or system ui
|
||||||
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED ||
|
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED ||
|
||||||
event.packageName != null && event.packageName == "org.sufficientlysecure.keychain" ||
|
event.packageName != null && event.packageName == "org.sufficientlysecure.keychain" ||
|
||||||
event.packageName != null && event.packageName == "com.android.systemui") {
|
event.packageName != null && event.packageName == "com.android.systemui") {
|
||||||
dismissDialog()
|
dismissDialog()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
||||||
// need to request permission before attempting to draw dialog
|
// need to request permission before attempting to draw dialog
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
|
||||||
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||||
Uri.parse("package:" + getPackageName()))
|
Uri.parse("package:" + getPackageName()))
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
return
|
return
|
||||||
|
@ -283,7 +283,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
||||||
val value = prefs.getString(key, null)
|
val value = prefs.getString(key, null)
|
||||||
val keyLowerCase = key.toLowerCase(Locale.ROOT)
|
val keyLowerCase = key.toLowerCase(Locale.ROOT)
|
||||||
if (value != null && value != "" &&
|
if (value != null && value != "" &&
|
||||||
(webViewUrlLowerCase.contains(keyLowerCase) || keyLowerCase.contains(webViewUrlLowerCase))) {
|
(webViewUrlLowerCase.contains(keyLowerCase) || keyLowerCase.contains(webViewUrlLowerCase))) {
|
||||||
preference = value
|
preference = value
|
||||||
settingsURL = key
|
settingsURL = key
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
||||||
for (i in items.indices) {
|
for (i in items.indices) {
|
||||||
if (autofillFullPath) {
|
if (autofillFullPath) {
|
||||||
itemNames[i] = items[i].path.replace(".gpg", "")
|
itemNames[i] = items[i].path.replace(".gpg", "")
|
||||||
.replace("$passwordDirectory/", "")
|
.replace("$passwordDirectory/", "")
|
||||||
} else {
|
} else {
|
||||||
itemNames[i] = items[i].name.replace(".gpg", "")
|
itemNames[i] = items[i].name.replace(".gpg", "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ private fun Context.matchPreferences(formOrigin: FormOrigin): SharedPreferences
|
||||||
|
|
||||||
class AutofillPublisherChangedException(val formOrigin: FormOrigin) :
|
class AutofillPublisherChangedException(val formOrigin: FormOrigin) :
|
||||||
Exception("The publisher of '${formOrigin.identifier}' changed since an entry was first matched with this app") {
|
Exception("The publisher of '${formOrigin.identifier}' changed since an entry was first matched with this app") {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(formOrigin is FormOrigin.App)
|
require(formOrigin is FormOrigin.App)
|
||||||
}
|
}
|
||||||
|
@ -40,6 +41,7 @@ class AutofillPublisherChangedException(val formOrigin: FormOrigin) :
|
||||||
* Manages "matches", i.e., associations between apps or websites and Password Store entries.
|
* Manages "matches", i.e., associations between apps or websites and Password Store entries.
|
||||||
*/
|
*/
|
||||||
class AutofillMatcher {
|
class AutofillMatcher {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val MAX_NUM_MATCHES = 10
|
private const val MAX_NUM_MATCHES = 10
|
||||||
|
|
||||||
|
@ -172,10 +174,10 @@ class AutofillMatcher {
|
||||||
.minus(deletePathList)
|
.minus(deletePathList)
|
||||||
.minus(oldNewPathMap.values)
|
.minus(oldNewPathMap.values)
|
||||||
.map { match ->
|
.map { match ->
|
||||||
val newPath = oldNewPathMap[match] ?: return@map match
|
val newPath = oldNewPathMap[match] ?: return@map match
|
||||||
d { "Updating match for $key: $match --> $newPath" }
|
d { "Updating match for $key: $match --> $newPath" }
|
||||||
newPath
|
newPath
|
||||||
}.toSet()
|
}.toSet()
|
||||||
if (newMatches != oldMatches)
|
if (newMatches != oldMatches)
|
||||||
prefs.edit { putStringSet(key, newMatches) }
|
prefs.edit { putStringSet(key, newMatches) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,7 @@ data class ClassifiedAutofillScenario<T : Any>(
|
||||||
val currentPassword: List<T>,
|
val currentPassword: List<T>,
|
||||||
val newPassword: List<T>
|
val newPassword: List<T>
|
||||||
) : AutofillScenario<T>() {
|
) : AutofillScenario<T>() {
|
||||||
|
|
||||||
override val allPasswordFields
|
override val allPasswordFields
|
||||||
get() = currentPassword + newPassword
|
get() = currentPassword + newPassword
|
||||||
override val passwordFieldsToFillOnMatch
|
override val passwordFieldsToFillOnMatch
|
||||||
|
@ -148,6 +149,7 @@ data class GenericAutofillScenario<T : Any>(
|
||||||
override val fillUsername: Boolean,
|
override val fillUsername: Boolean,
|
||||||
val genericPassword: List<T>
|
val genericPassword: List<T>
|
||||||
) : AutofillScenario<T>() {
|
) : AutofillScenario<T>() {
|
||||||
|
|
||||||
override val allPasswordFields
|
override val allPasswordFields
|
||||||
get() = genericPassword
|
get() = genericPassword
|
||||||
override val passwordFieldsToFillOnMatch
|
override val passwordFieldsToFillOnMatch
|
||||||
|
|
|
@ -14,10 +14,12 @@ annotation class AutofillDsl
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
interface FieldMatcher {
|
interface FieldMatcher {
|
||||||
|
|
||||||
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
|
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
|
||||||
|
|
||||||
@AutofillDsl
|
@AutofillDsl
|
||||||
class Builder {
|
class Builder {
|
||||||
|
|
||||||
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
|
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
|
||||||
private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
|
private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
|
@ -68,6 +70,7 @@ class SingleFieldMatcher(
|
||||||
|
|
||||||
@AutofillDsl
|
@AutofillDsl
|
||||||
class Builder {
|
class Builder {
|
||||||
|
|
||||||
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
|
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
|
||||||
private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
|
private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
|
@ -169,6 +172,7 @@ class AutofillRule private constructor(
|
||||||
private val applyInSingleOriginMode: Boolean,
|
private val applyInSingleOriginMode: Boolean,
|
||||||
private val applyOnManualRequestOnly: Boolean
|
private val applyOnManualRequestOnly: Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var ruleId = 1
|
private var ruleId = 1
|
||||||
}
|
}
|
||||||
|
@ -304,6 +308,7 @@ class AutofillStrategy private constructor(private val rules: List<AutofillRule>
|
||||||
|
|
||||||
@AutofillDsl
|
@AutofillDsl
|
||||||
class Builder {
|
class Builder {
|
||||||
|
|
||||||
private val rules: MutableList<AutofillRule> = mutableListOf()
|
private val rules: MutableList<AutofillRule> = mutableListOf()
|
||||||
|
|
||||||
fun rule(
|
fun rule(
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.io.File
|
||||||
* A unique identifier for either an Android app (package name) or a website (origin minus port).
|
* A unique identifier for either an Android app (package name) or a website (origin minus port).
|
||||||
*/
|
*/
|
||||||
sealed class FormOrigin(open val identifier: String) {
|
sealed class FormOrigin(open val identifier: String) {
|
||||||
|
|
||||||
data class Web(override val identifier: String) : FormOrigin(identifier)
|
data class Web(override val identifier: String) : FormOrigin(identifier)
|
||||||
data class App(override val identifier: String) : FormOrigin(identifier)
|
data class App(override val identifier: String) : FormOrigin(identifier)
|
||||||
|
|
||||||
|
@ -198,6 +199,7 @@ class FillableForm private constructor(
|
||||||
private val ignoredIds: List<AutofillId>,
|
private val ignoredIds: List<AutofillId>,
|
||||||
private val saveFlags: Int?
|
private val saveFlags: Int?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun makeFillInDataset(
|
fun makeFillInDataset(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
|
|
@ -22,16 +22,6 @@ import com.zeapo.pwdstore.autofill.oreo.AutofillPreferences
|
||||||
import com.zeapo.pwdstore.autofill.oreo.Credentials
|
import com.zeapo.pwdstore.autofill.oreo.Credentials
|
||||||
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
||||||
import com.zeapo.pwdstore.autofill.oreo.FillableForm
|
import com.zeapo.pwdstore.autofill.oreo.FillableForm
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
import java.io.UnsupportedEncodingException
|
|
||||||
import kotlin.coroutines.Continuation
|
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.resumeWithException
|
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
@ -42,6 +32,16 @@ import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
||||||
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
|
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
|
||||||
import org.openintents.openpgp.IOpenPgpService2
|
import org.openintents.openpgp.IOpenPgpService2
|
||||||
import org.openintents.openpgp.OpenPgpError
|
import org.openintents.openpgp.OpenPgpError
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.UnsupportedEncodingException
|
||||||
|
import kotlin.coroutines.Continuation
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
class AutofillDecryptActivity : Activity(), CoroutineScope {
|
class AutofillDecryptActivity : Activity(), CoroutineScope {
|
||||||
|
@ -214,9 +214,9 @@ class AutofillDecryptActivity : Activity(), CoroutineScope {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
"Error from OpenKeyChain: ${error.message}",
|
"Error from OpenKeyChain: ${error.message}",
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
e { "OpenPgpApi ACTION_DECRYPT_VERIFY failed (${error.errorId}): ${error.message}" }
|
e { "OpenPgpApi ACTION_DECRYPT_VERIFY failed (${error.errorId}): ${error.message}" }
|
||||||
|
|
|
@ -78,19 +78,19 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
||||||
try {
|
try {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val packageInfo =
|
val packageInfo =
|
||||||
packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA)
|
packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA)
|
||||||
val installTime = DateUtils.getRelativeTimeSpanString(packageInfo.firstInstallTime)
|
val installTime = DateUtils.getRelativeTimeSpanString(packageInfo.firstInstallTime)
|
||||||
warningAppInstallDate.text =
|
warningAppInstallDate.text =
|
||||||
getString(R.string.oreo_autofill_warning_publisher_install_time, installTime)
|
getString(R.string.oreo_autofill_warning_publisher_install_time, installTime)
|
||||||
val appInfo =
|
val appInfo =
|
||||||
packageManager.getApplicationInfo(appPackage, PackageManager.GET_META_DATA)
|
packageManager.getApplicationInfo(appPackage, PackageManager.GET_META_DATA)
|
||||||
warningAppName.text = "“${packageManager.getApplicationLabel(appInfo)}”"
|
warningAppName.text = "“${packageManager.getApplicationLabel(appInfo)}”"
|
||||||
|
|
||||||
val currentHash = computeCertificatesHash(this@AutofillPublisherChangedActivity, appPackage)
|
val currentHash = computeCertificatesHash(this@AutofillPublisherChangedActivity, appPackage)
|
||||||
warningAppAdvancedInfo.text = getString(
|
warningAppAdvancedInfo.text = getString(
|
||||||
R.string.oreo_autofill_warning_publisher_advanced_info_template,
|
R.string.oreo_autofill_warning_publisher_advanced_info_template,
|
||||||
appPackage,
|
appPackage,
|
||||||
currentHash
|
currentHash
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
|
@ -52,13 +52,28 @@ import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
||||||
import com.zeapo.pwdstore.ui.dialogs.PasswordGeneratorDialogFragment
|
import com.zeapo.pwdstore.ui.dialogs.PasswordGeneratorDialogFragment
|
||||||
import com.zeapo.pwdstore.ui.dialogs.XkPasswordGeneratorDialogFragment
|
import com.zeapo.pwdstore.ui.dialogs.XkPasswordGeneratorDialogFragment
|
||||||
import com.zeapo.pwdstore.utils.Otp
|
import com.zeapo.pwdstore.utils.Otp
|
||||||
import java.io.ByteArrayInputStream
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_container_decrypt
|
||||||
import java.io.ByteArrayOutputStream
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_copy_otp
|
||||||
import java.io.File
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_copy_username
|
||||||
import java.nio.charset.Charset
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_show
|
||||||
import java.util.Date
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_show_layout
|
||||||
import kotlinx.android.synthetic.main.decrypt_layout.*
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_toggle_show
|
||||||
import kotlinx.android.synthetic.main.encrypt_layout.*
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_otp_show
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_otp_show_label
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_category_decrypt
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_file
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_last_changed
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_show
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_show_label
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_toggle_show
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_username_show
|
||||||
|
import kotlinx.android.synthetic.main.decrypt_layout.crypto_username_show_label
|
||||||
|
import kotlinx.android.synthetic.main.encrypt_layout.crypto_extra_edit
|
||||||
|
import kotlinx.android.synthetic.main.encrypt_layout.crypto_password_category
|
||||||
|
import kotlinx.android.synthetic.main.encrypt_layout.crypto_password_edit
|
||||||
|
import kotlinx.android.synthetic.main.encrypt_layout.crypto_password_file_edit
|
||||||
|
import kotlinx.android.synthetic.main.encrypt_layout.encrypt_username
|
||||||
|
import kotlinx.android.synthetic.main.encrypt_layout.generate_password
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
||||||
|
@ -74,6 +89,11 @@ import org.apache.commons.io.FileUtils
|
||||||
import org.apache.commons.io.FilenameUtils
|
import org.apache.commons.io.FilenameUtils
|
||||||
import org.openintents.openpgp.IOpenPgpService2
|
import org.openintents.openpgp.IOpenPgpService2
|
||||||
import org.openintents.openpgp.OpenPgpError
|
import org.openintents.openpgp.OpenPgpError
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
private val clipboard by lazy { getSystemService<ClipboardManager>() }
|
private val clipboard by lazy { getSystemService<ClipboardManager>() }
|
||||||
|
@ -96,10 +116,10 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
private val name: String by lazy { getName(fullPath) }
|
private val name: String by lazy { getName(fullPath) }
|
||||||
private val lastChangedString: CharSequence by lazy {
|
private val lastChangedString: CharSequence by lazy {
|
||||||
getLastChangedString(
|
getLastChangedString(
|
||||||
intent.getLongExtra(
|
intent.getLongExtra(
|
||||||
"LAST_CHANGED_TIMESTAMP",
|
"LAST_CHANGED_TIMESTAMP",
|
||||||
-1L
|
-1L
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
private val relativeParentPath: String by lazy { getParentPath(fullPath, repoPath) }
|
private val relativeParentPath: String by lazy { getParentPath(fullPath, repoPath) }
|
||||||
|
@ -325,8 +345,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
val pi: PendingIntent? = result.getParcelableExtra(RESULT_INTENT)
|
val pi: PendingIntent? = result.getParcelableExtra(RESULT_INTENT)
|
||||||
try {
|
try {
|
||||||
this@PgpActivity.startIntentSenderFromChild(
|
this@PgpActivity.startIntentSenderFromChild(
|
||||||
this@PgpActivity, pi?.intentSender, requestCode,
|
this@PgpActivity, pi?.intentSender, requestCode,
|
||||||
null, 0, 0, 0
|
null, 0, 0, 0
|
||||||
)
|
)
|
||||||
} catch (e: IntentSender.SendIntentException) {
|
} catch (e: IntentSender.SendIntentException) {
|
||||||
e(e) { "SendIntentException" }
|
e(e) { "SendIntentException" }
|
||||||
|
@ -401,8 +421,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
HoldToShowPasswordTransformation(
|
HoldToShowPasswordTransformation(
|
||||||
crypto_password_toggle_show,
|
crypto_password_toggle_show,
|
||||||
Runnable { crypto_password_show.text = entry.password }
|
Runnable { crypto_password_show.text = entry.password }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,19 +475,19 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
if (entry.hasTotp()) {
|
if (entry.hasTotp()) {
|
||||||
crypto_copy_otp.setOnClickListener {
|
crypto_copy_otp.setOnClickListener {
|
||||||
copyOtpToClipBoard(
|
copyOtpToClipBoard(
|
||||||
Otp.calculateCode(
|
Otp.calculateCode(
|
||||||
entry.totpSecret,
|
entry.totpSecret,
|
||||||
Date().time / (1000 * entry.totpPeriod),
|
Date().time / (1000 * entry.totpPeriod),
|
||||||
entry.totpAlgorithm,
|
entry.totpAlgorithm,
|
||||||
entry.digits)
|
entry.digits)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
crypto_otp_show.text =
|
crypto_otp_show.text =
|
||||||
Otp.calculateCode(
|
Otp.calculateCode(
|
||||||
entry.totpSecret,
|
entry.totpSecret,
|
||||||
Date().time / (1000 * entry.totpPeriod),
|
Date().time / (1000 * entry.totpPeriod),
|
||||||
entry.totpAlgorithm,
|
entry.totpAlgorithm,
|
||||||
entry.digits)
|
entry.digits)
|
||||||
} else {
|
} else {
|
||||||
// we only want to calculate and show HOTP if the user requests it
|
// we only want to calculate and show HOTP if the user requests it
|
||||||
crypto_copy_otp.setOnClickListener {
|
crypto_copy_otp.setOnClickListener {
|
||||||
|
@ -482,31 +502,31 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
val checkInflater = LayoutInflater.from(this@PgpActivity)
|
val checkInflater = LayoutInflater.from(this@PgpActivity)
|
||||||
val checkLayout = checkInflater.inflate(R.layout.otp_confirm_layout, null)
|
val checkLayout = checkInflater.inflate(R.layout.otp_confirm_layout, null)
|
||||||
val rememberCheck: CheckBox =
|
val rememberCheck: CheckBox =
|
||||||
checkLayout.findViewById(R.id.hotp_remember_checkbox)
|
checkLayout.findViewById(R.id.hotp_remember_checkbox)
|
||||||
val dialogBuilder = MaterialAlertDialogBuilder(this@PgpActivity)
|
val dialogBuilder = MaterialAlertDialogBuilder(this@PgpActivity)
|
||||||
dialogBuilder.setView(checkLayout)
|
dialogBuilder.setView(checkLayout)
|
||||||
dialogBuilder.setMessage(R.string.dialog_update_body)
|
dialogBuilder.setMessage(R.string.dialog_update_body)
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setPositiveButton(R.string.dialog_update_positive) { _, _ ->
|
.setPositiveButton(R.string.dialog_update_positive) { _, _ ->
|
||||||
run {
|
run {
|
||||||
calculateAndCommitHotp(entry)
|
calculateAndCommitHotp(entry)
|
||||||
if (rememberCheck.isChecked) {
|
if (rememberCheck.isChecked) {
|
||||||
settings.edit {
|
|
||||||
putBoolean("hotp_remember_check", true)
|
|
||||||
putBoolean("hotp_remember_choice", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.dialog_update_negative) { _, _ ->
|
|
||||||
run {
|
|
||||||
calculateHotp(entry)
|
|
||||||
settings.edit {
|
settings.edit {
|
||||||
putBoolean("hotp_remember_check", true)
|
putBoolean("hotp_remember_check", true)
|
||||||
putBoolean("hotp_remember_choice", false)
|
putBoolean("hotp_remember_choice", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.dialog_update_negative) { _, _ ->
|
||||||
|
run {
|
||||||
|
calculateHotp(entry)
|
||||||
|
settings.edit {
|
||||||
|
putBoolean("hotp_remember_check", true)
|
||||||
|
putBoolean("hotp_remember_choice", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
val updateDialog = dialogBuilder.create()
|
val updateDialog = dialogBuilder.create()
|
||||||
updateDialog.setTitle(R.string.dialog_update_title)
|
updateDialog.setTitle(R.string.dialog_update_title)
|
||||||
updateDialog.show()
|
updateDialog.show()
|
||||||
|
@ -612,11 +632,11 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
|
|
||||||
if (shouldGeneratePassword) {
|
if (shouldGeneratePassword) {
|
||||||
val directoryStructure =
|
val directoryStructure =
|
||||||
AutofillPreferences.directoryStructure(applicationContext)
|
AutofillPreferences.directoryStructure(applicationContext)
|
||||||
val entry = PasswordEntry(content)
|
val entry = PasswordEntry(content)
|
||||||
returnIntent.putExtra("PASSWORD", entry.password)
|
returnIntent.putExtra("PASSWORD", entry.password)
|
||||||
val username = PasswordEntry(content).username
|
val username = PasswordEntry(content).username
|
||||||
?: directoryStructure.getUsernameFor(file)
|
?: directoryStructure.getUsernameFor(file)
|
||||||
returnIntent.putExtra("USERNAME", username)
|
returnIntent.putExtra("USERNAME", username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,9 +660,9 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
generate_password?.setOnClickListener {
|
generate_password?.setOnClickListener {
|
||||||
when (settings.getString("pref_key_pwgen_type", KEY_PWGEN_TYPE_CLASSIC)) {
|
when (settings.getString("pref_key_pwgen_type", KEY_PWGEN_TYPE_CLASSIC)) {
|
||||||
KEY_PWGEN_TYPE_CLASSIC -> PasswordGeneratorDialogFragment()
|
KEY_PWGEN_TYPE_CLASSIC -> PasswordGeneratorDialogFragment()
|
||||||
.show(supportFragmentManager, "generator")
|
.show(supportFragmentManager, "generator")
|
||||||
KEY_PWGEN_TYPE_XKPASSWD -> XkPasswordGeneratorDialogFragment()
|
KEY_PWGEN_TYPE_XKPASSWD -> XkPasswordGeneratorDialogFragment()
|
||||||
.show(supportFragmentManager, "xkpwgenerator")
|
.show(supportFragmentManager, "xkpwgenerator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,7 +736,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
RESULT_CODE_SUCCESS -> {
|
RESULT_CODE_SUCCESS -> {
|
||||||
try {
|
try {
|
||||||
val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)
|
val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)
|
||||||
?: LongArray(0)
|
?: LongArray(0)
|
||||||
val keys = ids.map { it.toString() }.toSet()
|
val keys = ids.map { it.toString() }.toSet()
|
||||||
|
|
||||||
// use Long
|
// use Long
|
||||||
|
@ -777,7 +797,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private inner class HoldToShowPasswordTransformation constructor(button: Button, private val onToggle: Runnable) :
|
private inner class HoldToShowPasswordTransformation constructor(button: Button, private val onToggle: Runnable) :
|
||||||
PasswordTransformationMethod(), View.OnTouchListener {
|
PasswordTransformationMethod(), View.OnTouchListener {
|
||||||
|
|
||||||
private var shown = false
|
private var shown = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -856,10 +877,10 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
sendIntent.putExtra(Intent.EXTRA_TEXT, passwordEntry?.password)
|
sendIntent.putExtra(Intent.EXTRA_TEXT, passwordEntry?.password)
|
||||||
sendIntent.type = "text/plain"
|
sendIntent.type = "text/plain"
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent.createChooser(
|
Intent.createChooser(
|
||||||
sendIntent,
|
sendIntent,
|
||||||
resources.getText(R.string.send_plaintext_password_to)
|
resources.getText(R.string.send_plaintext_password_to)
|
||||||
)
|
)
|
||||||
) // Always show a picker to give the user a chance to cancel
|
) // Always show a picker to give the user a chance to cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,7 +991,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||||
* Gets the relative path to the repository
|
* Gets the relative path to the repository
|
||||||
*/
|
*/
|
||||||
fun getRelativePath(fullPath: String, repositoryPath: String): String =
|
fun getRelativePath(fullPath: String, repositoryPath: String): String =
|
||||||
fullPath.replace(repositoryPath, "").replace("/+".toRegex(), "/")
|
fullPath.replace(repositoryPath, "").replace("/+".toRegex(), "/")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Parent path, relative to the repository
|
* Gets the Parent path, relative to the repository
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.net.URI
|
||||||
* tasks and makes sense to be held here.
|
* tasks and makes sense to be held here.
|
||||||
*/
|
*/
|
||||||
abstract class BaseGitActivity : AppCompatActivity() {
|
abstract class BaseGitActivity : AppCompatActivity() {
|
||||||
|
|
||||||
lateinit var protocol: Protocol
|
lateinit var protocol: Protocol
|
||||||
lateinit var connectionMode: ConnectionMode
|
lateinit var connectionMode: ConnectionMode
|
||||||
var url: String? = null
|
var url: String? = null
|
||||||
|
@ -180,7 +181,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
op.executeAfterAuthentication(connectionMode, serverUser,
|
op.executeAfterAuthentication(connectionMode, serverUser,
|
||||||
File("$filesDir/.ssh_key"), identity)
|
File("$filesDir/.ssh_key"), identity)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
|
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
|
||||||
|
|
|
@ -7,11 +7,11 @@ package com.zeapo.pwdstore.git
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.api.GitCommand
|
import org.eclipse.jgit.api.GitCommand
|
||||||
import org.eclipse.jgit.api.PushCommand
|
import org.eclipse.jgit.api.PushCommand
|
||||||
import org.eclipse.jgit.api.RebaseCommand
|
import org.eclipse.jgit.api.RebaseCommand
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
|
class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
|
||||||
private lateinit var commands: List<GitCommand<out Any>>
|
private lateinit var commands: List<GitCommand<out Any>>
|
||||||
|
@ -26,14 +26,14 @@ class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperatio
|
||||||
val branchName = "conflicting-master-${System.currentTimeMillis()}"
|
val branchName = "conflicting-master-${System.currentTimeMillis()}"
|
||||||
|
|
||||||
this.commands = listOf(
|
this.commands = listOf(
|
||||||
// abort the rebase
|
// abort the rebase
|
||||||
git.rebase().setOperation(RebaseCommand.Operation.ABORT),
|
git.rebase().setOperation(RebaseCommand.Operation.ABORT),
|
||||||
// git checkout -b conflict-branch
|
// git checkout -b conflict-branch
|
||||||
git.checkout().setCreateBranch(true).setName(branchName),
|
git.checkout().setCreateBranch(true).setName(branchName),
|
||||||
// push the changes
|
// push the changes
|
||||||
git.push().setRemote("origin"),
|
git.push().setRemote("origin"),
|
||||||
// switch back to master
|
// switch back to master
|
||||||
git.checkout().setName("master")
|
git.checkout().setName("master")
|
||||||
)
|
)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,11 @@ class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperatio
|
||||||
val git = Git(repository)
|
val git = Git(repository)
|
||||||
if (!git.repository.repositoryState.isRebasing) {
|
if (!git.repository.repositoryState.isRebasing) {
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
|
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
|
||||||
.setMessage("The repository is not rebasing, no need to push to another branch")
|
.setMessage("The repository is not rebasing, no need to push to another branch")
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
|
||||||
callingActivity.finish()
|
callingActivity.finish()
|
||||||
}.show()
|
}.show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,26 +59,26 @@ class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperatio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GitAsyncTask(callingActivity, true, this, null)
|
GitAsyncTask(callingActivity, true, this, null)
|
||||||
.execute(*this.commands.toTypedArray())
|
.execute(*this.commands.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(errorMessage: String) {
|
override fun onError(errorMessage: String) {
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
||||||
.setMessage("Error occurred when checking out another branch operation $errorMessage")
|
.setMessage("Error occurred when checking out another branch operation $errorMessage")
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
|
||||||
callingActivity.finish()
|
callingActivity.finish()
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess() {
|
override fun onSuccess() {
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
|
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
|
||||||
.setMessage("There was a conflict when trying to rebase. " +
|
.setMessage("There was a conflict when trying to rebase. " +
|
||||||
"Your local master branch was pushed to another branch named conflicting-master-....\n" +
|
"Your local master branch was pushed to another branch named conflicting-master-....\n" +
|
||||||
"Use this branch to resolve conflict on your computer")
|
"Use this branch to resolve conflict on your computer")
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
|
||||||
callingActivity.finish()
|
callingActivity.finish()
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.CloneCommand
|
import org.eclipse.jgit.api.CloneCommand
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clone operation
|
* Creates a new clone operation
|
||||||
|
@ -28,9 +28,9 @@ class CloneOperation(fileDir: File, callingActivity: Activity) : GitOperation(fi
|
||||||
*/
|
*/
|
||||||
fun setCommand(uri: String): CloneOperation {
|
fun setCommand(uri: String): CloneOperation {
|
||||||
this.command = Git.cloneRepository()
|
this.command = Git.cloneRepository()
|
||||||
.setCloneAllBranches(true)
|
.setCloneAllBranches(true)
|
||||||
.setDirectory(repository?.workTree)
|
.setDirectory(repository?.workTree)
|
||||||
.setURI(uri)
|
.setURI(uri)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +67,12 @@ class CloneOperation(fileDir: File, callingActivity: Activity) : GitOperation(fi
|
||||||
override fun onError(errorMessage: String) {
|
override fun onError(errorMessage: String) {
|
||||||
super.onError(errorMessage)
|
super.onError(errorMessage)
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
||||||
.setMessage("Error occured during the clone operation, " +
|
.setMessage("Error occured during the clone operation, " +
|
||||||
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
||||||
errorMessage +
|
errorMessage +
|
||||||
"\nPlease check the FAQ for possible reasons why this error might occur.")
|
"\nPlease check the FAQ for possible reasons why this error might occur.")
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,10 @@ import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.zeapo.pwdstore.PasswordStore;
|
import com.zeapo.pwdstore.PasswordStore;
|
||||||
import com.zeapo.pwdstore.R;
|
import com.zeapo.pwdstore.R;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import org.eclipse.jgit.api.CommitCommand;
|
import org.eclipse.jgit.api.CommitCommand;
|
||||||
import org.eclipse.jgit.api.GitCommand;
|
import org.eclipse.jgit.api.GitCommand;
|
||||||
import org.eclipse.jgit.api.PullCommand;
|
import org.eclipse.jgit.api.PullCommand;
|
||||||
|
@ -21,6 +22,8 @@ import org.eclipse.jgit.api.StatusCommand;
|
||||||
import org.eclipse.jgit.transport.PushResult;
|
import org.eclipse.jgit.transport.PushResult;
|
||||||
import org.eclipse.jgit.transport.RemoteRefUpdate;
|
import org.eclipse.jgit.transport.RemoteRefUpdate;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
|
public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
|
||||||
private WeakReference<Activity> activityWeakReference;
|
private WeakReference<Activity> activityWeakReference;
|
||||||
private boolean refreshListOnEnd;
|
private boolean refreshListOnEnd;
|
||||||
|
@ -29,10 +32,10 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
|
||||||
private Intent finishWithResultOnEnd;
|
private Intent finishWithResultOnEnd;
|
||||||
|
|
||||||
public GitAsyncTask(
|
public GitAsyncTask(
|
||||||
Activity activity,
|
Activity activity,
|
||||||
boolean refreshListOnEnd,
|
boolean refreshListOnEnd,
|
||||||
GitOperation operation,
|
GitOperation operation,
|
||||||
Intent finishWithResultOnEnd) {
|
Intent finishWithResultOnEnd) {
|
||||||
this.activityWeakReference = new WeakReference<>(activity);
|
this.activityWeakReference = new WeakReference<>(activity);
|
||||||
this.refreshListOnEnd = refreshListOnEnd;
|
this.refreshListOnEnd = refreshListOnEnd;
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
|
@ -47,7 +50,7 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
|
||||||
|
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
this.dialog.setMessage(
|
this.dialog.setMessage(
|
||||||
getActivity().getResources().getString(R.string.running_dialog_text));
|
getActivity().getResources().getString(R.string.running_dialog_text));
|
||||||
this.dialog.setCancelable(false);
|
this.dialog.setCancelable(false);
|
||||||
this.dialog.show();
|
this.dialog.show();
|
||||||
}
|
}
|
||||||
|
@ -85,13 +88,13 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
|
||||||
case NON_EXISTING:
|
case NON_EXISTING:
|
||||||
case NOT_ATTEMPTED:
|
case NOT_ATTEMPTED:
|
||||||
return activity.getString(R.string.git_push_generic_error)
|
return activity.getString(R.string.git_push_generic_error)
|
||||||
+ rru.getStatus().name();
|
+ rru.getStatus().name();
|
||||||
case REJECTED_OTHER_REASON:
|
case REJECTED_OTHER_REASON:
|
||||||
if ("non-fast-forward".equals(rru.getMessage())) {
|
if ("non-fast-forward".equals(rru.getMessage())) {
|
||||||
return activity.getString(R.string.git_push_other_error);
|
return activity.getString(R.string.git_push_other_error);
|
||||||
} else {
|
} else {
|
||||||
return activity.getString(R.string.git_push_generic_error)
|
return activity.getString(R.string.git_push_generic_error)
|
||||||
+ rru.getMessage();
|
+ rru.getMessage();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -53,9 +53,9 @@ class GitConfigActivity : BaseGitActivity() {
|
||||||
val name = binding.gitUserName.text.toString().trim()
|
val name = binding.gitUserName.text.toString().trim()
|
||||||
if (!email.matches(Patterns.EMAIL_ADDRESS.toRegex())) {
|
if (!email.matches(Patterns.EMAIL_ADDRESS.toRegex())) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(getString(R.string.invalid_email_dialog_text))
|
.setMessage(getString(R.string.invalid_email_dialog_text))
|
||||||
.setPositiveButton(getString(R.string.dialog_ok), null)
|
.setPositiveButton(getString(R.string.dialog_ok), null)
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
settings.edit {
|
settings.edit {
|
||||||
putString("git_config_user_email", email)
|
putString("git_config_user_email", email)
|
||||||
|
|
|
@ -25,11 +25,11 @@ import com.zeapo.pwdstore.git.config.SshConfigSessionFactory
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||||
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.GitCommand
|
import org.eclipse.jgit.api.GitCommand
|
||||||
import org.eclipse.jgit.lib.Repository
|
import org.eclipse.jgit.lib.Repository
|
||||||
import org.eclipse.jgit.transport.SshSessionFactory
|
import org.eclipse.jgit.transport.SshSessionFactory
|
||||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider
|
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new git operation
|
* Creates a new git operation
|
||||||
|
@ -260,14 +260,14 @@ abstract class GitOperation(fileDir: File, internal val callingActivity: Activit
|
||||||
// Clear various auth related fields on failure
|
// Clear various auth related fields on failure
|
||||||
if (SshSessionFactory.getInstance() is SshApiSessionFactory) {
|
if (SshSessionFactory.getInstance() is SshApiSessionFactory) {
|
||||||
PreferenceManager.getDefaultSharedPreferences(callingActivity.applicationContext)
|
PreferenceManager.getDefaultSharedPreferences(callingActivity.applicationContext)
|
||||||
.edit { putString("ssh_openkeystore_keyid", null) }
|
.edit { putString("ssh_openkeystore_keyid", null) }
|
||||||
callingActivity.applicationContext
|
callingActivity.applicationContext
|
||||||
.getEncryptedPrefs("git_operation")
|
.getEncryptedPrefs("git_operation")
|
||||||
.edit { remove("ssh_key_local_passphrase") }
|
.edit { remove("ssh_key_local_passphrase") }
|
||||||
} else if (SshSessionFactory.getInstance() is GitConfigSessionFactory) {
|
} else if (SshSessionFactory.getInstance() is GitConfigSessionFactory) {
|
||||||
callingActivity.applicationContext
|
callingActivity.applicationContext
|
||||||
.getEncryptedPrefs("git_operation")
|
.getEncryptedPrefs("git_operation")
|
||||||
.edit { remove("https_password") }
|
.edit { remove("https_password") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,17 +56,17 @@ open class GitOperationActivity : BaseGitActivity() {
|
||||||
private fun syncRepository(operation: Int) {
|
private fun syncRepository(operation: Int) {
|
||||||
if (serverUser.isEmpty() || serverHostname.isEmpty() || url.isNullOrEmpty())
|
if (serverUser.isEmpty() || serverHostname.isEmpty() || url.isNullOrEmpty())
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(getString(R.string.set_information_dialog_text))
|
.setMessage(getString(R.string.set_information_dialog_text))
|
||||||
.setPositiveButton(getString(R.string.dialog_positive)) { _, _ ->
|
.setPositiveButton(getString(R.string.dialog_positive)) { _, _ ->
|
||||||
val intent = Intent(this, UserPreference::class.java)
|
val intent = Intent(this, UserPreference::class.java)
|
||||||
startActivityForResult(intent, REQUEST_PULL)
|
startActivityForResult(intent, REQUEST_PULL)
|
||||||
}
|
}
|
||||||
.setNegativeButton(getString(R.string.dialog_negative)) { _, _ ->
|
.setNegativeButton(getString(R.string.dialog_negative)) { _, _ ->
|
||||||
// do nothing :(
|
// do nothing :(
|
||||||
setResult(RESULT_OK)
|
setResult(RESULT_OK)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
else {
|
else {
|
||||||
// check that the remote origin is here, else add it
|
// check that the remote origin is here, else add it
|
||||||
PasswordRepository.addRemote("origin", url!!, true)
|
PasswordRepository.addRemote("origin", url!!, true)
|
||||||
|
|
|
@ -144,27 +144,27 @@ class GitServerConfigActivity : BaseGitActivity() {
|
||||||
val localDirFiles = localDir.listFiles() ?: emptyArray()
|
val localDirFiles = localDir.listFiles() ?: emptyArray()
|
||||||
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
|
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
|
||||||
if (localDir.exists() && localDirFiles.isNotEmpty() &&
|
if (localDir.exists() && localDirFiles.isNotEmpty() &&
|
||||||
!(localDirFiles.size == 1 && localDirFiles[0].name == ".git")) {
|
!(localDirFiles.size == 1 && localDirFiles[0].name == ".git")) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.dialog_delete_title)
|
.setTitle(R.string.dialog_delete_title)
|
||||||
.setMessage(resources.getString(R.string.dialog_delete_msg) + " " + localDir.toString())
|
.setMessage(resources.getString(R.string.dialog_delete_msg) + " " + localDir.toString())
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setPositiveButton(R.string.dialog_delete) { dialog, _ ->
|
.setPositiveButton(R.string.dialog_delete) { dialog, _ ->
|
||||||
try {
|
try {
|
||||||
localDir.deleteRecursively()
|
localDir.deleteRecursively()
|
||||||
launchGitOperation(REQUEST_CLONE)
|
launchGitOperation(REQUEST_CLONE)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
// TODO Handle the exception correctly if we are unable to delete the directory...
|
// TODO Handle the exception correctly if we are unable to delete the directory...
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
|
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
|
||||||
} finally {
|
} finally {
|
||||||
dialog.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.dialog_do_not_delete) { dialog, _ ->
|
|
||||||
dialog.cancel()
|
dialog.cancel()
|
||||||
}
|
}
|
||||||
.show()
|
}
|
||||||
|
.setNegativeButton(R.string.dialog_do_not_delete) { dialog, _ ->
|
||||||
|
dialog.cancel()
|
||||||
|
}
|
||||||
|
.show()
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
// Silently delete & replace the lone .git folder if it exists
|
// Silently delete & replace the lone .git folder if it exists
|
||||||
|
|
|
@ -8,9 +8,9 @@ import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.api.PullCommand
|
import org.eclipse.jgit.api.PullCommand
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new git operation
|
* Creates a new git operation
|
||||||
|
@ -27,9 +27,9 @@ class PullOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
|
||||||
*/
|
*/
|
||||||
fun setCommand(): PullOperation {
|
fun setCommand(): PullOperation {
|
||||||
this.command = Git(repository)
|
this.command = Git(repository)
|
||||||
.pull()
|
.pull()
|
||||||
.setRebase(true)
|
.setRebase(true)
|
||||||
.setRemote("origin")
|
.setRemote("origin")
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,12 +41,12 @@ class PullOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
|
||||||
override fun onError(errorMessage: String) {
|
override fun onError(errorMessage: String) {
|
||||||
super.onError(errorMessage)
|
super.onError(errorMessage)
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
||||||
.setMessage("Error occured during the pull operation, " +
|
.setMessage("Error occured during the pull operation, " +
|
||||||
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
||||||
errorMessage +
|
errorMessage +
|
||||||
"\nPlease check the FAQ for possible reasons why this error might occur.")
|
"\nPlease check the FAQ for possible reasons why this error might occur.")
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.api.PushCommand
|
import org.eclipse.jgit.api.PushCommand
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new git operation
|
* Creates a new git operation
|
||||||
|
@ -27,9 +27,9 @@ class PushOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
|
||||||
*/
|
*/
|
||||||
fun setCommand(): PushOperation {
|
fun setCommand(): PushOperation {
|
||||||
this.command = Git(repository)
|
this.command = Git(repository)
|
||||||
.push()
|
.push()
|
||||||
.setPushAll()
|
.setPushAll()
|
||||||
.setRemote("origin")
|
.setRemote("origin")
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,9 +42,9 @@ class PushOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
|
||||||
// TODO handle the "Nothing to push" case
|
// TODO handle the "Nothing to push" case
|
||||||
super.onError(errorMessage)
|
super.onError(errorMessage)
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
||||||
.setMessage(callingActivity.getString(R.string.jgit_error_push_dialog_text) + errorMessage)
|
.setMessage(callingActivity.getString(R.string.jgit_error_push_dialog_text) + errorMessage)
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.AddCommand
|
import org.eclipse.jgit.api.AddCommand
|
||||||
import org.eclipse.jgit.api.FetchCommand
|
import org.eclipse.jgit.api.FetchCommand
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.api.ResetCommand
|
import org.eclipse.jgit.api.ResetCommand
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new git operation
|
* Creates a new git operation
|
||||||
|
@ -21,6 +21,7 @@ import org.eclipse.jgit.api.ResetCommand
|
||||||
* @param callingActivity the calling activity
|
* @param callingActivity the calling activity
|
||||||
*/
|
*/
|
||||||
class ResetToRemoteOperation(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
|
class ResetToRemoteOperation(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
|
||||||
|
|
||||||
private var addCommand: AddCommand? = null
|
private var addCommand: AddCommand? = null
|
||||||
private var fetchCommand: FetchCommand? = null
|
private var fetchCommand: FetchCommand? = null
|
||||||
private var resetCommand: ResetCommand? = null
|
private var resetCommand: ResetCommand? = null
|
||||||
|
@ -41,18 +42,18 @@ class ResetToRemoteOperation(fileDir: File, callingActivity: Activity) : GitOper
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
this.fetchCommand?.setCredentialsProvider(this.provider)
|
this.fetchCommand?.setCredentialsProvider(this.provider)
|
||||||
GitAsyncTask(callingActivity, false, this, Intent())
|
GitAsyncTask(callingActivity, false, this, Intent())
|
||||||
.execute(this.addCommand, this.fetchCommand, this.resetCommand)
|
.execute(this.addCommand, this.fetchCommand, this.resetCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(errorMessage: String) {
|
override fun onError(errorMessage: String) {
|
||||||
super.onError(errorMessage)
|
super.onError(errorMessage)
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
||||||
.setMessage("Error occured during the sync operation, " +
|
.setMessage("Error occured during the sync operation, " +
|
||||||
"\nPlease check the FAQ for possible reasons why this error might occur." +
|
"\nPlease check the FAQ for possible reasons why this error might occur." +
|
||||||
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
||||||
errorMessage)
|
errorMessage)
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,13 @@ import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.jgit.api.AddCommand
|
import org.eclipse.jgit.api.AddCommand
|
||||||
import org.eclipse.jgit.api.CommitCommand
|
import org.eclipse.jgit.api.CommitCommand
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.api.PullCommand
|
import org.eclipse.jgit.api.PullCommand
|
||||||
import org.eclipse.jgit.api.PushCommand
|
import org.eclipse.jgit.api.PushCommand
|
||||||
import org.eclipse.jgit.api.StatusCommand
|
import org.eclipse.jgit.api.StatusCommand
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new git operation
|
* Creates a new git operation
|
||||||
|
@ -23,6 +23,7 @@ import org.eclipse.jgit.api.StatusCommand
|
||||||
* @param callingActivity the calling activity
|
* @param callingActivity the calling activity
|
||||||
*/
|
*/
|
||||||
class SyncOperation(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
|
class SyncOperation(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
|
||||||
|
|
||||||
private var addCommand: AddCommand? = null
|
private var addCommand: AddCommand? = null
|
||||||
private var statusCommand: StatusCommand? = null
|
private var statusCommand: StatusCommand? = null
|
||||||
private var commitCommand: CommitCommand? = null
|
private var commitCommand: CommitCommand? = null
|
||||||
|
@ -55,12 +56,12 @@ class SyncOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
|
||||||
override fun onError(errorMessage: String) {
|
override fun onError(errorMessage: String) {
|
||||||
super.onError(errorMessage)
|
super.onError(errorMessage)
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
|
||||||
.setMessage("Error occured during the sync operation, " +
|
.setMessage("Error occured during the sync operation, " +
|
||||||
"\nPlease check the FAQ for possible reasons why this error might occur." +
|
"\nPlease check the FAQ for possible reasons why this error might occur." +
|
||||||
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
|
||||||
errorMessage)
|
errorMessage)
|
||||||
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
|
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,10 @@ import android.app.PendingIntent;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentSender;
|
import android.content.IntentSender;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.jcraft.jsch.Identity;
|
import com.jcraft.jsch.Identity;
|
||||||
import com.jcraft.jsch.JSch;
|
import com.jcraft.jsch.JSch;
|
||||||
|
@ -19,8 +21,7 @@ import com.jcraft.jsch.Session;
|
||||||
import com.jcraft.jsch.UserInfo;
|
import com.jcraft.jsch.UserInfo;
|
||||||
import com.zeapo.pwdstore.R;
|
import com.zeapo.pwdstore.R;
|
||||||
import com.zeapo.pwdstore.git.BaseGitActivity;
|
import com.zeapo.pwdstore.git.BaseGitActivity;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
|
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
|
||||||
import org.eclipse.jgit.transport.CredentialItem;
|
import org.eclipse.jgit.transport.CredentialItem;
|
||||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||||
|
@ -39,6 +40,9 @@ import org.openintents.ssh.authentication.request.SigningRequest;
|
||||||
import org.openintents.ssh.authentication.request.SshPublicKeyRequest;
|
import org.openintents.ssh.authentication.request.SshPublicKeyRequest;
|
||||||
import org.openintents.ssh.authentication.util.SshAuthenticationApiUtils;
|
import org.openintents.ssh.authentication.util.SshAuthenticationApiUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
public class SshApiSessionFactory extends GitConfigSessionFactory {
|
public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
/**
|
/**
|
||||||
* Intent request code indicating a completed signature that should be posted to an outstanding
|
* Intent request code indicating a completed signature that should be posted to an outstanding
|
||||||
|
@ -57,7 +61,7 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected JSch getJSch(@NonNull final OpenSshConfig.Host hc, @NonNull FS fs)
|
protected JSch getJSch(@NonNull final OpenSshConfig.Host hc, @NonNull FS fs)
|
||||||
throws JSchException {
|
throws JSchException {
|
||||||
JSch jsch = super.getJSch(hc, fs);
|
JSch jsch = super.getJSch(hc, fs);
|
||||||
jsch.removeAllIdentity();
|
jsch.removeAllIdentity();
|
||||||
jsch.addIdentity(identity, null);
|
jsch.addIdentity(identity, null);
|
||||||
|
@ -70,28 +74,28 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
session.setConfig("PreferredAuthentications", "publickey");
|
session.setConfig("PreferredAuthentications", "publickey");
|
||||||
|
|
||||||
CredentialsProvider provider =
|
CredentialsProvider provider =
|
||||||
new CredentialsProvider() {
|
new CredentialsProvider() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isInteractive() {
|
public boolean isInteractive() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(CredentialItem... items) {
|
public boolean supports(CredentialItem... items) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean get(URIish uri, CredentialItem... items)
|
public boolean get(URIish uri, CredentialItem... items)
|
||||||
throws UnsupportedCredentialItem {
|
throws UnsupportedCredentialItem {
|
||||||
for (CredentialItem item : items) {
|
for (CredentialItem item : items) {
|
||||||
if (item instanceof CredentialItem.Username) {
|
if (item instanceof CredentialItem.Username) {
|
||||||
((CredentialItem.Username) item).setValue(username);
|
((CredentialItem.Username) item).setValue(username);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
|
UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
|
||||||
session.setUserInfo(userInfo);
|
session.setUserInfo(userInfo);
|
||||||
}
|
}
|
||||||
|
@ -114,14 +118,14 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
* Construct a new IdentityBuilder
|
* Construct a new IdentityBuilder
|
||||||
*
|
*
|
||||||
* @param callingActivity Activity that will be used to launch pending intents and that will
|
* @param callingActivity Activity that will be used to launch pending intents and that will
|
||||||
* receive and handle the results.
|
* receive and handle the results.
|
||||||
*/
|
*/
|
||||||
public IdentityBuilder(BaseGitActivity callingActivity) {
|
public IdentityBuilder(BaseGitActivity callingActivity) {
|
||||||
this.callingActivity = callingActivity;
|
this.callingActivity = callingActivity;
|
||||||
|
|
||||||
List<String> providers =
|
List<String> providers =
|
||||||
SshAuthenticationApiUtils.getAuthenticationProviderPackageNames(
|
SshAuthenticationApiUtils.getAuthenticationProviderPackageNames(
|
||||||
callingActivity);
|
callingActivity);
|
||||||
if (providers.isEmpty())
|
if (providers.isEmpty())
|
||||||
throw new RuntimeException(callingActivity.getString(R.string.no_ssh_api_provider));
|
throw new RuntimeException(callingActivity.getString(R.string.no_ssh_api_provider));
|
||||||
|
|
||||||
|
@ -130,12 +134,14 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
connection = new SshAuthenticationConnection(callingActivity, providers.get(0));
|
connection = new SshAuthenticationConnection(callingActivity, providers.get(0));
|
||||||
|
|
||||||
settings =
|
settings =
|
||||||
PreferenceManager.getDefaultSharedPreferences(
|
PreferenceManager.getDefaultSharedPreferences(
|
||||||
callingActivity.getApplicationContext());
|
callingActivity.getApplicationContext());
|
||||||
keyId = settings.getString("ssh_openkeystore_keyid", null);
|
keyId = settings.getString("ssh_openkeystore_keyid", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Free any resources associated with this IdentityBuilder */
|
/**
|
||||||
|
* Free any resources associated with this IdentityBuilder
|
||||||
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
if (connection != null && connection.isConnected()) connection.disconnect();
|
if (connection != null && connection.isConnected()) connection.disconnect();
|
||||||
}
|
}
|
||||||
|
@ -143,10 +149,10 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
/**
|
/**
|
||||||
* Helper to invoke an OpenKeyshain SSH API method and correctly interpret the result.
|
* Helper to invoke an OpenKeyshain SSH API method and correctly interpret the result.
|
||||||
*
|
*
|
||||||
* @param request The request intent to launch
|
* @param request The request intent to launch
|
||||||
* @param requestCode The request code to use if a pending intent needs to be sent
|
* @param requestCode The request code to use if a pending intent needs to be sent
|
||||||
* @return The resulting intent if the request completed immediately, or null if we had to
|
* @return The resulting intent if the request completed immediately, or null if we had to
|
||||||
* launch a pending intent to interact with the user
|
* launch a pending intent to interact with the user
|
||||||
*/
|
*/
|
||||||
private Intent executeApi(Request request, int requestCode) {
|
private Intent executeApi(Request request, int requestCode) {
|
||||||
Intent result = api.executeApi(request.toIntent());
|
Intent result = api.executeApi(request.toIntent());
|
||||||
|
@ -154,13 +160,13 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
switch (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, -1)) {
|
switch (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, -1)) {
|
||||||
case SshAuthenticationApi.RESULT_CODE_ERROR:
|
case SshAuthenticationApi.RESULT_CODE_ERROR:
|
||||||
SshAuthenticationApiError error =
|
SshAuthenticationApiError error =
|
||||||
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
|
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
|
||||||
// On an OpenKeychain SSH API error, clear out the stored keyid
|
// On an OpenKeychain SSH API error, clear out the stored keyid
|
||||||
settings.edit().putString("ssh_openkeystore_keyid", null).apply();
|
settings.edit().putString("ssh_openkeystore_keyid", null).apply();
|
||||||
|
|
||||||
switch (error.getError()) {
|
switch (error.getError()) {
|
||||||
// If the problem was just a bad keyid, reset to allow them to choose a
|
// If the problem was just a bad keyid, reset to allow them to choose a
|
||||||
// different one
|
// different one
|
||||||
case (SshAuthenticationApiError.NO_SUCH_KEY):
|
case (SshAuthenticationApiError.NO_SUCH_KEY):
|
||||||
case (SshAuthenticationApiError.NO_AUTH_KEY):
|
case (SshAuthenticationApiError.NO_AUTH_KEY):
|
||||||
keyId = null;
|
keyId = null;
|
||||||
|
@ -169,7 +175,7 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
alg = null;
|
alg = null;
|
||||||
return executeApi(new KeySelectionRequest(), requestCode);
|
return executeApi(new KeySelectionRequest(), requestCode);
|
||||||
|
|
||||||
// Other errors are fatal
|
// Other errors are fatal
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException(error.getMessage());
|
throw new RuntimeException(error.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -177,19 +183,19 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
break;
|
break;
|
||||||
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
PendingIntent pendingIntent =
|
PendingIntent pendingIntent =
|
||||||
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
|
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
|
||||||
try {
|
try {
|
||||||
callingActivity.startIntentSenderForResult(
|
callingActivity.startIntentSenderForResult(
|
||||||
pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0);
|
pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0);
|
||||||
return null;
|
return null;
|
||||||
} catch (IntentSender.SendIntentException e) {
|
} catch (IntentSender.SendIntentException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
|
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
callingActivity.getString(R.string.ssh_api_unknown_error));
|
callingActivity.getString(R.string.ssh_api_unknown_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -223,32 +229,32 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
*
|
*
|
||||||
* @param requestCode The request code to use if a pending intent needs to be sent
|
* @param requestCode The request code to use if a pending intent needs to be sent
|
||||||
* @return The built identity, or null of user interaction is still required (in which case
|
* @return The built identity, or null of user interaction is still required (in which case
|
||||||
* a pending intent will have already been launched)
|
* a pending intent will have already been launched)
|
||||||
*/
|
*/
|
||||||
public ApiIdentity tryBuild(int requestCode) {
|
public ApiIdentity tryBuild(int requestCode) {
|
||||||
// First gate, need to initiate a connection to the service and wait for it to connect.
|
// First gate, need to initiate a connection to the service and wait for it to connect.
|
||||||
if (api == null) {
|
if (api == null) {
|
||||||
connection.connect(
|
connection.connect(
|
||||||
new SshAuthenticationConnection.OnBound() {
|
new SshAuthenticationConnection.OnBound() {
|
||||||
@Override
|
@Override
|
||||||
public void onBound(ISshAuthenticationService sshAgent) {
|
public void onBound(ISshAuthenticationService sshAgent) {
|
||||||
api = new SshAuthenticationApi(callingActivity, sshAgent);
|
api = new SshAuthenticationApi(callingActivity, sshAgent);
|
||||||
// We can immediately try the next phase without needing to post
|
// We can immediately try the next phase without needing to post
|
||||||
// back
|
// back
|
||||||
// though onActivityResult
|
// though onActivityResult
|
||||||
callingActivity.onActivityResult(
|
callingActivity.onActivityResult(
|
||||||
requestCode, Activity.RESULT_OK, null);
|
requestCode, Activity.RESULT_OK, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError() {
|
public void onError() {
|
||||||
new MaterialAlertDialogBuilder(callingActivity)
|
new MaterialAlertDialogBuilder(callingActivity)
|
||||||
.setMessage(
|
.setMessage(
|
||||||
callingActivity.getString(
|
callingActivity.getString(
|
||||||
R.string.openkeychain_ssh_api_connect_fail))
|
R.string.openkeychain_ssh_api_connect_fail))
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +279,9 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A Jsch identity that delegates key operations via the OpenKeychain SSH API */
|
/**
|
||||||
|
* A Jsch identity that delegates key operations via the OpenKeychain SSH API
|
||||||
|
*/
|
||||||
public static class ApiIdentity implements Identity {
|
public static class ApiIdentity implements Identity {
|
||||||
private String keyId, description, alg;
|
private String keyId, description, alg;
|
||||||
private byte[] publicKey;
|
private byte[] publicKey;
|
||||||
|
@ -283,12 +291,12 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
private byte[] signature;
|
private byte[] signature;
|
||||||
|
|
||||||
ApiIdentity(
|
ApiIdentity(
|
||||||
String keyId,
|
String keyId,
|
||||||
String description,
|
String description,
|
||||||
byte[] publicKey,
|
byte[] publicKey,
|
||||||
String alg,
|
String alg,
|
||||||
Activity callingActivity,
|
Activity callingActivity,
|
||||||
SshAuthenticationApi api) {
|
SshAuthenticationApi api) {
|
||||||
this.keyId = keyId;
|
this.keyId = keyId;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
|
@ -313,35 +321,35 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
*
|
*
|
||||||
* @param result The result intent to handle
|
* @param result The result intent to handle
|
||||||
* @return The signed challenge, or null if it was not immediately available, in which case
|
* @return The signed challenge, or null if it was not immediately available, in which case
|
||||||
* the latch has been initialized and the pending intent started
|
* the latch has been initialized and the pending intent started
|
||||||
*/
|
*/
|
||||||
private byte[] handleSignResult(Intent result) {
|
private byte[] handleSignResult(Intent result) {
|
||||||
switch (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, -1)) {
|
switch (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, -1)) {
|
||||||
case SshAuthenticationApi.RESULT_CODE_ERROR:
|
case SshAuthenticationApi.RESULT_CODE_ERROR:
|
||||||
SshAuthenticationApiError error =
|
SshAuthenticationApiError error =
|
||||||
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
|
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
|
||||||
throw new RuntimeException(error.getMessage());
|
throw new RuntimeException(error.getMessage());
|
||||||
case SshAuthenticationApi.RESULT_CODE_SUCCESS:
|
case SshAuthenticationApi.RESULT_CODE_SUCCESS:
|
||||||
return result.getByteArrayExtra(SshAuthenticationApi.EXTRA_SIGNATURE);
|
return result.getByteArrayExtra(SshAuthenticationApi.EXTRA_SIGNATURE);
|
||||||
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
PendingIntent pendingIntent =
|
PendingIntent pendingIntent =
|
||||||
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
|
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
|
||||||
try {
|
try {
|
||||||
latch = new CountDownLatch(1);
|
latch = new CountDownLatch(1);
|
||||||
callingActivity.startIntentSenderForResult(
|
callingActivity.startIntentSenderForResult(
|
||||||
pendingIntent.getIntentSender(), POST_SIGNATURE, null, 0, 0, 0);
|
pendingIntent.getIntentSender(), POST_SIGNATURE, null, 0, 0, 0);
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
|
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (result.hasExtra(SshAuthenticationApi.EXTRA_CHALLENGE))
|
if (result.hasExtra(SshAuthenticationApi.EXTRA_CHALLENGE))
|
||||||
return handleSignResult(api.executeApi(result));
|
return handleSignResult(api.executeApi(result));
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
callingActivity.getString(R.string.ssh_api_unknown_error));
|
callingActivity.getString(R.string.ssh_api_unknown_error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,6 +407,7 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {}
|
public void clear() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,46 +11,46 @@ internal object Phonemes {
|
||||||
private const val NOT_FIRST = 0x0008
|
private const val NOT_FIRST = 0x0008
|
||||||
|
|
||||||
private val elements = arrayOf(
|
private val elements = arrayOf(
|
||||||
Element("a", VOWEL),
|
Element("a", VOWEL),
|
||||||
Element("ae", VOWEL or DIPTHONG),
|
Element("ae", VOWEL or DIPTHONG),
|
||||||
Element("ah", VOWEL or DIPTHONG),
|
Element("ah", VOWEL or DIPTHONG),
|
||||||
Element("ai", VOWEL or DIPTHONG),
|
Element("ai", VOWEL or DIPTHONG),
|
||||||
Element("b", CONSONANT),
|
Element("b", CONSONANT),
|
||||||
Element("c", CONSONANT),
|
Element("c", CONSONANT),
|
||||||
Element("ch", CONSONANT or DIPTHONG),
|
Element("ch", CONSONANT or DIPTHONG),
|
||||||
Element("d", CONSONANT),
|
Element("d", CONSONANT),
|
||||||
Element("e", VOWEL),
|
Element("e", VOWEL),
|
||||||
Element("ee", VOWEL or DIPTHONG),
|
Element("ee", VOWEL or DIPTHONG),
|
||||||
Element("ei", VOWEL or DIPTHONG),
|
Element("ei", VOWEL or DIPTHONG),
|
||||||
Element("f", CONSONANT),
|
Element("f", CONSONANT),
|
||||||
Element("g", CONSONANT),
|
Element("g", CONSONANT),
|
||||||
Element("gh", CONSONANT or DIPTHONG or NOT_FIRST),
|
Element("gh", CONSONANT or DIPTHONG or NOT_FIRST),
|
||||||
Element("h", CONSONANT),
|
Element("h", CONSONANT),
|
||||||
Element("i", VOWEL),
|
Element("i", VOWEL),
|
||||||
Element("ie", VOWEL or DIPTHONG),
|
Element("ie", VOWEL or DIPTHONG),
|
||||||
Element("j", CONSONANT),
|
Element("j", CONSONANT),
|
||||||
Element("k", CONSONANT),
|
Element("k", CONSONANT),
|
||||||
Element("l", CONSONANT),
|
Element("l", CONSONANT),
|
||||||
Element("m", CONSONANT),
|
Element("m", CONSONANT),
|
||||||
Element("n", CONSONANT),
|
Element("n", CONSONANT),
|
||||||
Element("ng", CONSONANT or DIPTHONG or NOT_FIRST),
|
Element("ng", CONSONANT or DIPTHONG or NOT_FIRST),
|
||||||
Element("o", VOWEL),
|
Element("o", VOWEL),
|
||||||
Element("oh", VOWEL or DIPTHONG),
|
Element("oh", VOWEL or DIPTHONG),
|
||||||
Element("oo", VOWEL or DIPTHONG),
|
Element("oo", VOWEL or DIPTHONG),
|
||||||
Element("p", CONSONANT),
|
Element("p", CONSONANT),
|
||||||
Element("ph", CONSONANT or DIPTHONG),
|
Element("ph", CONSONANT or DIPTHONG),
|
||||||
Element("qu", CONSONANT or DIPTHONG),
|
Element("qu", CONSONANT or DIPTHONG),
|
||||||
Element("r", CONSONANT),
|
Element("r", CONSONANT),
|
||||||
Element("s", CONSONANT),
|
Element("s", CONSONANT),
|
||||||
Element("sh", CONSONANT or DIPTHONG),
|
Element("sh", CONSONANT or DIPTHONG),
|
||||||
Element("t", CONSONANT),
|
Element("t", CONSONANT),
|
||||||
Element("th", CONSONANT or DIPTHONG),
|
Element("th", CONSONANT or DIPTHONG),
|
||||||
Element("u", VOWEL),
|
Element("u", VOWEL),
|
||||||
Element("v", CONSONANT),
|
Element("v", CONSONANT),
|
||||||
Element("w", CONSONANT),
|
Element("w", CONSONANT),
|
||||||
Element("x", CONSONANT),
|
Element("x", CONSONANT),
|
||||||
Element("y", CONSONANT),
|
Element("y", CONSONANT),
|
||||||
Element("z", CONSONANT)
|
Element("z", CONSONANT)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val NUM_ELEMENTS = elements.size
|
private val NUM_ELEMENTS = elements.size
|
||||||
|
@ -110,7 +110,7 @@ internal object Phonemes {
|
||||||
}
|
}
|
||||||
// Don't allow VOWEL followed a Vowel/Dipthong pair
|
// Don't allow VOWEL followed a Vowel/Dipthong pair
|
||||||
if (prev and VOWEL > 0 && flags and VOWEL > 0 &&
|
if (prev and VOWEL > 0 && flags and VOWEL > 0 &&
|
||||||
flags and DIPTHONG > 0
|
flags and DIPTHONG > 0
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ internal object Phonemes {
|
||||||
// Handle UPPERS
|
// Handle UPPERS
|
||||||
if (pwFlags and PasswordGenerator.UPPERS > 0) {
|
if (pwFlags and PasswordGenerator.UPPERS > 0) {
|
||||||
if ((pwFlags and PasswordGenerator.LOWERS == 0) ||
|
if ((pwFlags and PasswordGenerator.LOWERS == 0) ||
|
||||||
(first || flags and CONSONANT > 0) && RandomNumberGenerator.number(10) < 2) {
|
(first || flags and CONSONANT > 0) && RandomNumberGenerator.number(10) < 2) {
|
||||||
val index = password.length - length
|
val index = password.length - length
|
||||||
password = password.substring(0, index) + str.toUpperCase()
|
password = password.substring(0, index) + str.toUpperCase()
|
||||||
featureFlags = featureFlags and PasswordGenerator.UPPERS.inv()
|
featureFlags = featureFlags and PasswordGenerator.UPPERS.inv()
|
||||||
|
@ -169,7 +169,7 @@ internal object Phonemes {
|
||||||
cha = Character.forDigit(RandomNumberGenerator.number(10), 10)
|
cha = Character.forDigit(RandomNumberGenerator.number(10), 10)
|
||||||
character = cha.toString()
|
character = cha.toString()
|
||||||
} while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
|
} while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
|
||||||
PasswordGenerator.AMBIGUOUS_STR.contains(character))
|
PasswordGenerator.AMBIGUOUS_STR.contains(character))
|
||||||
password += character
|
password += character
|
||||||
curSize++
|
curSize++
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ internal object Phonemes {
|
||||||
cha = PasswordGenerator.SYMBOLS_STR.toCharArray()[num]
|
cha = PasswordGenerator.SYMBOLS_STR.toCharArray()[num]
|
||||||
character = cha.toString()
|
character = cha.toString()
|
||||||
} while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
|
} while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
|
||||||
PasswordGenerator.AMBIGUOUS_STR.contains(character))
|
PasswordGenerator.AMBIGUOUS_STR.contains(character))
|
||||||
password += character
|
password += character
|
||||||
curSize++
|
curSize++
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ internal object Phonemes {
|
||||||
VOWEL
|
VOWEL
|
||||||
} else {
|
} else {
|
||||||
if (prev and VOWEL > 0 || flags and DIPTHONG > 0 ||
|
if (prev and VOWEL > 0 || flags and DIPTHONG > 0 ||
|
||||||
RandomNumberGenerator.number(10) > 3
|
RandomNumberGenerator.number(10) > 3
|
||||||
) {
|
) {
|
||||||
CONSONANT
|
CONSONANT
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -53,7 +53,7 @@ internal object RandomPasswordGenerator {
|
||||||
cha = bank.toCharArray()[num]
|
cha = bank.toCharArray()[num]
|
||||||
character = cha.toString()
|
character = cha.toString()
|
||||||
if (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
|
if (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
|
||||||
PasswordGenerator.AMBIGUOUS_STR.contains(character)) {
|
PasswordGenerator.AMBIGUOUS_STR.contains(character)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (pwFlags and PasswordGenerator.NO_VOWELS > 0 && PasswordGenerator.VOWELS_STR.contains(character)) {
|
if (pwFlags and PasswordGenerator.NO_VOWELS > 0 && PasswordGenerator.VOWELS_STR.contains(character)) {
|
||||||
|
|
|
@ -127,7 +127,8 @@ class PasswordBuilder(ctx: Context) {
|
||||||
CapsType.TitleCase -> {
|
CapsType.TitleCase -> {
|
||||||
s = capitalize(s)
|
s = capitalize(s)
|
||||||
}
|
}
|
||||||
CapsType.lowercase, CapsType.As_iS -> {}
|
CapsType.lowercase, CapsType.As_iS -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
password.append(s)
|
password.append(s)
|
||||||
|
|
|
@ -16,9 +16,9 @@ import androidx.core.content.getSystemService
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import org.apache.commons.io.FileUtils
|
|
||||||
|
|
||||||
class ShowSshKeyFragment : DialogFragment() {
|
class ShowSshKeyFragment : DialogFragment() {
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ class ShowSshKeyFragment : DialogFragment() {
|
||||||
ad.setOnShowListener {
|
ad.setOnShowListener {
|
||||||
val b = ad.getButton(AlertDialog.BUTTON_NEUTRAL)
|
val b = ad.getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||||
b.setOnClickListener {
|
b.setOnClickListener {
|
||||||
val clipboard = activity.getSystemService<ClipboardManager>() ?: return@setOnClickListener
|
val clipboard = activity.getSystemService<ClipboardManager>()
|
||||||
|
?: return@setOnClickListener
|
||||||
val clip = ClipData.newPlainText("public key", publicKey.text.toString())
|
val clip = ClipData.newPlainText("public key", publicKey.text.toString())
|
||||||
clipboard.setPrimaryClip(clip)
|
clipboard.setPrimaryClip(clip)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,9 @@ class SshKeyGenActivity : AppCompatActivity() {
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.replace(android.R.id.content, SshKeyGenFragment())
|
.replace(android.R.id.content, SshKeyGenFragment())
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,11 @@ import com.jcraft.jsch.JSch
|
||||||
import com.jcraft.jsch.KeyPair
|
import com.jcraft.jsch.KeyPair
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import com.zeapo.pwdstore.databinding.FragmentSshKeygenBinding
|
import com.zeapo.pwdstore.databinding.FragmentSshKeygenBinding
|
||||||
import java.io.File
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
class SshKeyGenFragment : Fragment() {
|
class SshKeyGenFragment : Fragment() {
|
||||||
|
|
||||||
|
@ -96,12 +96,12 @@ class SshKeyGenFragment : Fragment() {
|
||||||
prefs.edit { putBoolean("use_generated_key", true) }
|
prefs.edit { putBoolean("use_generated_key", true) }
|
||||||
} else {
|
} else {
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(activity.getString(R.string.error_generate_ssh_key))
|
.setTitle(activity.getString(R.string.error_generate_ssh_key))
|
||||||
.setMessage(activity.getString(R.string.ssh_key_error_dialog_text) + e.message)
|
.setMessage(activity.getString(R.string.ssh_key_error_dialog_text) + e.message)
|
||||||
.setPositiveButton(activity.getString(R.string.dialog_ok)) { _, _ ->
|
.setPositiveButton(activity.getString(R.string.dialog_ok)) { _, _ ->
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ open class PasswordItemRecyclerAdapter :
|
||||||
|
|
||||||
class PasswordItemDetailsLookup(private val recyclerView: RecyclerView) :
|
class PasswordItemDetailsLookup(private val recyclerView: RecyclerView) :
|
||||||
ItemDetailsLookup<String>() {
|
ItemDetailsLookup<String>() {
|
||||||
|
|
||||||
override fun getItemDetails(event: MotionEvent): ItemDetails<String>? {
|
override fun getItemDetails(event: MotionEvent): ItemDetails<String>? {
|
||||||
val view = recyclerView.findChildViewUnder(event.x, event.y) ?: return null
|
val view = recyclerView.findChildViewUnder(event.x, event.y) ?: return null
|
||||||
return (recyclerView.getChildViewHolder(view) as PasswordItemViewHolder).itemDetails
|
return (recyclerView.getChildViewHolder(view) as PasswordItemViewHolder).itemDetails
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.zeapo.pwdstore.pwgen.PasswordGenerator.setPrefs
|
||||||
|
|
||||||
/** A placeholder fragment containing a simple view. */
|
/** A placeholder fragment containing a simple view. */
|
||||||
class PasswordGeneratorDialogFragment : DialogFragment() {
|
class PasswordGeneratorDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||||
val callingActivity = requireActivity()
|
val callingActivity = requireActivity()
|
||||||
|
@ -31,7 +32,7 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
|
||||||
val monoTypeface = Typeface.createFromAsset(callingActivity.assets, "fonts/sourcecodepro.ttf")
|
val monoTypeface = Typeface.createFromAsset(callingActivity.assets, "fonts/sourcecodepro.ttf")
|
||||||
builder.setView(view)
|
builder.setView(view)
|
||||||
val prefs = requireActivity().applicationContext
|
val prefs = requireActivity().applicationContext
|
||||||
.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
|
.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
view.findViewById<CheckBox>(R.id.numerals)?.isChecked = !prefs.getBoolean("0", false)
|
view.findViewById<CheckBox>(R.id.numerals)?.isChecked = !prefs.getBoolean("0", false)
|
||||||
view.findViewById<CheckBox>(R.id.symbols)?.isChecked = prefs.getBoolean("y", false)
|
view.findViewById<CheckBox>(R.id.symbols)?.isChecked = prefs.getBoolean("y", false)
|
||||||
|
|
|
@ -117,13 +117,13 @@ class XkPasswordGeneratorDialogFragment : DialogFragment() {
|
||||||
private fun makeAndSetPassword(passwordText: AppCompatTextView) {
|
private fun makeAndSetPassword(passwordText: AppCompatTextView) {
|
||||||
try {
|
try {
|
||||||
passwordText.text = PasswordBuilder(requireContext())
|
passwordText.text = PasswordBuilder(requireContext())
|
||||||
.setNumberOfWords(Integer.valueOf(editNumWords.text.toString()))
|
.setNumberOfWords(Integer.valueOf(editNumWords.text.toString()))
|
||||||
.setMinimumWordLength(DEFAULT_MIN_WORD_LENGTH)
|
.setMinimumWordLength(DEFAULT_MIN_WORD_LENGTH)
|
||||||
.setMaximumWordLength(DEFAULT_MAX_WORD_LENGTH)
|
.setMaximumWordLength(DEFAULT_MAX_WORD_LENGTH)
|
||||||
.setSeparator(editSeparator.text.toString())
|
.setSeparator(editSeparator.text.toString())
|
||||||
.appendNumbers(if (cbNumbers.isChecked) Integer.parseInt(spinnerNumbersCount.selectedItem as String) else 0)
|
.appendNumbers(if (cbNumbers.isChecked) Integer.parseInt(spinnerNumbersCount.selectedItem as String) else 0)
|
||||||
.appendSymbols(if (cbSymbols.isChecked) Integer.parseInt(spinnerSymbolsCount.selectedItem as String) else 0)
|
.appendSymbols(if (cbSymbols.isChecked) Integer.parseInt(spinnerSymbolsCount.selectedItem as String) else 0)
|
||||||
.setCapitalization(CapsType.valueOf(spinnerCapsType.selectedItem.toString())).create()
|
.setCapitalization(CapsType.valueOf(spinnerCapsType.selectedItem.toString())).create()
|
||||||
} catch (e: PasswordGenerator.PasswordGeneratorExeption) {
|
} catch (e: PasswordGenerator.PasswordGeneratorExeption) {
|
||||||
Toast.makeText(requireActivity(), e.message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireActivity(), e.message, Toast.LENGTH_SHORT).show()
|
||||||
tag("xkpw").e(e, "failure generating xkpasswd")
|
tag("xkpw").e(e, "failure generating xkpasswd")
|
||||||
|
|
|
@ -61,11 +61,11 @@ object BiometricAuthenticator {
|
||||||
}
|
}
|
||||||
val biometricPrompt = BiometricPrompt(activity, { handler.post(it) }, authCallback)
|
val biometricPrompt = BiometricPrompt(activity, { handler.post(it) }, authCallback)
|
||||||
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||||
.setTitle(activity.getString(dialogTitleRes))
|
.setTitle(activity.getString(dialogTitleRes))
|
||||||
.setDeviceCredentialAllowed(true)
|
.setDeviceCredentialAllowed(true)
|
||||||
.build()
|
.build()
|
||||||
if (BiometricManager.from(activity).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS ||
|
if (BiometricManager.from(activity).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS ||
|
||||||
activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true) {
|
activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true) {
|
||||||
biometricPrompt.authenticate(promptInfo)
|
biometricPrompt.authenticate(promptInfo)
|
||||||
} else {
|
} else {
|
||||||
callback(Result.HardwareUnavailableOrDisabled)
|
callback(Result.HardwareUnavailableOrDisabled)
|
||||||
|
|
|
@ -36,11 +36,11 @@ fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
|
||||||
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
|
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
|
||||||
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
|
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
|
||||||
return EncryptedSharedPreferences.create(
|
return EncryptedSharedPreferences.create(
|
||||||
fileName,
|
fileName,
|
||||||
masterKeyAlias,
|
masterKeyAlias,
|
||||||
this,
|
this,
|
||||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ fun <T : View> AlertDialog.requestInputFocusOnView(@IdRes id: Int) {
|
||||||
setOnFocusChangeListener { v, _ ->
|
setOnFocusChangeListener { v, _ ->
|
||||||
v.post {
|
v.post {
|
||||||
context.getSystemService<InputMethodManager>()
|
context.getSystemService<InputMethodManager>()
|
||||||
?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
|
?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestFocus()
|
requestFocus()
|
||||||
|
|
|
@ -4,24 +4,28 @@
|
||||||
*/
|
*/
|
||||||
package com.zeapo.pwdstore.utils;
|
package com.zeapo.pwdstore.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base32;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import org.apache.commons.codec.binary.Base32;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class Otp {
|
public class Otp {
|
||||||
|
|
||||||
private static final Base32 BASE_32 = new Base32();
|
private static final Base32 BASE_32 = new Base32();
|
||||||
|
|
||||||
private Otp() {}
|
private Otp() {
|
||||||
|
}
|
||||||
|
|
||||||
public static String calculateCode(
|
public static String calculateCode(
|
||||||
String secret, long counter, String algorithm, String digits) {
|
String secret, long counter, String algorithm, String digits) {
|
||||||
String[] steam = {
|
String[] steam = {
|
||||||
"2", "3", "4", "5", "6", "7", "8", "9", "B", "C", "D", "F", "G", "H", "J", "K", "M",
|
"2", "3", "4", "5", "6", "7", "8", "9", "B", "C", "D", "F", "G", "H", "J", "K", "M",
|
||||||
"N", "P", "Q", "R", "T", "V", "W", "X", "Y"
|
"N", "P", "Q", "R", "T", "V", "W", "X", "Y"
|
||||||
|
|
|
@ -14,14 +14,15 @@ data class PasswordItem(
|
||||||
val file: File,
|
val file: File,
|
||||||
val rootDir: File
|
val rootDir: File
|
||||||
) : Comparable<PasswordItem> {
|
) : Comparable<PasswordItem> {
|
||||||
|
|
||||||
val fullPathToParent = file.absolutePath
|
val fullPathToParent = file.absolutePath
|
||||||
.replace(rootDir.absolutePath, "")
|
.replace(rootDir.absolutePath, "")
|
||||||
.replace(file.name, "")
|
.replace(file.name, "")
|
||||||
|
|
||||||
val longName = PgpActivity.getLongName(
|
val longName = PgpActivity.getLongName(
|
||||||
fullPathToParent,
|
fullPathToParent,
|
||||||
rootDir.absolutePath,
|
rootDir.absolutePath,
|
||||||
toString())
|
toString())
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return (other is PasswordItem) && (other.file == file)
|
return (other is PasswordItem) && (other.file == file)
|
||||||
|
|
|
@ -8,9 +8,6 @@ import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import java.io.File
|
|
||||||
import java.io.FileFilter
|
|
||||||
import java.util.Comparator
|
|
||||||
import org.apache.commons.io.filefilter.FileFilterUtils
|
import org.apache.commons.io.filefilter.FileFilterUtils
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.lib.Repository
|
import org.eclipse.jgit.lib.Repository
|
||||||
|
@ -18,6 +15,9 @@ import org.eclipse.jgit.storage.file.FileRepositoryBuilder
|
||||||
import org.eclipse.jgit.transport.RefSpec
|
import org.eclipse.jgit.transport.RefSpec
|
||||||
import org.eclipse.jgit.transport.RemoteConfig
|
import org.eclipse.jgit.transport.RemoteConfig
|
||||||
import org.eclipse.jgit.transport.URIish
|
import org.eclipse.jgit.transport.URIish
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileFilter
|
||||||
|
import java.util.Comparator
|
||||||
|
|
||||||
open class PasswordRepository protected constructor() {
|
open class PasswordRepository protected constructor() {
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ open class PasswordRepository protected constructor() {
|
||||||
|
|
||||||
FOLDER_FIRST(Comparator { p1: PasswordItem, p2: PasswordItem ->
|
FOLDER_FIRST(Comparator { p1: PasswordItem, p2: PasswordItem ->
|
||||||
(p1.type + p1.name)
|
(p1.type + p1.name)
|
||||||
.compareTo(p2.type + p2.name, ignoreCase = true)
|
.compareTo(p2.type + p2.name, ignoreCase = true)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
INDEPENDENT(Comparator { p1: PasswordItem, p2: PasswordItem ->
|
INDEPENDENT(Comparator { p1: PasswordItem, p2: PasswordItem ->
|
||||||
|
@ -62,8 +62,8 @@ open class PasswordRepository protected constructor() {
|
||||||
val builder = FileRepositoryBuilder()
|
val builder = FileRepositoryBuilder()
|
||||||
try {
|
try {
|
||||||
repository = builder.setGitDir(localDir)
|
repository = builder.setGitDir(localDir)
|
||||||
.readEnvironment()
|
.readEnvironment()
|
||||||
.build()
|
.build()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return null
|
return null
|
||||||
|
@ -81,8 +81,8 @@ open class PasswordRepository protected constructor() {
|
||||||
if (repository != null) {
|
if (repository != null) {
|
||||||
// Check if remote exists
|
// Check if remote exists
|
||||||
return repository!!.config.getSubsections("remote").isNotEmpty() &&
|
return repository!!.config.getSubsections("remote").isNotEmpty() &&
|
||||||
repository!!.objectDatabase.exists() &&
|
repository!!.objectDatabase.exists() &&
|
||||||
repository!!.allRefs.isNotEmpty()
|
repository!!.allRefs.isNotEmpty()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -196,9 +196,9 @@ open class PasswordRepository protected constructor() {
|
||||||
if (path == null || !path.exists()) return ArrayList()
|
if (path == null || !path.exists()) return ArrayList()
|
||||||
|
|
||||||
val directories = (path.listFiles(FileFilterUtils.directoryFileFilter() as FileFilter)
|
val directories = (path.listFiles(FileFilterUtils.directoryFileFilter() as FileFilter)
|
||||||
?: emptyArray()).toList()
|
?: emptyArray()).toList()
|
||||||
val files = (path.listFiles(FileFilterUtils.suffixFileFilter(".gpg") as FileFilter)
|
val files = (path.listFiles(FileFilterUtils.suffixFileFilter(".gpg") as FileFilter)
|
||||||
?: emptyArray()).toList()
|
?: emptyArray()).toList()
|
||||||
|
|
||||||
val items = ArrayList<File>()
|
val items = ArrayList<File>()
|
||||||
items.addAll(directories)
|
items.addAll(directories)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<scale
|
<scale
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:fromXScale="1.0"
|
android:fromXScale="1.0"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<scale
|
<scale
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:fromXScale="0"
|
android:fromXScale="0"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_checked="false"
|
<item android:color="#00FFFFFF" android:state_checked="false" />
|
||||||
android:color="#00FFFFFF" />
|
|
||||||
<item android:color="@color/button_color" />
|
<item android:color="@color/button_color" />
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0,0 0,4 20H20A2,2 0,0 0,22 18V8C22,6.89 21.1,6 20,6Z"/>
|
android:pathData="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0,0 0,4 20H20A2,2 0,0 0,22 18V8C22,6.89 21.1,6 20,6Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M14,2H6A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2M18,20H6V4H13V9H18M12.83,15A3,3 0,1 0,12.83 17H14V19H16V17H17V15M10,17A1,1 0,1 1,11 16A1,1 0,0 1,10 17Z"/>
|
android:pathData="M14,2H6A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2M18,20H6V4H13V9H18M12.83,15A3,3 0,1 0,12.83 17H14V19H16V17H17V15M10,17A1,1 0,1 1,11 16A1,1 0,0 1,10 17Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorOnPrimary"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24">
|
||||||
android:tint="?attr/colorOnPrimary">
|
<path
|
||||||
<path
|
android:fillColor="#FFFFFFFF"
|
||||||
android:fillColor="#FFFFFFFF"
|
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z" />
|
||||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M14,2H6A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2M18,20H6V4H13V9H18M12.83,15A3,3 0,1 0,12.83 17H14V19H16V17H17V15M10,17A1,1 0,1 1,11 16A1,1 0,0 1,10 17Z"/>
|
android:pathData="M14,2H6A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2M18,20H6V4H13V9H18M12.83,15A3,3 0,1 0,12.83 17H14V19H16V17H17V15M10,17A1,1 0,1 1,11 16A1,1 0,0 1,10 17Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15.59,7L12,10.59 8.41,7 7,8.41 10.59,12 7,15.59 8.41,17 12,13.41 15.59,17 17,15.59 13.41,12 17,8.41z"/>
|
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15.59,7L12,10.59 8.41,7 7,8.41 10.59,12 7,15.59 8.41,17 12,13.41 15.59,17 17,15.59 13.41,12 17,8.41z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z"/>
|
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z"/>
|
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M16,9v10H8V9h8m-1.5,-6h-5l-1,1H5v2h14V4h-3.5l-1,-1zM18,7H6v12c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7z"/>
|
android:pathData="M16,9v10H8V9h8m-1.5,-6h-5l-1,1H5v2h14V4h-3.5l-1,-1zM18,7H6v12c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
|
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M14.06,9.02l0.92,0.92L5.92,19L5,19v-0.92l9.06,-9.06M17.66,3c-0.25,0 -0.51,0.1 -0.7,0.29l-1.83,1.83 3.75,3.75 1.83,-1.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.2,-0.2 -0.45,-0.29 -0.71,-0.29zM14.06,6.19L3,17.25L3,21h3.75L17.81,9.94l-3.75,-3.75z"/>
|
android:pathData="M14.06,9.02l0.92,0.92L5.92,19L5,19v-0.92l9.06,-9.06M17.66,3c-0.25,0 -0.51,0.1 -0.7,0.29l-1.83,1.83 3.75,3.75 1.83,-1.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.2,-0.2 -0.45,-0.29 -0.71,-0.29zM14.06,6.19L3,17.25L3,21h3.75L17.81,9.94l-3.75,-3.75z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorOnPrimary"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24">
|
||||||
android:tint="?attr/colorOnPrimary">
|
<path
|
||||||
<path
|
android:fillColor="#FFFFFFFF"
|
||||||
android:fillColor="#FFFFFFFF"
|
android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z" />
|
||||||
android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,23 +3,24 @@
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="110.34687"
|
android:viewportWidth="110.34687"
|
||||||
android:viewportHeight="110.34687">
|
android:viewportHeight="110.34687">
|
||||||
<group android:translateX="24.828047"
|
<group
|
||||||
android:translateY="24.828047">
|
android:translateX="24.828047"
|
||||||
<path
|
android:translateY="24.828047">
|
||||||
android:pathData="m18.8,30.2129v-11.546c0,-6.4144 5.1315,-11.546 11.546,-11.546 6.4144,0 11.546,5.1315 11.546,11.546v11.546"
|
<path
|
||||||
android:strokeWidth="5.349"
|
android:fillColor="#00000000"
|
||||||
android:fillColor="#00000000"
|
android:pathData="m18.8,30.2129v-11.546c0,-6.4144 5.1315,-11.546 11.546,-11.546 6.4144,0 11.546,5.1315 11.546,11.546v11.546"
|
||||||
android:strokeColor="#013e5b"/>
|
android:strokeWidth="5.349"
|
||||||
<path
|
android:strokeColor="#013e5b" />
|
||||||
android:pathData="M15.4099,21.8429L45.2811,21.8429A2.2639,2.2639 0,0 1,47.545 24.1068L47.545,53.977A2.2639,2.2639 0,0 1,45.2811 56.2409L15.4099,56.2409A2.2639,2.2639 0,0 1,13.146 53.977L13.146,24.1068A2.2639,2.2639 0,0 1,15.4099 21.8429z"
|
<path
|
||||||
android:fillColor="#00c7a0"/>
|
android:fillColor="#00c7a0"
|
||||||
<path
|
android:pathData="M15.4099,21.8429L45.2811,21.8429A2.2639,2.2639 0,0 1,47.545 24.1068L47.545,53.977A2.2639,2.2639 0,0 1,45.2811 56.2409L15.4099,56.2409A2.2639,2.2639 0,0 1,13.146 53.977L13.146,24.1068A2.2639,2.2639 0,0 1,15.4099 21.8429z" />
|
||||||
android:pathData="m44.8267,37.6961 l-13.1408,-13.1393c-0.7569,-0.7566 -1.9838,-0.7566 -2.7408,0l-13.08,13.0785c-0.7567,0.7573 -0.7567,1.9846 0,2.7419l13.1415,13.14c0.7572,0.7567 1.9842,0.7567 2.7414,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421"
|
<path
|
||||||
android:strokeWidth=".35344"
|
android:fillColor="#fff"
|
||||||
android:fillColor="#fff"/>
|
android:pathData="m44.8267,37.6961 l-13.1408,-13.1393c-0.7569,-0.7566 -1.9838,-0.7566 -2.7408,0l-13.08,13.0785c-0.7567,0.7573 -0.7567,1.9846 0,2.7419l13.1415,13.14c0.7572,0.7567 1.9842,0.7567 2.7414,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421"
|
||||||
<path
|
android:strokeWidth=".35344" />
|
||||||
android:pathData="m30.3156,23.9881c-0.496,0 -0.992,0.1893 -1.3705,0.5676l-2.7282,2.7288 3.4612,3.4606c0.8044,-0.2715 1.727,-0.0892 2.368,0.5517 0.6237,0.624 0.8361,1.5493 0.5471,2.3828l3.3357,3.3357c0.8076,-0.2777 1.738,-0.098 2.3828,0.5476 0.9008,0.9005 0.9008,2.361 0,3.2615 -1.7823,1.7848 -4.7253,-0.1767 -3.7641,-2.5087l-3.1111,-3.1106c-2.2315,0.5285 -3.8934,-1.2655 -3.149,-3.1674l-0.6863,-0.6863l0,15.9165l5.4913,0l0,-5.8608c-0.0315,-0.7566 1.1201,-0.7566 1.0886,0l0,6.4043c0.0005,0.3013 -0.2438,0.5457 -0.545,0.5455l-6.5804,0c-0.3015,0.0005 -0.546,-0.2441 -0.5456,-0.5455l0,-17.4333c-0.0005,-0.0363 0.0029,-0.0728 0.0097,-0.1085l-1.6444,-1.6444 -9.0106,9.0084c-0.7567,0.7573 -0.7567,1.9848 0,2.7421l13.1415,13.14c0.7572,0.7567 1.9844,0.7567 2.7416,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421l-13.14,-13.1393c-0.3785,-0.3783 -0.8746,-0.5676 -1.3705,-0.5676zM29.9512,39.1825c0.1001,0 0.1808,0.0381 0.2426,0.1146 0.0648,0.0736 0.1326,0.1975 0.2032,0.371 0.0705,0.1706 0.1089,0.2615 0.1146,0.2733 0.0059,-0.0119 0.0424,-0.1026 0.11,-0.2733 0.0707,-0.1705 0.1401,-0.2946 0.2078,-0.371 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2103 0.1592,0.3485 0,0.0676 -0.0179,0.1368 -0.0532,0.2073 -0.0323,0.0707 -0.0777,0.1444 -0.1366,0.2211 -0.056,0.0734 -0.1164,0.1571 -0.1812,0.2513 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0354 0.3004,-0.0354 0.0969,0 0.1762,0.0224 0.238,0.0666 0.0648,0.0442 0.1118,0.1042 0.1413,0.1807 0.0294,0.0734 0.044,0.1544 0.044,0.2426 0,0.1384 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1372 -0.3219,0.1372 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.0386 -0.3045,-0.0446 0.1531,0.2177 0.2534,0.3652 0.3004,0.4417 0.047,0.0736 0.0706,0.1544 0.0706,0.2426 0,0.1412 -0.0533,0.2556 -0.1592,0.3439 -0.1028,0.0853 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0366 -0.2559,-0.11 -0.0646,-0.0767 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0235 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1646 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.11 -0.2513,0.11 -0.15,0 -0.2779,-0.0427 -0.3838,-0.1279 -0.1059,-0.0883 -0.1587,-0.2027 -0.1587,-0.3439 0,-0.0618 0.0156,-0.1263 0.0481,-0.194 0.0323,-0.0707 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1532 0.2206,-0.3091 -0.0736,0.0059 -0.1751,0.021 -0.3045,0.0446 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.046 -0.3311,-0.1372 -0.0707,-0.0941 -0.1059,-0.2101 -0.1059,-0.3485 0,-0.1411 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0107 0.2687,0.0312 0.1059,0.0206 0.2062,0.038 0.3004,0.0527 -0.0824,-0.1177 -0.1648,-0.2366 -0.2472,-0.3572 -0.0824,-0.1206 -0.1233,-0.2282 -0.1233,-0.3224 0,-0.1382 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412zM29.9512,43.2235c0.1001,0 0.1808,0.0383 0.2426,0.1146 0.0648,0.0735 0.1326,0.197 0.2032,0.3705 0.0705,0.1707 0.1089,0.262 0.1146,0.2738 0.0059,-0.0119 0.0424,-0.1031 0.11,-0.2738 0.0707,-0.1705 0.1401,-0.2941 0.2078,-0.3705 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2102 0.1592,0.3485 0,0.0675 -0.0179,0.1366 -0.0532,0.2073 -0.0323,0.0705 -0.0777,0.1441 -0.1366,0.2206 -0.056,0.0735 -0.1164,0.1576 -0.1812,0.2518 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0353 0.3004,-0.0353 0.0969,0 0.1762,0.0219 0.238,0.0661 0.0648,0.0442 0.1118,0.1047 0.1413,0.1812 0.0294,0.0736 0.044,0.1542 0.044,0.2426 0,0.1382 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1366 -0.3219,0.1366 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.038 -0.3045,-0.044 0.1531,0.2177 0.2534,0.3647 0.3004,0.4411 0.047,0.0736 0.0706,0.1549 0.0706,0.2431 0,0.1411 -0.0533,0.2558 -0.1592,0.3439 -0.1028,0.0854 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0371 -0.2559,-0.1105 -0.0646,-0.0765 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0236 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1648 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.1105 -0.2513,0.1105 -0.15,0 -0.2779,-0.0425 -0.3838,-0.1279 -0.1059,-0.0881 -0.1587,-0.2028 -0.1587,-0.3439 0,-0.0617 0.0156,-0.1268 0.0481,-0.1945 0.0323,-0.0705 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1527 0.2206,-0.3086 -0.0736,0.0059 -0.1751,0.0205 -0.3045,0.044 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.0454 -0.3311,-0.1366 -0.0707,-0.0941 -0.1059,-0.2103 -0.1059,-0.3485 0,-0.1412 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0101 0.2687,0.0307 0.1059,0.0204 0.2062,0.0384 0.3004,0.0532 -0.0824,-0.1177 -0.1648,-0.2371 -0.2472,-0.3577 -0.0824,-0.1206 -0.1233,-0.2278 -0.1233,-0.3219 0,-0.1384 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412z"
|
<path
|
||||||
android:strokeWidth="1.3358"
|
android:fillColor="#3bdbbc"
|
||||||
android:fillColor="#3bdbbc"/>
|
android:pathData="m30.3156,23.9881c-0.496,0 -0.992,0.1893 -1.3705,0.5676l-2.7282,2.7288 3.4612,3.4606c0.8044,-0.2715 1.727,-0.0892 2.368,0.5517 0.6237,0.624 0.8361,1.5493 0.5471,2.3828l3.3357,3.3357c0.8076,-0.2777 1.738,-0.098 2.3828,0.5476 0.9008,0.9005 0.9008,2.361 0,3.2615 -1.7823,1.7848 -4.7253,-0.1767 -3.7641,-2.5087l-3.1111,-3.1106c-2.2315,0.5285 -3.8934,-1.2655 -3.149,-3.1674l-0.6863,-0.6863l0,15.9165l5.4913,0l0,-5.8608c-0.0315,-0.7566 1.1201,-0.7566 1.0886,0l0,6.4043c0.0005,0.3013 -0.2438,0.5457 -0.545,0.5455l-6.5804,0c-0.3015,0.0005 -0.546,-0.2441 -0.5456,-0.5455l0,-17.4333c-0.0005,-0.0363 0.0029,-0.0728 0.0097,-0.1085l-1.6444,-1.6444 -9.0106,9.0084c-0.7567,0.7573 -0.7567,1.9848 0,2.7421l13.1415,13.14c0.7572,0.7567 1.9844,0.7567 2.7416,0l13.0778,-13.0785c0.7572,-0.7572 0.7572,-1.9849 0,-2.7421l-13.14,-13.1393c-0.3785,-0.3783 -0.8746,-0.5676 -1.3705,-0.5676zM29.9512,39.1825c0.1001,0 0.1808,0.0381 0.2426,0.1146 0.0648,0.0736 0.1326,0.1975 0.2032,0.371 0.0705,0.1706 0.1089,0.2615 0.1146,0.2733 0.0059,-0.0119 0.0424,-0.1026 0.11,-0.2733 0.0707,-0.1705 0.1401,-0.2946 0.2078,-0.371 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2103 0.1592,0.3485 0,0.0676 -0.0179,0.1368 -0.0532,0.2073 -0.0323,0.0707 -0.0777,0.1444 -0.1366,0.2211 -0.056,0.0734 -0.1164,0.1571 -0.1812,0.2513 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0354 0.3004,-0.0354 0.0969,0 0.1762,0.0224 0.238,0.0666 0.0648,0.0442 0.1118,0.1042 0.1413,0.1807 0.0294,0.0734 0.044,0.1544 0.044,0.2426 0,0.1384 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1372 -0.3219,0.1372 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.0386 -0.3045,-0.0446 0.1531,0.2177 0.2534,0.3652 0.3004,0.4417 0.047,0.0736 0.0706,0.1544 0.0706,0.2426 0,0.1412 -0.0533,0.2556 -0.1592,0.3439 -0.1028,0.0853 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0366 -0.2559,-0.11 -0.0646,-0.0767 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0235 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1646 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.11 -0.2513,0.11 -0.15,0 -0.2779,-0.0427 -0.3838,-0.1279 -0.1059,-0.0883 -0.1587,-0.2027 -0.1587,-0.3439 0,-0.0618 0.0156,-0.1263 0.0481,-0.194 0.0323,-0.0707 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1532 0.2206,-0.3091 -0.0736,0.0059 -0.1751,0.021 -0.3045,0.0446 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.046 -0.3311,-0.1372 -0.0707,-0.0941 -0.1059,-0.2101 -0.1059,-0.3485 0,-0.1411 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0107 0.2687,0.0312 0.1059,0.0206 0.2062,0.038 0.3004,0.0527 -0.0824,-0.1177 -0.1648,-0.2366 -0.2472,-0.3572 -0.0824,-0.1206 -0.1233,-0.2282 -0.1233,-0.3224 0,-0.1382 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412zM29.9512,43.2235c0.1001,0 0.1808,0.0383 0.2426,0.1146 0.0648,0.0735 0.1326,0.197 0.2032,0.3705 0.0705,0.1707 0.1089,0.262 0.1146,0.2738 0.0059,-0.0119 0.0424,-0.1031 0.11,-0.2738 0.0707,-0.1705 0.1401,-0.2941 0.2078,-0.3705 0.0677,-0.0765 0.1513,-0.1146 0.2513,-0.1146 0.1412,0 0.2646,0.047 0.3705,0.1412 0.1059,0.0941 0.1592,0.2102 0.1592,0.3485 0,0.0675 -0.0179,0.1366 -0.0532,0.2073 -0.0323,0.0705 -0.0777,0.1441 -0.1366,0.2206 -0.056,0.0735 -0.1164,0.1576 -0.1812,0.2518 0.0648,-0.0089 0.1589,-0.0251 0.2825,-0.0486 0.1265,-0.0236 0.2268,-0.0353 0.3004,-0.0353 0.0969,0 0.1762,0.0219 0.238,0.0661 0.0648,0.0442 0.1118,0.1047 0.1413,0.1812 0.0294,0.0736 0.044,0.1542 0.044,0.2426 0,0.1382 -0.0337,0.2544 -0.1013,0.3485 -0.0677,0.0912 -0.1749,0.1366 -0.3219,0.1366 -0.0472,0 -0.14,-0.0119 -0.2784,-0.0354 -0.1382,-0.0236 -0.2397,-0.038 -0.3045,-0.044 0.1531,0.2177 0.2534,0.3647 0.3004,0.4411 0.047,0.0736 0.0706,0.1549 0.0706,0.2431 0,0.1411 -0.0533,0.2558 -0.1592,0.3439 -0.1028,0.0854 -0.2264,0.1279 -0.3705,0.1279 -0.1028,0 -0.1882,-0.0371 -0.2559,-0.1105 -0.0646,-0.0765 -0.1309,-0.1955 -0.1986,-0.3572 -0.0646,-0.1647 -0.1028,-0.259 -0.1146,-0.2825 -0.0117,0.0236 -0.0516,0.1178 -0.1192,0.2825 -0.0648,0.1648 -0.1281,0.2836 -0.1899,0.3572 -0.0617,0.0735 -0.1454,0.1105 -0.2513,0.1105 -0.15,0 -0.2779,-0.0425 -0.3838,-0.1279 -0.1059,-0.0881 -0.1587,-0.2028 -0.1587,-0.3439 0,-0.0617 0.0156,-0.1268 0.0481,-0.1945 0.0323,-0.0705 0.0665,-0.1311 0.1018,-0.1812 0.0382,-0.0499 0.1118,-0.1527 0.2206,-0.3086 -0.0736,0.0059 -0.1751,0.0205 -0.3045,0.044 -0.1294,0.0236 -0.2176,0.0354 -0.2646,0.0354 -0.1472,0 -0.2577,-0.0454 -0.3311,-0.1366 -0.0707,-0.0941 -0.1059,-0.2103 -0.1059,-0.3485 0,-0.1412 0.0352,-0.2573 0.1059,-0.3485 0.0734,-0.0942 0.184,-0.1412 0.3311,-0.1412 0.0736,0 0.1628,0.0101 0.2687,0.0307 0.1059,0.0204 0.2062,0.0384 0.3004,0.0532 -0.0824,-0.1177 -0.1648,-0.2371 -0.2472,-0.3577 -0.0824,-0.1206 -0.1233,-0.2278 -0.1233,-0.3219 0,-0.1384 0.0543,-0.2544 0.1633,-0.3485 0.1088,-0.0942 0.2351,-0.1412 0.3792,-0.1412z"
|
||||||
|
android:strokeWidth="1.3358" />
|
||||||
</group>
|
</group>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M20,6L12,6L10,4L4,4A2,2 0,0 0,2 6L2,18a2,2 0,0 0,2 2L20,20a2,2 0,0 0,2 -2L22,8A2,2 0,0 0,20 6ZM20,18L4,18L4,8L20,8ZM13,12L7,12v2h6v2l4,-3 -4,-3Z"/>
|
android:pathData="M20,6L12,6L10,4L4,4A2,2 0,0 0,2 6L2,18a2,2 0,0 0,2 2L20,20a2,2 0,0 0,2 -2L22,8A2,2 0,0 0,20 6ZM20,18L4,18L4,8L20,8ZM13,12L7,12v2h6v2l4,-3 -4,-3Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?colorOnPrimary"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24">
|
||||||
android:tint="?colorOnPrimary">
|
<path
|
||||||
<path
|
android:fillColor="#FFFFFFFF"
|
||||||
android:fillColor="#FFFFFFFF"
|
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z" />
|
||||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M19,5L7,5A2,2 0,0 0,5 7L5,21a2,2 0,0 0,2 2L21,23a2,2 0,0 0,2 -2L23,9ZM21,21L7,21L7,7L18.17,7L21,9.83ZM14,14a3,3 0,1 0,3 3A3,3 0,0 0,14 14ZM8,8h9v4L8,12ZM15,1L3,1A2,2 0,0 0,1 3L1,17L3,17L3,3L15,3Z"/>
|
android:pathData="M19,5L7,5A2,2 0,0 0,5 7L5,21a2,2 0,0 0,2 2L21,23a2,2 0,0 0,2 -2L23,9ZM21,21L7,21L7,7L18.17,7L21,9.83ZM14,14a3,3 0,1 0,3 3A3,3 0,0 0,14 14ZM8,8h9v4L8,12ZM15,1L3,1A2,2 0,0 0,1 3L1,17L3,17L3,3L15,3Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM19,19L5,19L5,5h11.17L19,7.83L19,19zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM6,6h9v4L6,10z"/>
|
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM19,19L5,19L5,5h11.17L19,7.83L19,19zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM6,6h9v4L6,10z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92s2.92,-1.31 2.92,-2.92c0,-1.61 -1.31,-2.92 -2.92,-2.92zM18,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM6,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,20.02c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
|
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92s2.92,-1.31 2.92,-2.92c0,-1.61 -1.31,-2.92 -2.92,-2.92zM18,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM6,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,20.02c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFF0000"
|
android:fillColor="#FFFF0000"
|
||||||
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
|
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
<!--
|
|
||||||
Requires a layer-list since attributes cannot be resolved in selectors, see:
|
Requires a layer-list since attributes cannot be resolved in selectors, see:
|
||||||
https://stackoverflow.com/a/36424426/297261
|
https://stackoverflow.com/a/36424426/297261
|
||||||
-->
|
-->
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item>
|
<item>
|
||||||
<selector>
|
<selector>
|
||||||
<item android:drawable="@color/list_multiselect_background" android:state_selected="true" />
|
<item
|
||||||
<item android:drawable="@android:color/transparent"/>
|
android:drawable="@color/list_multiselect_background"
|
||||||
</selector>
|
android:state_selected="true" />
|
||||||
</item>
|
<item android:drawable="@android:color/transparent" />
|
||||||
<item android:drawable="?android:attr/selectableItemBackground"/>
|
</selector>
|
||||||
|
</item>
|
||||||
|
<item android:drawable="?android:attr/selectableItemBackground" />
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|
|
@ -3,44 +3,44 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:attr/windowBackground"
|
||||||
android:padding="@dimen/activity_horizontal_margin"
|
android:padding="@dimen/activity_horizontal_margin"
|
||||||
tools:context="com.zeapo.pwdstore.git.GitOperationActivity"
|
tools:context="com.zeapo.pwdstore.git.GitOperationActivity">
|
||||||
android:background="?android:attr/windowBackground">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline5"
|
|
||||||
android:id="@+id/server_label"
|
android:id="@+id/server_label"
|
||||||
android:textStyle="bold"
|
style="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
android:textSize="24sp"
|
|
||||||
android:text="@string/server_name"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
|
android:text="@string/server_name"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
||||||
android:id="@+id/label_server_protocol"
|
android:id="@+id/label_server_protocol"
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/server_protocol"
|
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/server_label"
|
android:text="@string/server_protocol"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/server_label" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline1"
|
|
||||||
android:id="@+id/clone_protocol_group"
|
android:id="@+id/clone_protocol_group"
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline1"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/label_server_protocol"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/label_server_protocol"
|
||||||
app:selectionRequired="true"
|
app:selectionRequired="true"
|
||||||
app:singleSelection="true">
|
app:singleSelection="true">
|
||||||
|
|
||||||
|
@ -61,11 +61,12 @@
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/server_user_layout"
|
android:id="@+id/server_user_layout"
|
||||||
android:hint="@string/server_user"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
|
android:hint="@string/server_user"
|
||||||
app:layout_constraintTop_toBottomOf="@id/clone_protocol_group">
|
app:layout_constraintTop_toBottomOf="@id/clone_protocol_group">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/server_user"
|
android:id="@+id/server_user"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -79,14 +80,14 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/server_url"
|
android:hint="@string/server_url"
|
||||||
app:layout_constraintTop_toBottomOf="@id/server_user_layout"
|
app:layout_constraintEnd_toStartOf="@id/label_server_port"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/label_server_port">
|
app:layout_constraintTop_toBottomOf="@id/server_user_layout">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/server_url"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/server_url"
|
|
||||||
android:inputType="textWebEmailAddress" />
|
android:inputType="textWebEmailAddress" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
@ -97,10 +98,10 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/server_port_hint"
|
android:hint="@string/server_port_hint"
|
||||||
app:layout_constraintStart_toEndOf="@id/label_server_url"
|
app:layout_constraintDimensionRatio="1:0.8"
|
||||||
app:layout_constraintTop_toBottomOf="@id/server_user_layout"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintDimensionRatio="1:0.8">
|
app:layout_constraintStart_toEndOf="@id/label_server_url"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/server_user_layout">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/server_port"
|
android:id="@+id/server_port"
|
||||||
|
@ -123,19 +124,19 @@
|
||||||
android:id="@+id/server_path"
|
android:id="@+id/server_path"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textWebEmailAddress"/>
|
android:inputType="textWebEmailAddress" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
|
||||||
android:id="@+id/label_connection_mode"
|
android:id="@+id/label_connection_mode"
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/connection_mode"
|
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
|
android:text="@string/connection_mode"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/label_server_path" />
|
app:layout_constraintTop_toBottomOf="@id/label_server_path" />
|
||||||
|
|
||||||
|
@ -144,8 +145,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintTop_toBottomOf="@id/label_connection_mode"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintTop_toBottomOf="@id/label_connection_mode">
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/connection_mode_ssh_key"
|
android:id="@+id/connection_mode_ssh_key"
|
||||||
|
@ -179,11 +180,11 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/save_button"
|
android:id="@+id/save_button"
|
||||||
android:text="@string/crypto_save"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/connection_mode_group"
|
android:text="@string/crypto_save"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/connection_mode_group" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="@dimen/activity_horizontal_margin"
|
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
|
android:padding="@dimen/activity_horizontal_margin"
|
||||||
tools:context="com.zeapo.pwdstore.git.GitConfigActivity"
|
tools:context="com.zeapo.pwdstore.git.GitConfigActivity"
|
||||||
tools:layout_editor_absoluteX="0dp"
|
tools:layout_editor_absoluteX="0dp"
|
||||||
tools:layout_editor_absoluteY="81dp">
|
tools:layout_editor_absoluteY="81dp">
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/git_user_name_hint"
|
android:hint="@string/git_user_name_hint"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:layout_editor_absoluteY="64dp">
|
tools:layout_editor_absoluteY="64dp">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
@ -33,8 +33,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/git_user_email"
|
android:hint="@string/git_user_email"
|
||||||
app:layout_constraintTop_toBottomOf="@id/username_input_layout"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintTop_toBottomOf="@id/username_input_layout">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/git_user_email"
|
android:id="@+id/git_user_email"
|
||||||
|
@ -50,20 +50,20 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:text="@string/crypto_save"
|
android:text="@string/crypto_save"
|
||||||
app:layout_constraintTop_toBottomOf="@id/email_input_layout"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintTop_toBottomOf="@id/email_input_layout" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline5"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:id="@+id/git_tools_title"
|
android:id="@+id/git_tools_title"
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:text="@string/hackish_tools"
|
android:text="@string/hackish_tools"
|
||||||
app:layout_constraintTop_toBottomOf="@id/save_button"
|
android:textSize="24sp"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/save_button" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/commit_hash_label"
|
android:id="@+id/commit_hash_label"
|
||||||
|
@ -71,8 +71,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:text="@string/commit_hash"
|
android:text="@string/commit_hash"
|
||||||
app:layout_constraintTop_toBottomOf="@id/git_tools_title"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"/>
|
app:layout_constraintTop_toBottomOf="@id/git_tools_title" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/git_commit_hash"
|
android:id="@+id/git_commit_hash"
|
||||||
|
@ -80,9 +80,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintTop_toBottomOf="@id/git_tools_title"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/commit_hash_label"
|
app:layout_constraintStart_toEndOf="@id/commit_hash_label"
|
||||||
tools:text="HASH"/>
|
app:layout_constraintTop_toBottomOf="@id/git_tools_title"
|
||||||
|
tools:text="HASH" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/git_abort_rebase"
|
android:id="@+id/git_abort_rebase"
|
||||||
|
|
|
@ -42,15 +42,16 @@
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
tools:text="example.com" />
|
tools:text="example.com" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<ViewSwitcher
|
<ViewSwitcher
|
||||||
android:id="@+id/rvPasswordSwitcher"
|
android:id="@+id/rvPasswordSwitcher"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||||
app:layout_constraintBottom_toTopOf="@id/strictDomainSearch"
|
app:layout_constraintBottom_toTopOf="@id/strictDomainSearch"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/searchLayout"
|
app:layout_constraintTop_toBottomOf="@id/searchLayout">
|
||||||
android:layout_height="0dp">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/rvPassword"
|
android:id="@+id/rvPassword"
|
||||||
|
@ -84,7 +85,7 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/rvPasswordSwitcher"
|
app:layout_constraintTop_toBottomOf="@id/rvPasswordSwitcher"
|
||||||
app:layout_constraintVertical_bias="1.0"
|
app:layout_constraintVertical_bias="1.0"
|
||||||
tools:text="Phishing-resistant search"/>
|
tools:text="Phishing-resistant search" />
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/shouldMatch"
|
android:id="@+id/shouldMatch"
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".PasswordStore"
|
android:orientation="vertical"
|
||||||
android:orientation="vertical">
|
tools:context=".PasswordStore">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/main_layout"
|
android:id="@+id/main_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"/>
|
android:orientation="vertical" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="20dp"
|
|
||||||
android:paddingLeft="24dp"
|
android:paddingLeft="24dp"
|
||||||
|
android:paddingTop="20dp"
|
||||||
android:paddingRight="24dp"
|
android:paddingRight="24dp"
|
||||||
android:paddingTop="20dp">
|
android:paddingBottom="20dp">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -21,19 +21,19 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:src="@drawable/autofill_ins_1"
|
android:contentDescription="@string/autofill_ins_1_hint"
|
||||||
android:contentDescription="@string/autofill_ins_1_hint" />
|
android:src="@drawable/autofill_ins_1" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:src="@drawable/autofill_ins_2"
|
android:contentDescription="@string/autofill_ins_2_hint"
|
||||||
android:contentDescription="@string/autofill_ins_2_hint" />
|
android:src="@drawable/autofill_ins_2" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -44,10 +44,10 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="114dp"
|
android:layout_height="114dp"
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:src="@drawable/autofill_ins_3"
|
android:layout_marginBottom="8dp"
|
||||||
android:contentDescription="@string/autofill_ins_3_hint" />
|
android:contentDescription="@string/autofill_ins_3_hint"
|
||||||
|
android:src="@drawable/autofill_ins_3" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/autofill_recycler"
|
android:id="@+id/autofill_recycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
tools:listitem="@layout/autofill_row_layout"
|
tools:itemCount="20"
|
||||||
tools:itemCount="20"/>
|
tools:listitem="@layout/autofill_row_layout" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progress_bar"
|
android:id="@+id/progress_bar"
|
||||||
|
@ -24,16 +24,16 @@
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:src="@drawable/ic_add_white_48dp"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="@dimen/fab_compat_margin"
|
||||||
|
android:src="@drawable/ic_add_white_48dp"
|
||||||
|
app:backgroundTint="?attr/colorSecondary"
|
||||||
|
app:borderWidth="0dp"
|
||||||
app:elevation="6dp"
|
app:elevation="6dp"
|
||||||
app:pressedTranslationZ="12dp"
|
app:pressedTranslationZ="12dp"
|
||||||
app:backgroundTint="?attr/colorSecondary"
|
app:rippleColor="?attr/colorSecondary" />
|
||||||
app:rippleColor="?attr/colorSecondary"
|
|
||||||
app:borderWidth="0dp"
|
|
||||||
android:layout_margin="@dimen/fab_compat_margin"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentEnd="true"/>
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout android:layout_width="match_parent"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="64dp"
|
android:layout_height="64dp"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
android:paddingRight="@dimen/activity_horizontal_margin">
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/app_icon"
|
android:id="@+id/app_icon"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:contentDescription="@string/app_icon_hint"/>
|
android:contentDescription="@string/app_icon_hint" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content" />
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical" >
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/app_name"
|
android:id="@+id/secondary_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
android:textColor="?android:attr/textColor" />
|
||||||
android:id="@+id/secondary_text"
|
</LinearLayout>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:textColor="?android:attr/textColor" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context="com.zeapo.pwdstore.crypto.PgpActivity">
|
tools:context="com.zeapo.pwdstore.crypto.PgpActivity">
|
||||||
|
@ -58,8 +58,8 @@
|
||||||
android:id="@+id/divider"
|
android:id="@+id/divider"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
android:src="@drawable/divider"
|
android:src="@drawable/divider"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_password_last_changed"
|
app:layout_constraintTop_toBottomOf="@id/crypto_password_last_changed"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
|
@ -70,8 +70,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:visibility="visible"
|
app:layout_constraintTop_toBottomOf="@id/divider"
|
||||||
app:layout_constraintTop_toBottomOf="@id/divider">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_password_show_label"
|
android:id="@+id/crypto_password_show_label"
|
||||||
|
@ -79,9 +79,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/password"
|
android:text="@string/password"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_password_show"
|
android:id="@+id/crypto_password_show"
|
||||||
|
@ -90,16 +90,16 @@
|
||||||
android:layout_gravity="fill"
|
android:layout_gravity="fill"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
app:layout_constraintStart_toEndOf="@id/crypto_password_show_label"
|
android:typeface="monospace"
|
||||||
app:layout_constraintBaseline_toBaselineOf="@id/crypto_password_show_label"
|
app:layout_constraintBaseline_toBaselineOf="@id/crypto_password_show_label"
|
||||||
android:typeface="monospace" />
|
app:layout_constraintStart_toEndOf="@id/crypto_password_show_label" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/crypto_password_toggle_show"
|
android:id="@+id/crypto_password_toggle_show"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/show_password"
|
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/show_password"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_password_show_label" />
|
app:layout_constraintTop_toBottomOf="@id/crypto_password_show_label" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -116,15 +116,15 @@
|
||||||
android:id="@+id/crypto_copy_username"
|
android:id="@+id/crypto_copy_username"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:contentDescription="@string/copy_username"
|
android:contentDescription="@string/copy_username"
|
||||||
android:src="@drawable/ic_content_copy"
|
android:src="@drawable/ic_content_copy"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:visibility="visible"/>
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_username_show_label"
|
android:id="@+id/crypto_username_show_label"
|
||||||
|
@ -139,84 +139,84 @@
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_username_show"
|
android:id="@+id/crypto_username_show"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/crypto_username_show_label"
|
android:layout_below="@id/crypto_username_show_label"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
android:layout_toStartOf="@id/crypto_copy_username"
|
android:layout_toStartOf="@id/crypto_copy_username"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
android:typeface="monospace"
|
android:typeface="monospace"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_username_show_label"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
tools:visibility="visible"/>
|
app:layout_constraintTop_toBottomOf="@id/crypto_username_show_label"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/crypto_copy_otp"
|
android:id="@+id/crypto_copy_otp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_below="@id/crypto_username_show"
|
android:layout_below="@id/crypto_username_show"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:contentDescription="@string/copy_otp"
|
android:contentDescription="@string/copy_otp"
|
||||||
android:src="@drawable/ic_content_copy"
|
android:src="@drawable/ic_content_copy"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:layout_constraintTop_toTopOf="@id/crypto_otp_show_label"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:visibility="visible"/>
|
app:layout_constraintTop_toTopOf="@id/crypto_otp_show_label"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_otp_show_label"
|
android:id="@+id/crypto_otp_show_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/crypto_username_show"
|
android:layout_below="@id/crypto_username_show"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
android:layout_toStartOf="@id/crypto_copy_otp"
|
android:layout_toStartOf="@id/crypto_copy_otp"
|
||||||
android:text="@string/otp"
|
android:text="@string/otp"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_username_show"
|
android:textStyle="bold"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:textStyle="bold" />
|
app:layout_constraintTop_toBottomOf="@id/crypto_username_show" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_otp_show"
|
android:id="@+id/crypto_otp_show"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/crypto_otp_show_label"
|
android:layout_below="@id/crypto_otp_show_label"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
android:layout_toStartOf="@id/crypto_copy_otp"
|
android:layout_toStartOf="@id/crypto_copy_otp"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_otp_show_label"
|
android:typeface="monospace"
|
||||||
android:typeface="monospace" />
|
app:layout_constraintTop_toBottomOf="@id/crypto_otp_show_label" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_extra_show_label"
|
android:id="@+id/crypto_extra_show_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/crypto_otp_show"
|
android:layout_below="@id/crypto_otp_show"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
android:text="@string/extra_content"
|
android:text="@string/extra_content"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_otp_show"
|
android:textStyle="bold"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:textStyle="bold" />
|
app:layout_constraintTop_toBottomOf="@id/crypto_otp_show" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/crypto_extra_show"
|
android:id="@+id/crypto_extra_show"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@id/crypto_extra_show_label"
|
android:layout_below="@id/crypto_extra_show_label"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
android:textColor="?android:attr/textColor"
|
android:textColor="?android:attr/textColor"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_extra_show_label"
|
android:typeface="monospace"
|
||||||
android:typeface="monospace" />
|
app:layout_constraintTop_toBottomOf="@id/crypto_extra_show_label" />
|
||||||
|
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
android:id="@+id/crypto_extra_toggle_show"
|
android:id="@+id/crypto_extra_toggle_show"
|
||||||
|
@ -225,13 +225,13 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/crypto_extra_show"
|
android:layout_below="@id/crypto_extra_show"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
|
android:backgroundTint="?attr/colorSecondary"
|
||||||
android:checked="false"
|
android:checked="false"
|
||||||
android:paddingTop="8dp"
|
android:paddingTop="8dp"
|
||||||
android:textColor="?android:attr/windowBackground"
|
android:textColor="?android:attr/windowBackground"
|
||||||
android:textOff="@string/show_extra"
|
android:textOff="@string/show_extra"
|
||||||
android:textOn="@string/hide_extra"
|
android:textOn="@string/hide_extra"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_extra_show"
|
app:layout_constraintTop_toBottomOf="@id/crypto_extra_show" />
|
||||||
android:backgroundTint="?attr/colorSecondary"/>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:background="?android:attr/windowBackground"
|
android:background="?android:attr/windowBackground"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/activity_horizontal_margin"
|
android:padding="@dimen/activity_horizontal_margin"
|
||||||
|
@ -14,8 +14,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||||
android:textColor="?android:attr/textColor"
|
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
|
android:textColor="?android:attr/textColor"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
@ -23,17 +23,18 @@
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/name_input_layout"
|
android:id="@+id/name_input_layout"
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/crypto_name_hint"
|
android:hint="@string/crypto_name_hint"
|
||||||
app:layout_constraintTop_toBottomOf="@id/crypto_password_category"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintTop_toBottomOf="@id/crypto_password_category">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/crypto_password_file_edit"
|
android:id="@+id/crypto_password_file_edit"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
@ -43,13 +44,14 @@
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/crypto_pass_label"
|
android:hint="@string/crypto_pass_label"
|
||||||
app:endIconMode="password_toggle"
|
app:endIconMode="password_toggle"
|
||||||
app:layout_constraintTop_toBottomOf="@id/name_input_layout"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintTop_toBottomOf="@id/name_input_layout">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/crypto_password_edit"
|
android:id="@+id/crypto_password_edit"
|
||||||
android:inputType="textVisiblePassword"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textVisiblePassword" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
@ -58,8 +60,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:text="@string/pwd_generate_button"
|
android:text="@string/pwd_generate_button"
|
||||||
app:layout_constraintTop_toBottomOf="@id/password_input_layout"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintTop_toBottomOf="@id/password_input_layout" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/extra_input_layout"
|
android:id="@+id/extra_input_layout"
|
||||||
|
@ -67,14 +69,14 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:hint="@string/crypto_extra_label"
|
android:hint="@string/crypto_extra_label"
|
||||||
app:layout_constraintTop_toBottomOf="@id/generate_password"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintTop_toBottomOf="@id/generate_password">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/crypto_extra_edit"
|
android:id="@+id/crypto_extra_edit"
|
||||||
android:inputType="textMultiLine|textVisiblePassword"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textMultiLine|textVisiblePassword" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
@ -17,7 +15,7 @@
|
||||||
android:id="@+id/folder_name_text"
|
android:id="@+id/folder_name_text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textNoSuggestions|textVisiblePassword"/>
|
android:inputType="textNoSuggestions|textVisiblePassword" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="20dp"
|
|
||||||
android:paddingLeft="24dp"
|
android:paddingLeft="24dp"
|
||||||
|
android:paddingTop="20dp"
|
||||||
android:paddingRight="24dp"
|
android:paddingRight="24dp"
|
||||||
android:paddingTop="20dp">
|
android:paddingBottom="20dp">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="URL">
|
android:hint="URL">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/webURL"
|
android:id="@+id/webURL"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textUri"/>
|
android:inputType="textUri" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
|
@ -56,14 +56,14 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/matchButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="+"
|
|
||||||
android:id="@+id/matchButton"
|
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="+"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:checked="false"
|
android:checked="false"
|
||||||
android:text="@string/autofill_apps_never"/>
|
android:text="@string/autofill_apps_never" />
|
||||||
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="20dp"
|
|
||||||
android:paddingLeft="24dp"
|
android:paddingLeft="24dp"
|
||||||
android:paddingRight="24dp"
|
|
||||||
android:paddingTop="20dp"
|
android:paddingTop="20dp"
|
||||||
|
android:paddingRight="24dp"
|
||||||
|
android:paddingBottom="20dp"
|
||||||
tools:context=".MainActivityFragment">
|
tools:context=".MainActivityFragment">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="20dp"
|
|
||||||
android:paddingLeft="24dp"
|
android:paddingLeft="24dp"
|
||||||
|
android:paddingTop="20dp"
|
||||||
android:paddingRight="24dp"
|
android:paddingRight="24dp"
|
||||||
android:paddingTop="20dp">
|
android:paddingBottom="20dp">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/public_key"
|
android:id="@+id/public_key"
|
||||||
|
|
|
@ -18,18 +18,20 @@
|
||||||
android:text="@string/ssh_keygen_length" />
|
android:text="@string/ssh_keygen_length" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
style="@style/TextAppearance.MaterialComponents.Headline1"
|
|
||||||
android:id="@+id/key_length_group"
|
android:id="@+id/key_length_group"
|
||||||
|
style="@style/TextAppearance.MaterialComponents.Headline1"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:selectionRequired="true"
|
app:selectionRequired="true"
|
||||||
app:singleSelection="true">
|
app:singleSelection="true">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/key_length_2048"
|
android:id="@+id/key_length_2048"
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
style="?attr/materialButtonOutlinedStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/key_length_2048" />
|
android:text="@string/key_length_2048" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/key_length_4096"
|
android:id="@+id/key_length_4096"
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
style="?attr/materialButtonOutlinedStyle"
|
||||||
|
@ -49,8 +51,8 @@
|
||||||
android:id="@+id/passphrase"
|
android:id="@+id/passphrase"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:importantForAccessibility="no"
|
|
||||||
android:fontFamily="@font/sourcecodepro"
|
android:fontFamily="@font/sourcecodepro"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
android:inputType="textPassword" />
|
android:inputType="textPassword" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
@ -11,37 +10,37 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:src="@mipmap/ic_launcher"
|
|
||||||
android:contentDescription="@string/app_icon_hint"
|
android:contentDescription="@string/app_icon_hint"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
android:src="@mipmap/ic_launcher"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/app_name"
|
android:id="@+id/app_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
|
||||||
android:text="@string/app_name"
|
|
||||||
android:layout_below="@+id/app_icon"
|
android:layout_below="@+id/app_icon"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/app_icon"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintTop_toBottomOf="@+id/app_icon" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:onClick="openSettings"
|
|
||||||
android:text="@string/action_settings"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_marginEnd="@dimen/activity_horizontal_margin"
|
android:layout_marginEnd="@dimen/activity_horizontal_margin"
|
||||||
|
android:onClick="openSettings"
|
||||||
|
android:text="@string/action_settings"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -49,13 +48,13 @@
|
||||||
android:id="@+id/use_local_directory"
|
android:id="@+id/use_local_directory"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="48dp"
|
||||||
android:onClick="createNewRepository"
|
android:onClick="createNewRepository"
|
||||||
android:text="@string/initialize"
|
android:text="@string/initialize"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:layout_marginTop="48dp"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/app_name"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintTop_toBottomOf="@id/app_name" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -63,8 +62,8 @@
|
||||||
android:onClick="cloneExistingRepository"
|
android:onClick="cloneExistingRepository"
|
||||||
android:text="@string/clone"
|
android:text="@string/clone"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/use_local_directory"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintTop_toBottomOf="@id/use_local_directory" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue