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:
Harsh Shandilya 2020-05-10 19:21:39 +05:30 committed by GitHub
parent 94dc92f8d7
commit 041cf00510
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
136 changed files with 1603 additions and 1255 deletions

View file

@ -20,7 +20,7 @@
## :pencil: Checklist
<!--- 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

View file

@ -28,9 +28,6 @@ jobs:
- name: Download gradle dependencies
run: ./gradlew dependencies
- name: Validate codestyle with Spotless
run: ./gradlew spotlessCheck
- name: Build release app
run: ./gradlew :app:assembleRelease
env:

View file

@ -52,7 +52,7 @@ jobs:
${{ runner.os }}-gradlebuildcache-
- 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
uses: reactivecircus/android-emulator-runner@v2

175
.gitignore vendored
View file

@ -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
build
.DS_Store
build/
#Maven
target
pom.xml.*
# Ignore Gradle GUI config
gradle-app.setting
#Eclipse
.project
.classpath
.settings
.metadata
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
#Eclipse/Gradle integration
libs
project.properties
# Cache of project
.gradletasknamecache
#IntelliJ IDEA
.idea
*.iml
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
# Visual Studio Code
.vscode/
### Gradle Patch ###
**/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.*
# 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

View 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="&#10;" />
<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>

View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.idea/copyright/APS.xml Normal file
View file

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="/*&#10; * Copyright © 2014-&amp;#36;today.year The Android Password Store Authors. All Rights Reserved.&#10; * SPDX-License-Identifier: GPL-3.0-only&#10; */&#10;" />
<option name="myName" value="APS" />
</copyright>
</component>

22
.idea/gradle.xml Normal file
View 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>

View 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>

View file

@ -4,11 +4,11 @@
*/
package com.zeapo.pwdstore
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.junit.Test
class PasswordEntryTest {
@Test fun testGetPassword() {
@ -39,13 +39,13 @@ class PasswordEntryTest {
assertEquals("username", PasswordEntry("\n${field.toUpperCase()} username").username)
}
assertEquals(
"username",
PasswordEntry("secret\nextra\nlogin: username\ncontent\n").username)
"username",
PasswordEntry("secret\nextra\nlogin: username\ncontent\n").username)
assertEquals(
"username",
PasswordEntry("\nextra\nusername: username\ncontent\n").username)
"username",
PasswordEntry("\nextra\nusername: username\ncontent\n").username)
assertEquals(
"username", PasswordEntry("\nUSERNaMe: username\ncontent\n").username)
"username", PasswordEntry("\nUSERNaMe: username\ncontent\n").username)
assertEquals("username", PasswordEntry("\nlogin: username").username)
assertEquals("foo@example.com", PasswordEntry("\nemail: foo@example.com").username)
assertEquals("username", PasswordEntry("\nidentity: username\nlogin: another_username").username)
@ -75,7 +75,7 @@ class PasswordEntryTest {
@Test fun testTotpUriInContent() {
val entry = PasswordEntry(
"secret\nusername: test\notpauth://totp/test?secret=JBSWY3DPEHPK3PXP")
"secret\nusername: test\notpauth://totp/test?secret=JBSWY3DPEHPK3PXP")
assertTrue(entry.hasTotp())
assertEquals("JBSWY3DPEHPK3PXP", entry.totpSecret)
}
@ -96,7 +96,7 @@ class PasswordEntryTest {
@Test fun testHotpUriInContent() {
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())
assertEquals("JBSWY3DPEHPK3PXP", entry.hotpSecret)
assertEquals(25, entry.hotpCounter)

View file

@ -4,10 +4,10 @@
*/
package com.zeapo.pwdstore
import org.junit.Test
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.junit.Test
private infix fun String.matchedForDomain(domain: String) =
SearchableRepositoryViewModel.generateStrictDomainRegex(domain)?.containsMatchIn(this) == true

View file

@ -3,23 +3,24 @@
android:height="108dp"
android:viewportWidth="110.34687"
android:viewportHeight="110.34687">
<group android:translateX="24.828047"
android:translateY="24.828047">
<path
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:strokeWidth="5.349"
android:fillColor="#00000000"
android:strokeColor="#013e5b"/>
<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:fillColor="#c74c00"/>
<path
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"
android:strokeWidth=".35344"
android:fillColor="#fff"/>
<path
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"
android:fillColor="#f47a68"/>
<group
android:translateX="24.828047"
android:translateY="24.828047">
<path
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:strokeWidth="5.349"
android:strokeColor="#013e5b" />
<path
android:fillColor="#c74c00"
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="#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"
android:strokeWidth=".35344" />
<path
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>
</vector>

View file

@ -21,9 +21,9 @@
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:requestLegacyExternalStorage="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
@ -31,30 +31,35 @@
android:configChanges="orientation|screenSize"
android:label="@string/app_name" />
<activity android:name=".LaunchActivity"
android:label="@string/app_name"
android:configChanges="orientation|screenSize">
<activity
android:name=".LaunchActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".git.GitOperationActivity"
<activity
android:name=".git.GitOperationActivity"
android:theme="@style/NoBackgroundTheme" />
<activity android:name=".git.GitServerConfigActivity"
android:windowSoftInputMode="adjustResize"
android:label="@string/title_activity_git_clone" />
<activity
android:name=".git.GitServerConfigActivity"
android:label="@string/title_activity_git_clone"
android:windowSoftInputMode="adjustResize" />
<activity android:name=".git.GitConfigActivity"
android:windowSoftInputMode="adjustResize"
android:label="@string/title_activity_git_config" />
<activity
android:name=".git.GitConfigActivity"
android:label="@string/title_activity_git_config"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".UserPreference"
android:parentActivityName=".PasswordStore"
android:label="@string/action_settings" />
android:label="@string/action_settings"
android:parentActivityName=".PasswordStore" />
<service
android:name=".autofill.AutofillService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
@ -66,14 +71,17 @@
android:resource="@xml/autofill_config" />
</service>
<service
android:name=".ClipboardService"
android:process=":clipboard_service_process" />
<service android:name=".autofill.oreo.OreoAutofillService"
android:name=".ClipboardService"
android:process=":clipboard_service_process" />
<service
android:name=".autofill.oreo.OreoAutofillService"
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
<intent-filter>
<action android:name="android.service.autofill.AutofillService" />
</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>
<activity
@ -87,13 +95,13 @@
<activity
android:name=".crypto.PgpActivity"
android:configChanges="orientation|screenSize"
android:parentActivityName=".PasswordStore"
android:windowSoftInputMode="adjustResize"
android:configChanges="orientation|screenSize" />
android:windowSoftInputMode="adjustResize" />
<activity android:name=".SelectFolderActivity" />
<activity
android:label="@string/pref_ssh_keygen_title"
android:name=".sshkeygen.SshKeyGenActivity"
android:label="@string/pref_ssh_keygen_title"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".autofill.oreo.ui.AutofillDecryptActivity"
@ -101,16 +109,16 @@
<activity
android:name=".autofill.oreo.ui.AutofillFilterView"
android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="adjustNothing"
android:theme="@style/DialogLikeTheme" />
android:theme="@style/DialogLikeTheme"
android:windowSoftInputMode="adjustNothing" />
<activity
android:name=".autofill.oreo.ui.AutofillSaveActivity"
android:theme="@style/NoBackgroundTheme"/>
android:theme="@style/NoBackgroundTheme" />
<activity
android:name=".autofill.oreo.ui.AutofillPublisherChangedActivity"
android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="adjustNothing"
android:theme="@style/DialogLikeTheme" />
android:theme="@style/DialogLikeTheme"
android:windowSoftInputMode="adjustNothing" />
</application>
</manifest>

View file

@ -17,6 +17,7 @@ import com.haroldadmin.whatthestack.WhatTheStack
@Suppress("Unused")
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
private var prefs: SharedPreferences? = null
override fun onCreate() {

View file

@ -122,13 +122,13 @@ class ClipboardService : Service() {
}
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.tap_clear_clipboard))
.setSmallIcon(R.drawable.ic_action_secure_24dp)
.setContentIntent(pendingIntent)
.setUsesChronometer(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.tap_clear_clipboard))
.setSmallIcon(R.drawable.ic_action_secure_24dp)
.setContentIntent(pendingIntent)
.setUsesChronometer(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
startForeground(1, notification)
}
@ -136,9 +136,9 @@ class ClipboardService : Service() {
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
CHANNEL_ID,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
)
val manager = getSystemService<NotificationManager>()
if (manager != null) {

View file

@ -14,6 +14,7 @@ import java.io.UnsupportedEncodingException
* A single entry in password store.
*/
class PasswordEntry(private val content: String) {
val password: String
val username: String?
val digits: String
@ -109,8 +110,8 @@ class PasswordEntry(private val content: String) {
private fun findOtpDigits(decryptedContent: String): String {
decryptedContent.split("\n".toRegex()).forEach { line ->
if ((line.startsWith("otpauth://totp/") ||
line.startsWith("otpauth://hotp/")) &&
Uri.parse(line).getQueryParameter("digits") != null) {
line.startsWith("otpauth://hotp/")) &&
Uri.parse(line).getQueryParameter("digits") != null) {
return Uri.parse(line).getQueryParameter("digits")!!
}
}
@ -120,7 +121,7 @@ class PasswordEntry(private val content: String) {
private fun findTotpPeriod(decryptedContent: String): Long {
decryptedContent.split("\n".toRegex()).forEach { line ->
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")!!)
}
}
@ -130,7 +131,7 @@ class PasswordEntry(private val content: String) {
private fun findTotpAlgorithm(decryptedContent: String): String {
decryptedContent.split("\n".toRegex()).forEach { line ->
if (line.startsWith("otpauth://totp/") &&
Uri.parse(line).getQueryParameter("algorithm") != null) {
Uri.parse(line).getQueryParameter("algorithm") != null) {
return Uri.parse(line).getQueryParameter("algorithm")!!
}
}
@ -166,15 +167,15 @@ class PasswordEntry(private val content: String) {
companion object {
@VisibleForTesting(otherwise = PRIVATE)
val USERNAME_FIELDS = arrayOf(
"login:",
"username:",
"user:",
"account:",
"email:",
"name:",
"handle:",
"id:",
"identity:"
"login:",
"username:",
"user:",
"account:",
"email:",
"name:",
"handle:",
"id:",
"identity:"
)
}
}

View file

@ -33,9 +33,9 @@ import com.zeapo.pwdstore.ui.adapters.PasswordItemRecyclerAdapter
import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet
import com.zeapo.pwdstore.utils.PasswordItem
import com.zeapo.pwdstore.utils.PasswordRepository
import me.zhanghai.android.fastscroll.FastScrollerBuilder
import java.io.File
import java.util.Stack
import me.zhanghai.android.fastscroll.FastScrollerBuilder
class PasswordFragment : Fragment() {
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
@ -74,12 +74,12 @@ class PasswordFragment : Fragment() {
binding.swipeRefresher.setOnRefreshListener {
if (!PasswordRepository.isGitRepo()) {
Snackbar.make(binding.root, getString(R.string.clone_git_repo), Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.clone_button) {
val intent = Intent(context, GitServerConfigActivity::class.java)
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
}
.show()
.setAction(R.string.clone_button) {
val intent = Intent(context, GitServerConfigActivity::class.java)
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_CLONE)
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
}
.show()
binding.swipeRefresher.isRefreshing = false
} else {
// 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) {
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 {
override fun onAnimationRepeat(animation: Animation?) {
@ -226,9 +226,9 @@ class PasswordFragment : Fragment() {
}
})
animate().rotationBy(if (show) -90f else 90f)
.setStartDelay(if (show) 100 else 0)
.setDuration(100)
.start()
.setStartDelay(if (show) 100 else 0)
.setDuration(100)
.start()
startAnimation(animation)
}
}

View file

@ -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.isInitialized
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.FilenameUtils
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.errors.GitAPIException
import org.eclipse.jgit.revwalk.RevCommit
import java.io.File
import java.lang.Character.UnicodeBlock
import java.util.Stack
class PasswordStore : AppCompatActivity() {
@ -90,7 +90,7 @@ class PasswordStore : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
// open search view on search key, or Ctr+F
if ((keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_F && event.isCtrlPressed) &&
!searchItem.isActionViewExpanded) {
!searchItem.isActionViewExpanded) {
searchItem.expandActionView()
return true
}
@ -118,9 +118,9 @@ class PasswordStore : AppCompatActivity() {
// prevent attempt to create password list fragment
var savedInstance = savedInstanceState
if (savedInstanceState != null && (!settings.getBoolean("git_external", false) ||
ContextCompat.checkSelfPermission(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)) {
ContextCompat.checkSelfPermission(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)) {
savedInstance = null
}
super.onCreate(savedInstance)
@ -128,28 +128,28 @@ class PasswordStore : AppCompatActivity() {
// If user is eligible for Oreo autofill, prompt them to switch.
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 {
@SuppressLint("InflateParams")
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)
val supportedBrowsersTextView =
layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers)
layout.findViewById<AppCompatTextView>(R.id.supportedBrowsers)
supportedBrowsersTextView.text =
getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(
separator = "\n"
) {
val appLabel = it.first
val supportDescription = when (it.second) {
BrowserAutofillSupportLevel.None -> getString(R.string.oreo_autofill_no_support)
BrowserAutofillSupportLevel.FlakyFill -> getString(R.string.oreo_autofill_flaky_fill_support)
BrowserAutofillSupportLevel.PasswordFill -> getString(R.string.oreo_autofill_password_fill_support)
BrowserAutofillSupportLevel.GeneralFill -> getString(R.string.oreo_autofill_general_fill_support)
BrowserAutofillSupportLevel.GeneralFillAndSave -> getString(R.string.oreo_autofill_general_fill_and_save_support)
}
"$appLabel: $supportDescription"
getInstalledBrowsersWithAutofillSupportLevel(context).joinToString(
separator = "\n"
) {
val appLabel = it.first
val supportDescription = when (it.second) {
BrowserAutofillSupportLevel.None -> getString(R.string.oreo_autofill_no_support)
BrowserAutofillSupportLevel.FlakyFill -> getString(R.string.oreo_autofill_flaky_fill_support)
BrowserAutofillSupportLevel.PasswordFill -> getString(R.string.oreo_autofill_password_fill_support)
BrowserAutofillSupportLevel.GeneralFill -> getString(R.string.oreo_autofill_general_fill_support)
BrowserAutofillSupportLevel.GeneralFillAndSave -> getString(R.string.oreo_autofill_general_fill_and_save_support)
}
"$appLabel: $supportDescription"
}
setView(layout)
setTitle(R.string.autofill_onboarding_dialog_title)
setPositiveButton(R.string.dialog_ok) { _, _ ->
@ -204,7 +204,7 @@ class PasswordStore : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val menuRes = when {
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
else -> R.menu.main_menu_non_git
}
@ -219,40 +219,40 @@ class PasswordStore : AppCompatActivity() {
searchItem = menu.findItem(R.id.action_search)
searchView = searchItem.actionView as SearchView
searchView.setOnQueryTextListener(
object : OnQueryTextListener {
override fun onQueryTextSubmit(s: String): Boolean {
searchView.clearFocus()
return true
}
object : OnQueryTextListener {
override fun onQueryTextSubmit(s: String): Boolean {
searchView.clearFocus()
return true
}
override fun onQueryTextChange(s: String): Boolean {
val filter = s.trim()
// List the contents of the current directory if the user enters a blank
// search term.
if (filter.isEmpty())
model.navigateTo(
newDirectory = model.currentDir.value!!,
pushPreviousLocation = false
)
else
model.search(filter)
return true
}
})
override fun onQueryTextChange(s: String): Boolean {
val filter = s.trim()
// List the contents of the current directory if the user enters a blank
// search term.
if (filter.isEmpty())
model.navigateTo(
newDirectory = model.currentDir.value!!,
pushPreviousLocation = false
)
else
model.search(filter)
return true
}
})
// When using the support library, the setOnActionExpandListener() method is
// static and accepts the MenuItem object as an argument
searchItem.setOnActionExpandListener(
object : OnActionExpandListener {
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
refreshPasswordList()
return true
}
object : OnActionExpandListener {
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
refreshPasswordList()
return true
}
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
return true
}
})
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
return true
}
})
if (settings.getBoolean("search_on_start", false)) {
searchItem.expandActionView()
}
@ -266,8 +266,8 @@ class PasswordStore : AppCompatActivity() {
val id = item.itemId
val intent: Intent
val initBefore = MaterialAlertDialogBuilder(this)
.setMessage(resources.getString(R.string.creation_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
.setMessage(resources.getString(R.string.creation_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
when (id) {
R.id.user_pref -> {
try {
@ -379,7 +379,7 @@ class PasswordStore : AppCompatActivity() {
if (externalRepo && externalRepoPath != null) {
val dir = File(externalRepoPath)
if (dir.exists() && dir.isDirectory &&
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
closeRepository()
checkLocalRepository()
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())
if (keyIds != null && keyIds.isEmpty()) {
MaterialAlertDialogBuilder(this)
.setMessage(resources.getString(R.string.key_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_positive)) { _, _ ->
val intent = Intent(activity, UserPreference::class.java)
startActivityForResult(intent, BaseGitActivity.REQUEST_INIT)
}
.setNegativeButton(resources.getString(R.string.dialog_negative), null)
.show()
.setMessage(resources.getString(R.string.key_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_positive)) { _, _ ->
val intent = Intent(activity, UserPreference::class.java)
startActivityForResult(intent, BaseGitActivity.REQUEST_INIT)
}
.setNegativeButton(resources.getString(R.string.dialog_negative), null)
.show()
}
createRepository()
}
@ -407,15 +407,15 @@ class PasswordStore : AppCompatActivity() {
return if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
Snackbar.make(
findViewById(R.id.main_layout),
getString(R.string.access_sdcard_text),
Snackbar.LENGTH_INDEFINITE
findViewById(R.id.main_layout),
getString(R.string.access_sdcard_text),
Snackbar.LENGTH_INDEFINITE
).run {
setAction(getString(R.string.snackbar_action_grant)) {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_EXTERNAL_STORAGE
activity,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_EXTERNAL_STORAGE
)
dismiss()
}
@ -447,7 +447,7 @@ class PasswordStore : AppCompatActivity() {
tag(TAG).d { "Check, dir: ${localDir.absolutePath}" }
// do not push the fragment if we already have it
if (fragmentManager.findFragmentByTag("PasswordsList") == null ||
settings.getBoolean("repo_changed", false)) {
settings.getBoolean("repo_changed", false)) {
settings.edit { putBoolean("repo_changed", false) }
plist = PasswordFragment()
val args = Bundle()
@ -520,11 +520,11 @@ class PasswordStore : AppCompatActivity() {
// Adds shortcut
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
val shortcut = Builder(this, item.fullPathToParent)
.setShortLabel(item.toString())
.setLongLabel(item.fullPathToParent + item.toString())
.setIcon(Icon.createWithResource(this, R.mipmap.ic_launcher))
.setIntent(authDecryptIntent.setAction("DECRYPT_PASS")) // Needs action
.build()
.setShortLabel(item.toString())
.setLongLabel(item.fullPathToParent + item.toString())
.setIcon(Icon.createWithResource(this, R.mipmap.ic_launcher))
.setIntent(authDecryptIntent.setAction("DECRYPT_PASS")) // Needs action
.build()
val shortcuts = shortcutManager!!.dynamicShortcuts
if (shortcuts.size >= shortcutManager!!.maxShortcutCountPerActivity && shortcuts.size > 0) {
shortcuts.removeAt(shortcuts.size - 1)
@ -550,20 +550,20 @@ class PasswordStore : AppCompatActivity() {
private fun validateState(): Boolean {
if (!isInitialized) {
MaterialAlertDialogBuilder(this)
.setMessage(resources.getString(R.string.creation_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
.show()
.setMessage(resources.getString(R.string.creation_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
.show()
return false
}
if (settings.getStringSet("openpgp_key_ids_set", HashSet()).isNullOrEmpty()) {
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.no_key_selected_dialog_title))
.setMessage(resources.getString(R.string.no_key_selected_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ ->
val intent = Intent(activity, UserPreference::class.java)
startActivity(intent)
}
.show()
.setTitle(resources.getString(R.string.no_key_selected_dialog_title))
.setMessage(resources.getString(R.string.no_key_selected_dialog_text))
.setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ ->
val intent = Intent(activity, UserPreference::class.java)
startActivity(intent)
}
.show()
return false
}
return true
@ -593,22 +593,22 @@ class PasswordStore : AppCompatActivity() {
}
val item = selectedItems.pop()
MaterialAlertDialogBuilder(this)
.setMessage(resources.getString(R.string.delete_dialog_text, item.longName))
.setPositiveButton(resources.getString(R.string.dialog_yes)) { _, _ ->
val filesToDelete = if (item.file.isDirectory) {
FileUtils.listFiles(item.file, null, true)
} else {
listOf(item.file)
}
AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete)
item.file.deleteRecursively()
commitChange(resources.getString(R.string.git_commit_remove_text, item.longName))
deletePasswords(selectedItems)
.setMessage(resources.getString(R.string.delete_dialog_text, item.longName))
.setPositiveButton(resources.getString(R.string.dialog_yes)) { _, _ ->
val filesToDelete = if (item.file.isDirectory) {
FileUtils.listFiles(item.file, null, true)
} else {
listOf(item.file)
}
.setNegativeButton(resources.getString(R.string.dialog_no)) { _, _ ->
deletePasswords(selectedItems)
}
.show()
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)) { _, _ ->
deletePasswords(selectedItems)
}
.show()
}
fun movePasswords(values: List<PasswordItem>) {
@ -661,22 +661,22 @@ class PasswordStore : AppCompatActivity() {
if (data != null && data.getBooleanExtra("needCommit", false)) {
if (data.getStringExtra("OPERATION") == "EDIT") {
commitChange(resources.getString(R.string.git_commit_edit_text,
data.extras!!.getString("LONG_NAME")))
data.extras!!.getString("LONG_NAME")))
} else {
commitChange(resources.getString(R.string.git_commit_increment_text,
data.extras!!.getString("LONG_NAME")))
data.extras!!.getString("LONG_NAME")))
}
}
refreshPasswordList()
}
REQUEST_CODE_ENCRYPT -> {
commitChange(resources.getString(R.string.git_commit_add_text,
data!!.extras!!.getString("LONG_NAME")))
data!!.extras!!.getString("LONG_NAME")))
refreshPasswordList()
}
REQUEST_CODE_EDIT -> {
commitChange(resources.getString(R.string.git_commit_edit_text,
data!!.extras!!.getString("LONG_NAME")))
data!!.extras!!.getString("LONG_NAME")))
refreshPasswordList()
}
BaseGitActivity.REQUEST_INIT, NEW_REPO_BUTTON -> initializeRepositoryInfo()
@ -685,14 +685,14 @@ class PasswordStore : AppCompatActivity() {
// duplicate code
CLONE_REPO_BUTTON -> {
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 dir = externalRepoPath?.let { File(it) }
if (dir != null &&
dir.exists() &&
dir.isDirectory &&
!FileUtils.listFiles(dir, null, true).isEmpty() &&
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
dir.exists() &&
dir.isDirectory &&
!FileUtils.listFiles(dir, null, true).isEmpty() &&
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
closeRepository()
checkLocalRepository()
return // if not empty, just show me the passwords!
@ -732,17 +732,17 @@ class PasswordStore : AppCompatActivity() {
if (destinationFile.exists()) {
e { "Trying to move a file that already exists." }
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.password_exists_title))
.setMessage(resources.getString(
R.string.password_exists_message,
destinationLongName,
sourceLongName)
)
.setPositiveButton(R.string.dialog_ok) { _, _ ->
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
.setTitle(resources.getString(R.string.password_exists_title))
.setMessage(resources.getString(
R.string.password_exists_message,
destinationLongName,
sourceLongName)
)
.setPositiveButton(R.string.dialog_ok) { _, _ ->
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
} else {
movePasswords(source, destinationFile, sourceLongName, destinationLongName)
}
@ -773,66 +773,66 @@ class PasswordStore : AppCompatActivity() {
} else {
AutofillMatcher.updateMatches(this, sourceDestinationMap)
commitChange(resources
.getString(
R.string.git_commit_move_text,
sourceLongName,
destinationLongName))
.getString(
R.string.git_commit_move_text,
sourceLongName,
destinationLongName))
}
}
private fun initRepository(operation: Int) {
closeRepository()
MaterialAlertDialogBuilder(this)
.setTitle(resources.getString(R.string.location_dialog_title))
.setMessage(resources.getString(R.string.location_dialog_text))
.setPositiveButton(resources.getString(R.string.location_hidden)) { _, _ ->
settings.edit { putBoolean("git_external", false) }
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)
.setTitle(resources.getString(R.string.location_dialog_title))
.setMessage(resources.getString(R.string.location_dialog_text))
.setPositiveButton(resources.getString(R.string.location_hidden)) { _, _ ->
settings.edit { putBoolean("git_external", false) }
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.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) }
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()
}
.show()
}
fun matchPasswordWithApp(item: PasswordItem) {
val path = item.file
.absolutePath
.replace(getRepositoryDirectory(applicationContext).toString() + "/", "")
.replace(".gpg", "")
.absolutePath
.replace(getRepositoryDirectory(applicationContext).toString() + "/", "")
.replace(".gpg", "")
val data = Intent()
data.putExtra("path", path)
setResult(Activity.RESULT_OK, data)
@ -860,7 +860,7 @@ class PasswordStore : AppCompatActivity() {
private fun isPrintable(c: Char): Boolean {
val block = UnicodeBlock.of(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"

View file

@ -30,10 +30,6 @@ import com.zeapo.pwdstore.autofill.oreo.AutofillPreferences
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
import com.zeapo.pwdstore.utils.PasswordItem
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.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
@ -48,6 +44,10 @@ import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.yield
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)
PasswordItem.newPassword(name, this, root)

View file

@ -18,8 +18,8 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.zeapo.pwdstore.ui.adapters.PasswordItemRecyclerAdapter
import com.zeapo.pwdstore.utils.PasswordItem
import java.io.File
import me.zhanghai.android.fastscroll.FastScrollerBuilder
import java.io.File
class SelectFolderFragment : Fragment() {
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
@ -75,7 +75,7 @@ class SelectFolderFragment : Fragment() {
}
} catch (e: ClassCastException) {
throw ClassCastException(
"$context must implement OnFragmentInteractionListener")
"$context must implement OnFragmentInteractionListener")
}
}

View file

@ -50,6 +50,8 @@ import com.zeapo.pwdstore.utils.BiometricAuthenticator
import com.zeapo.pwdstore.utils.PasswordRepository
import com.zeapo.pwdstore.utils.autofillManager
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.IOException
import java.time.LocalDateTime
@ -57,8 +59,6 @@ import java.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.HashSet
import java.util.TimeZone
import me.msfjarvis.openpgpktx.util.OpenPgpUtils
import org.apache.commons.io.FileUtils
typealias ClickListener = Preference.OnPreferenceClickListener
typealias ChangeListener = Preference.OnPreferenceChangeListener
@ -98,8 +98,8 @@ class UserPreference : AppCompatActivity() {
if (!PasswordRepository.isGitRepo()) {
listOfNotNull(
gitServerPreference, gitConfigPreference, sshKeyPreference,
sshKeygenPreference, viewSshKeyPreference, clearSavedPassPreference
gitServerPreference, gitConfigPreference, sshKeyPreference,
sshKeygenPreference, viewSshKeyPreference, clearSavedPassPreference
).forEach {
it.parent?.removePreference(it)
}
@ -121,10 +121,10 @@ class UserPreference : AppCompatActivity() {
val autoFillShowFullNamePreference =
findPreference<CheckBoxPreference>("autofill_full_path")!!
autofillDependencies = listOf(
autoFillAppsPreference,
autoFillDefaultPreference,
autoFillAlwaysShowDialogPreference,
autoFillShowFullNamePreference
autoFillAppsPreference,
autoFillDefaultPreference,
autoFillAlwaysShowDialogPreference,
autoFillShowFullNamePreference
)
val oreoAutofillDirectoryStructurePreference =
findPreference<ListPreference>("oreo_autofill_directory_structure")!!
@ -139,7 +139,7 @@ class UserPreference : AppCompatActivity() {
clearHotpIncrementPreference?.isVisible = sharedPreferences.getBoolean("hotp_remember_check", false)
clearClipboard20xPreference?.isVisible = sharedPreferences.getString("general_show_time", "45")?.toInt() != 0
val selectedKeys = (sharedPreferences.getStringSet("openpgp_key_ids_set", null)
?: HashSet()).toTypedArray()
?: HashSet()).toTypedArray()
keyPreference?.summary = if (selectedKeys.isEmpty()) {
this.resources.getString(R.string.pref_no_key_selected)
} else {
@ -148,7 +148,7 @@ class UserPreference : AppCompatActivity() {
}
}
openkeystoreIdPreference?.isVisible = sharedPreferences.getString("ssh_openkeystore_keyid", null)?.isNotEmpty()
?: false
?: false
updateAutofillSettings()
updateClearSavedPassphrasePrefs()
@ -220,29 +220,29 @@ class UserPreference : AppCompatActivity() {
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext)
MaterialAlertDialogBuilder(callingActivity)
.setTitle(R.string.pref_dialog_delete_title)
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
try {
FileUtils.cleanDirectory(PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext))
PasswordRepository.closeRepository()
} catch (ignored: Exception) {
// TODO Handle the different cases of exceptions
}
sharedPreferences.edit { putBoolean("repository_initialized", false) }
dialogInterface.cancel()
callingActivity.finish()
.setTitle(R.string.pref_dialog_delete_title)
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
try {
FileUtils.cleanDirectory(PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext))
PasswordRepository.closeRepository()
} catch (ignored: Exception) {
// TODO Handle the different cases of exceptions
}
.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
}
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 {
callingActivity.selectExternalGitRepository()
true
@ -484,23 +484,23 @@ class UserPreference : AppCompatActivity() {
prefsFragment = PrefsFragment()
supportFragmentManager
.beginTransaction()
.replace(android.R.id.content, prefsFragment)
.commit()
.beginTransaction()
.replace(android.R.id.content, prefsFragment)
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
fun selectExternalGitRepository() {
MaterialAlertDialogBuilder(this)
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
.setPositiveButton(R.string.dialog_ok) { _, _ ->
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
startActivityForResult(Intent.createChooser(i, "Choose Directory"), SELECT_GIT_DIRECTORY)
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
.setPositiveButton(R.string.dialog_ok) { _, _ ->
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
startActivityForResult(Intent.createChooser(i, "Choose Directory"), SELECT_GIT_DIRECTORY)
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -630,9 +630,9 @@ class UserPreference : AppCompatActivity() {
copySshKey(uri)
Toast.makeText(
this,
this.resources.getString(R.string.ssh_key_success_dialog_title),
Toast.LENGTH_LONG
this,
this.resources.getString(R.string.ssh_key_success_dialog_title),
Toast.LENGTH_LONG
).show()
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
@ -668,13 +668,13 @@ class UserPreference : AppCompatActivity() {
if (Environment.getExternalStorageDirectory().path == repoPath) {
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.sdcard_root_warning_title))
.setMessage(getString(R.string.sdcard_root_warning_message))
.setPositiveButton("Remove everything") { _, _ ->
prefs.edit { putString("git_external_repo", uri?.path) }
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
.setTitle(getString(R.string.sdcard_root_warning_title))
.setMessage(getString(R.string.sdcard_root_warning_message))
.setPositiveButton("Remove everything") { _, _ ->
prefs.edit { putString("git_external_repo", uri?.path) }
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
}
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")
Toast.makeText(
this,
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
Toast.LENGTH_SHORT
this,
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
Toast.LENGTH_SHORT
).show()
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
@ -731,8 +731,8 @@ class UserPreference : AppCompatActivity() {
val dateString = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LocalDateTime
.now()
.format(DateTimeFormatter.ISO_DATE_TIME)
.now()
.format(DateTimeFormatter.ISO_DATE_TIME)
} else {
String.format("%tFT%<tRZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))
}

View file

@ -60,11 +60,11 @@ class AutofillFragment : DialogFragment() {
} else {
val browserIntent = Intent("android.intent.action.VIEW", Uri.parse("http://"))
val resolveInfo = requireContext().packageManager
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
iconPackageName = resolveInfo?.activityInfo?.packageName
builder.setTitle("Website")
(view.findViewById<View>(R.id.webURL) as EditText).setText(packageName
?: "com.android.browser")
?: "com.android.browser")
}
try {
if (iconPackageName != null) {
@ -86,9 +86,9 @@ class AutofillFragment : DialogFragment() {
(view.findViewById<View>(R.id.matched) as ListView).adapter = adapter
// delete items by clicking them
(view.findViewById<View>(R.id.matched) as ListView).onItemClickListener =
AdapterView.OnItemClickListener { _, _, position, _ ->
adapter!!.remove(adapter!!.getItem(position))
}
AdapterView.OnItemClickListener { _, _, position, _ ->
adapter!!.remove(adapter!!.getItem(position))
}
// set the existing preference, if any
val prefs: SharedPreferences = if (!isWeb) {
@ -122,7 +122,7 @@ class AutofillFragment : DialogFragment() {
if (isWeb) {
builder.setNeutralButton(R.string.autofill_apps_delete) { _, _ ->
if (callingActivity.recyclerAdapter != null &&
packageName != null && packageName != "") {
packageName != null && packageName != "") {
prefs.edit {
remove(packageName)
callingActivity.recyclerAdapter?.removeWebsite(packageName)

View file

@ -19,9 +19,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.zeapo.pwdstore.R
import me.zhanghai.android.fastscroll.FastScrollerBuilder
import java.lang.ref.WeakReference
import java.util.ArrayList
import me.zhanghai.android.fastscroll.FastScrollerBuilder
class AutofillPreferenceActivity : AppCompatActivity() {

View file

@ -18,9 +18,9 @@ import androidx.recyclerview.widget.SortedList
import androidx.recyclerview.widget.SortedListAdapterCallback
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.utils.splitLines
import me.zhanghai.android.fastscroll.PopupTextProvider
import java.util.ArrayList
import java.util.Locale
import me.zhanghai.android.fastscroll.PopupTextProvider
internal class AutofillRecyclerAdapter(
allApps: List<AppInfo>,
@ -63,7 +63,7 @@ internal class AutofillRecyclerAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
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)
}
@ -96,7 +96,7 @@ internal class AutofillRecyclerAdapter(
holder.secondary.append(" " + preference!!.splitLines()[0])
if (preference.trim { it <= ' ' }.splitLines().size - 1 > 0) {
holder.secondary.append(" and " +
(preference.trim { it <= ' ' }.splitLines().size - 1) + " more")
(preference.trim { it <= ' ' }.splitLines().size - 1) + " more")
}
}
}

View file

@ -32,15 +32,6 @@ import com.zeapo.pwdstore.PasswordEntry
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.utils.PasswordRepository
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.Dispatchers
import kotlinx.coroutines.cancel
@ -51,6 +42,15 @@ import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
import org.apache.commons.io.FileUtils
import org.openintents.openpgp.IOpenPgpService2
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) {
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 (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
event.packageName != null && event.packageName == packageName &&
resultData != null) {
event.packageName != null && event.packageName == packageName &&
resultData != null) {
bindDecryptAndVerify()
}
// look for webView and trigger accessibility events if window changes
// or if page changes in chrome
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED &&
event.packageName != null &&
(event.packageName == "com.android.chrome" || event.packageName == "com.android.browser"))) {
event.packageName != null &&
(event.packageName == "com.android.chrome" || event.packageName == "com.android.browser"))) {
// there is a chance for getRootInActiveWindow() to return null at any time. save it.
try {
val root = rootInActiveWindow
@ -145,8 +145,8 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
// nothing to do if field is keychain app or system ui
if (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED ||
event.packageName != null && event.packageName == "org.sufficientlysecure.keychain" ||
event.packageName != null && event.packageName == "com.android.systemui") {
event.packageName != null && event.packageName == "org.sufficientlysecure.keychain" ||
event.packageName != null && event.packageName == "com.android.systemui") {
dismissDialog()
return
}
@ -182,7 +182,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
// need to request permission before attempting to draw dialog
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()))
Uri.parse("package:" + getPackageName()))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
return
@ -283,7 +283,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
val value = prefs.getString(key, null)
val keyLowerCase = key.toLowerCase(Locale.ROOT)
if (value != null && value != "" &&
(webViewUrlLowerCase.contains(keyLowerCase) || keyLowerCase.contains(webViewUrlLowerCase))) {
(webViewUrlLowerCase.contains(keyLowerCase) || keyLowerCase.contains(webViewUrlLowerCase))) {
preference = value
settingsURL = key
}
@ -419,7 +419,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
for (i in items.indices) {
if (autofillFullPath) {
itemNames[i] = items[i].path.replace(".gpg", "")
.replace("$passwordDirectory/", "")
.replace("$passwordDirectory/", "")
} else {
itemNames[i] = items[i].name.replace(".gpg", "")
}

View file

@ -31,6 +31,7 @@ private fun Context.matchPreferences(formOrigin: FormOrigin): SharedPreferences
class AutofillPublisherChangedException(val formOrigin: FormOrigin) :
Exception("The publisher of '${formOrigin.identifier}' changed since an entry was first matched with this app") {
init {
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.
*/
class AutofillMatcher {
companion object {
private const val MAX_NUM_MATCHES = 10
@ -172,10 +174,10 @@ class AutofillMatcher {
.minus(deletePathList)
.minus(oldNewPathMap.values)
.map { match ->
val newPath = oldNewPathMap[match] ?: return@map match
d { "Updating match for $key: $match --> $newPath" }
newPath
}.toSet()
val newPath = oldNewPathMap[match] ?: return@map match
d { "Updating match for $key: $match --> $newPath" }
newPath
}.toSet()
if (newMatches != oldMatches)
prefs.edit { putStringSet(key, newMatches) }
}

View file

@ -130,6 +130,7 @@ data class ClassifiedAutofillScenario<T : Any>(
val currentPassword: List<T>,
val newPassword: List<T>
) : AutofillScenario<T>() {
override val allPasswordFields
get() = currentPassword + newPassword
override val passwordFieldsToFillOnMatch
@ -148,6 +149,7 @@ data class GenericAutofillScenario<T : Any>(
override val fillUsername: Boolean,
val genericPassword: List<T>
) : AutofillScenario<T>() {
override val allPasswordFields
get() = genericPassword
override val passwordFieldsToFillOnMatch

View file

@ -14,10 +14,12 @@ annotation class AutofillDsl
@RequiresApi(Build.VERSION_CODES.O)
interface FieldMatcher {
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
@AutofillDsl
class Builder {
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
mutableListOf()
@ -68,6 +70,7 @@ class SingleFieldMatcher(
@AutofillDsl
class Builder {
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
mutableListOf()
@ -169,6 +172,7 @@ class AutofillRule private constructor(
private val applyInSingleOriginMode: Boolean,
private val applyOnManualRequestOnly: Boolean
) {
companion object {
private var ruleId = 1
}
@ -304,6 +308,7 @@ class AutofillStrategy private constructor(private val rules: List<AutofillRule>
@AutofillDsl
class Builder {
private val rules: MutableList<AutofillRule> = mutableListOf()
fun rule(

View file

@ -31,6 +31,7 @@ import java.io.File
* A unique identifier for either an Android app (package name) or a website (origin minus port).
*/
sealed class FormOrigin(open val identifier: String) {
data class Web(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 saveFlags: Int?
) {
companion object {
fun makeFillInDataset(
context: Context,

View file

@ -22,16 +22,6 @@ import com.zeapo.pwdstore.autofill.oreo.AutofillPreferences
import com.zeapo.pwdstore.autofill.oreo.Credentials
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
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.Dispatchers
import kotlinx.coroutines.SupervisorJob
@ -42,6 +32,16 @@ import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
import org.openintents.openpgp.IOpenPgpService2
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)
class AutofillDecryptActivity : Activity(), CoroutineScope {
@ -214,9 +214,9 @@ class AutofillDecryptActivity : Activity(), CoroutineScope {
if (error != null) {
withContext(Dispatchers.Main) {
Toast.makeText(
applicationContext,
"Error from OpenKeyChain: ${error.message}",
Toast.LENGTH_LONG
applicationContext,
"Error from OpenKeyChain: ${error.message}",
Toast.LENGTH_LONG
).show()
}
e { "OpenPgpApi ACTION_DECRYPT_VERIFY failed (${error.errorId}): ${error.message}" }

View file

@ -78,19 +78,19 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
try {
with(binding) {
val packageInfo =
packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA)
packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA)
val installTime = DateUtils.getRelativeTimeSpanString(packageInfo.firstInstallTime)
warningAppInstallDate.text =
getString(R.string.oreo_autofill_warning_publisher_install_time, installTime)
getString(R.string.oreo_autofill_warning_publisher_install_time, installTime)
val appInfo =
packageManager.getApplicationInfo(appPackage, PackageManager.GET_META_DATA)
packageManager.getApplicationInfo(appPackage, PackageManager.GET_META_DATA)
warningAppName.text = "${packageManager.getApplicationLabel(appInfo)}"
val currentHash = computeCertificatesHash(this@AutofillPublisherChangedActivity, appPackage)
warningAppAdvancedInfo.text = getString(
R.string.oreo_autofill_warning_publisher_advanced_info_template,
appPackage,
currentHash
R.string.oreo_autofill_warning_publisher_advanced_info_template,
appPackage,
currentHash
)
}
} catch (exception: Exception) {

View file

@ -52,13 +52,28 @@ import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
import com.zeapo.pwdstore.ui.dialogs.PasswordGeneratorDialogFragment
import com.zeapo.pwdstore.ui.dialogs.XkPasswordGeneratorDialogFragment
import com.zeapo.pwdstore.utils.Otp
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.nio.charset.Charset
import java.util.Date
import kotlinx.android.synthetic.main.decrypt_layout.*
import kotlinx.android.synthetic.main.encrypt_layout.*
import kotlinx.android.synthetic.main.decrypt_layout.crypto_container_decrypt
import kotlinx.android.synthetic.main.decrypt_layout.crypto_copy_otp
import kotlinx.android.synthetic.main.decrypt_layout.crypto_copy_username
import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_show
import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_show_layout
import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_toggle_show
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.launch
import me.msfjarvis.openpgpktx.util.OpenPgpApi
@ -74,6 +89,11 @@ import org.apache.commons.io.FileUtils
import org.apache.commons.io.FilenameUtils
import org.openintents.openpgp.IOpenPgpService2
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 {
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 lastChangedString: CharSequence by lazy {
getLastChangedString(
intent.getLongExtra(
"LAST_CHANGED_TIMESTAMP",
-1L
)
intent.getLongExtra(
"LAST_CHANGED_TIMESTAMP",
-1L
)
)
}
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)
try {
this@PgpActivity.startIntentSenderFromChild(
this@PgpActivity, pi?.intentSender, requestCode,
null, 0, 0, 0
this@PgpActivity, pi?.intentSender, requestCode,
null, 0, 0, 0
)
} catch (e: IntentSender.SendIntentException) {
e(e) { "SendIntentException" }
@ -401,8 +421,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
null
} else {
HoldToShowPasswordTransformation(
crypto_password_toggle_show,
Runnable { crypto_password_show.text = entry.password }
crypto_password_toggle_show,
Runnable { crypto_password_show.text = entry.password }
)
}
@ -455,19 +475,19 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
if (entry.hasTotp()) {
crypto_copy_otp.setOnClickListener {
copyOtpToClipBoard(
Otp.calculateCode(
entry.totpSecret,
Date().time / (1000 * entry.totpPeriod),
entry.totpAlgorithm,
entry.digits)
Otp.calculateCode(
entry.totpSecret,
Date().time / (1000 * entry.totpPeriod),
entry.totpAlgorithm,
entry.digits)
)
}
crypto_otp_show.text =
Otp.calculateCode(
entry.totpSecret,
Date().time / (1000 * entry.totpPeriod),
entry.totpAlgorithm,
entry.digits)
Otp.calculateCode(
entry.totpSecret,
Date().time / (1000 * entry.totpPeriod),
entry.totpAlgorithm,
entry.digits)
} else {
// we only want to calculate and show HOTP if the user requests it
crypto_copy_otp.setOnClickListener {
@ -482,31 +502,31 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
val checkInflater = LayoutInflater.from(this@PgpActivity)
val checkLayout = checkInflater.inflate(R.layout.otp_confirm_layout, null)
val rememberCheck: CheckBox =
checkLayout.findViewById(R.id.hotp_remember_checkbox)
checkLayout.findViewById(R.id.hotp_remember_checkbox)
val dialogBuilder = MaterialAlertDialogBuilder(this@PgpActivity)
dialogBuilder.setView(checkLayout)
dialogBuilder.setMessage(R.string.dialog_update_body)
.setCancelable(false)
.setPositiveButton(R.string.dialog_update_positive) { _, _ ->
run {
calculateAndCommitHotp(entry)
if (rememberCheck.isChecked) {
settings.edit {
putBoolean("hotp_remember_check", true)
putBoolean("hotp_remember_choice", true)
}
}
}
}
.setNegativeButton(R.string.dialog_update_negative) { _, _ ->
run {
calculateHotp(entry)
.setCancelable(false)
.setPositiveButton(R.string.dialog_update_positive) { _, _ ->
run {
calculateAndCommitHotp(entry)
if (rememberCheck.isChecked) {
settings.edit {
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()
updateDialog.setTitle(R.string.dialog_update_title)
updateDialog.show()
@ -612,11 +632,11 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
if (shouldGeneratePassword) {
val directoryStructure =
AutofillPreferences.directoryStructure(applicationContext)
AutofillPreferences.directoryStructure(applicationContext)
val entry = PasswordEntry(content)
returnIntent.putExtra("PASSWORD", entry.password)
val username = PasswordEntry(content).username
?: directoryStructure.getUsernameFor(file)
?: directoryStructure.getUsernameFor(file)
returnIntent.putExtra("USERNAME", username)
}
@ -640,9 +660,9 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
generate_password?.setOnClickListener {
when (settings.getString("pref_key_pwgen_type", KEY_PWGEN_TYPE_CLASSIC)) {
KEY_PWGEN_TYPE_CLASSIC -> PasswordGeneratorDialogFragment()
.show(supportFragmentManager, "generator")
.show(supportFragmentManager, "generator")
KEY_PWGEN_TYPE_XKPASSWD -> XkPasswordGeneratorDialogFragment()
.show(supportFragmentManager, "xkpwgenerator")
.show(supportFragmentManager, "xkpwgenerator")
}
}
@ -716,7 +736,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
RESULT_CODE_SUCCESS -> {
try {
val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)
?: LongArray(0)
?: LongArray(0)
val keys = ids.map { it.toString() }.toSet()
// use Long
@ -777,7 +797,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
@SuppressLint("ClickableViewAccessibility")
private inner class HoldToShowPasswordTransformation constructor(button: Button, private val onToggle: Runnable) :
PasswordTransformationMethod(), View.OnTouchListener {
PasswordTransformationMethod(), View.OnTouchListener {
private var shown = false
init {
@ -856,10 +877,10 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
sendIntent.putExtra(Intent.EXTRA_TEXT, passwordEntry?.password)
sendIntent.type = "text/plain"
startActivity(
Intent.createChooser(
sendIntent,
resources.getText(R.string.send_plaintext_password_to)
)
Intent.createChooser(
sendIntent,
resources.getText(R.string.send_plaintext_password_to)
)
) // 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
*/
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

View file

@ -31,6 +31,7 @@ import java.net.URI
* tasks and makes sense to be held here.
*/
abstract class BaseGitActivity : AppCompatActivity() {
lateinit var protocol: Protocol
lateinit var connectionMode: ConnectionMode
var url: String? = null
@ -180,7 +181,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
}
}
op.executeAfterAuthentication(connectionMode, serverUser,
File("$filesDir/.ssh_key"), identity)
File("$filesDir/.ssh_key"), identity)
} catch (e: Exception) {
e.printStackTrace()
MaterialAlertDialogBuilder(this).setMessage(e.message).show()

View file

@ -7,11 +7,11 @@ package com.zeapo.pwdstore.git
import android.app.Activity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import java.io.File
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.GitCommand
import org.eclipse.jgit.api.PushCommand
import org.eclipse.jgit.api.RebaseCommand
import java.io.File
class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
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()}"
this.commands = listOf(
// abort the rebase
git.rebase().setOperation(RebaseCommand.Operation.ABORT),
// git checkout -b conflict-branch
git.checkout().setCreateBranch(true).setName(branchName),
// push the changes
git.push().setRemote("origin"),
// switch back to master
git.checkout().setName("master")
// abort the rebase
git.rebase().setOperation(RebaseCommand.Operation.ABORT),
// git checkout -b conflict-branch
git.checkout().setCreateBranch(true).setName(branchName),
// push the changes
git.push().setRemote("origin"),
// switch back to master
git.checkout().setName("master")
)
return this
}
@ -42,11 +42,11 @@ class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperatio
val git = Git(repository)
if (!git.repository.repositoryState.isRebasing) {
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
.setMessage("The repository is not rebasing, no need to push to another branch")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
}.show()
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
.setMessage("The repository is not rebasing, no need to push to another branch")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
}.show()
return
}
@ -59,26 +59,26 @@ class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperatio
}
}
GitAsyncTask(callingActivity, true, this, null)
.execute(*this.commands.toTypedArray())
.execute(*this.commands.toTypedArray())
}
override fun onError(errorMessage: String) {
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occurred when checking out another branch operation $errorMessage")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
}.show()
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occurred when checking out another branch operation $errorMessage")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
}.show()
}
override fun onSuccess() {
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
.setMessage("There was a conflict when trying to rebase. " +
"Your local master branch was pushed to another branch named conflicting-master-....\n" +
"Use this branch to resolve conflict on your computer")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
}.show()
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
.setMessage("There was a conflict when trying to rebase. " +
"Your local master branch was pushed to another branch named conflicting-master-....\n" +
"Use this branch to resolve conflict on your computer")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
}.show()
}
}

View file

@ -8,9 +8,9 @@ import android.app.Activity
import android.content.Intent
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import java.io.File
import org.eclipse.jgit.api.CloneCommand
import org.eclipse.jgit.api.Git
import java.io.File
/**
* Creates a new clone operation
@ -28,9 +28,9 @@ class CloneOperation(fileDir: File, callingActivity: Activity) : GitOperation(fi
*/
fun setCommand(uri: String): CloneOperation {
this.command = Git.cloneRepository()
.setCloneAllBranches(true)
.setDirectory(repository?.workTree)
.setURI(uri)
.setCloneAllBranches(true)
.setDirectory(repository?.workTree)
.setURI(uri)
return this
}
@ -67,12 +67,12 @@ class CloneOperation(fileDir: File, callingActivity: Activity) : GitOperation(fi
override fun onError(errorMessage: String) {
super.onError(errorMessage)
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the clone operation, " +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage +
"\nPlease check the FAQ for possible reasons why this error might occur.")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
.show()
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the clone operation, " +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage +
"\nPlease check the FAQ for possible reasons why this error might occur.")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
.show()
}
}

View file

@ -8,9 +8,10 @@ import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import com.zeapo.pwdstore.PasswordStore;
import com.zeapo.pwdstore.R;
import java.lang.ref.WeakReference;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.GitCommand;
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.RemoteRefUpdate;
import java.lang.ref.WeakReference;
public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
private WeakReference<Activity> activityWeakReference;
private boolean refreshListOnEnd;
@ -29,10 +32,10 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
private Intent finishWithResultOnEnd;
public GitAsyncTask(
Activity activity,
boolean refreshListOnEnd,
GitOperation operation,
Intent finishWithResultOnEnd) {
Activity activity,
boolean refreshListOnEnd,
GitOperation operation,
Intent finishWithResultOnEnd) {
this.activityWeakReference = new WeakReference<>(activity);
this.refreshListOnEnd = refreshListOnEnd;
this.operation = operation;
@ -47,7 +50,7 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
protected void onPreExecute() {
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.show();
}
@ -85,13 +88,13 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
case NON_EXISTING:
case NOT_ATTEMPTED:
return activity.getString(R.string.git_push_generic_error)
+ rru.getStatus().name();
+ rru.getStatus().name();
case REJECTED_OTHER_REASON:
if ("non-fast-forward".equals(rru.getMessage())) {
return activity.getString(R.string.git_push_other_error);
} else {
return activity.getString(R.string.git_push_generic_error)
+ rru.getMessage();
+ rru.getMessage();
}
default:
break;

View file

@ -53,9 +53,9 @@ class GitConfigActivity : BaseGitActivity() {
val name = binding.gitUserName.text.toString().trim()
if (!email.matches(Patterns.EMAIL_ADDRESS.toRegex())) {
MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.invalid_email_dialog_text))
.setPositiveButton(getString(R.string.dialog_ok), null)
.show()
.setMessage(getString(R.string.invalid_email_dialog_text))
.setPositiveButton(getString(R.string.dialog_ok), null)
.show()
} else {
settings.edit {
putString("git_config_user_email", email)

View file

@ -25,11 +25,11 @@ import com.zeapo.pwdstore.git.config.SshConfigSessionFactory
import com.zeapo.pwdstore.utils.PasswordRepository
import com.zeapo.pwdstore.utils.getEncryptedPrefs
import com.zeapo.pwdstore.utils.requestInputFocusOnView
import java.io.File
import org.eclipse.jgit.api.GitCommand
import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.transport.SshSessionFactory
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider
import java.io.File
/**
* 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
if (SshSessionFactory.getInstance() is SshApiSessionFactory) {
PreferenceManager.getDefaultSharedPreferences(callingActivity.applicationContext)
.edit { putString("ssh_openkeystore_keyid", null) }
.edit { putString("ssh_openkeystore_keyid", null) }
callingActivity.applicationContext
.getEncryptedPrefs("git_operation")
.edit { remove("ssh_key_local_passphrase") }
.getEncryptedPrefs("git_operation")
.edit { remove("ssh_key_local_passphrase") }
} else if (SshSessionFactory.getInstance() is GitConfigSessionFactory) {
callingActivity.applicationContext
.getEncryptedPrefs("git_operation")
.edit { remove("https_password") }
.getEncryptedPrefs("git_operation")
.edit { remove("https_password") }
}
}

View file

@ -56,17 +56,17 @@ open class GitOperationActivity : BaseGitActivity() {
private fun syncRepository(operation: Int) {
if (serverUser.isEmpty() || serverHostname.isEmpty() || url.isNullOrEmpty())
MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.set_information_dialog_text))
.setPositiveButton(getString(R.string.dialog_positive)) { _, _ ->
val intent = Intent(this, UserPreference::class.java)
startActivityForResult(intent, REQUEST_PULL)
}
.setNegativeButton(getString(R.string.dialog_negative)) { _, _ ->
// do nothing :(
setResult(RESULT_OK)
finish()
}
.show()
.setMessage(getString(R.string.set_information_dialog_text))
.setPositiveButton(getString(R.string.dialog_positive)) { _, _ ->
val intent = Intent(this, UserPreference::class.java)
startActivityForResult(intent, REQUEST_PULL)
}
.setNegativeButton(getString(R.string.dialog_negative)) { _, _ ->
// do nothing :(
setResult(RESULT_OK)
finish()
}
.show()
else {
// check that the remote origin is here, else add it
PasswordRepository.addRemote("origin", url!!, true)

View file

@ -144,27 +144,27 @@ class GitServerConfigActivity : BaseGitActivity() {
val localDirFiles = localDir.listFiles() ?: emptyArray()
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
if (localDir.exists() && localDirFiles.isNotEmpty() &&
!(localDirFiles.size == 1 && localDirFiles[0].name == ".git")) {
!(localDirFiles.size == 1 && localDirFiles[0].name == ".git")) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.dialog_delete_title)
.setMessage(resources.getString(R.string.dialog_delete_msg) + " " + localDir.toString())
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialog, _ ->
try {
localDir.deleteRecursively()
launchGitOperation(REQUEST_CLONE)
} catch (e: IOException) {
// TODO Handle the exception correctly if we are unable to delete the directory...
e.printStackTrace()
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
} finally {
dialog.cancel()
}
}
.setNegativeButton(R.string.dialog_do_not_delete) { dialog, _ ->
.setTitle(R.string.dialog_delete_title)
.setMessage(resources.getString(R.string.dialog_delete_msg) + " " + localDir.toString())
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialog, _ ->
try {
localDir.deleteRecursively()
launchGitOperation(REQUEST_CLONE)
} catch (e: IOException) {
// TODO Handle the exception correctly if we are unable to delete the directory...
e.printStackTrace()
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
} finally {
dialog.cancel()
}
.show()
}
.setNegativeButton(R.string.dialog_do_not_delete) { dialog, _ ->
dialog.cancel()
}
.show()
} else {
try {
// Silently delete & replace the lone .git folder if it exists

View file

@ -8,9 +8,9 @@ import android.app.Activity
import android.content.Intent
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import java.io.File
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.PullCommand
import java.io.File
/**
* Creates a new git operation
@ -27,9 +27,9 @@ class PullOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
*/
fun setCommand(): PullOperation {
this.command = Git(repository)
.pull()
.setRebase(true)
.setRemote("origin")
.pull()
.setRebase(true)
.setRemote("origin")
return this
}
@ -41,12 +41,12 @@ class PullOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
override fun onError(errorMessage: String) {
super.onError(errorMessage)
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the pull operation, " +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage +
"\nPlease check the FAQ for possible reasons why this error might occur.")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
.show()
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the pull operation, " +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage +
"\nPlease check the FAQ for possible reasons why this error might occur.")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
.show()
}
}

View file

@ -8,9 +8,9 @@ import android.app.Activity
import android.content.Intent
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import java.io.File
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.PushCommand
import java.io.File
/**
* Creates a new git operation
@ -27,9 +27,9 @@ class PushOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
*/
fun setCommand(): PushOperation {
this.command = Git(repository)
.push()
.setPushAll()
.setRemote("origin")
.push()
.setPushAll()
.setRemote("origin")
return this
}
@ -42,9 +42,9 @@ class PushOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
// TODO handle the "Nothing to push" case
super.onError(errorMessage)
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage(callingActivity.getString(R.string.jgit_error_push_dialog_text) + errorMessage)
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
.show()
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage(callingActivity.getString(R.string.jgit_error_push_dialog_text) + errorMessage)
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
.show()
}
}

View file

@ -8,11 +8,11 @@ import android.app.Activity
import android.content.Intent
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import java.io.File
import org.eclipse.jgit.api.AddCommand
import org.eclipse.jgit.api.FetchCommand
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.ResetCommand
import java.io.File
/**
* Creates a new git operation
@ -21,6 +21,7 @@ import org.eclipse.jgit.api.ResetCommand
* @param callingActivity the calling activity
*/
class ResetToRemoteOperation(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
private var addCommand: AddCommand? = null
private var fetchCommand: FetchCommand? = null
private var resetCommand: ResetCommand? = null
@ -41,18 +42,18 @@ class ResetToRemoteOperation(fileDir: File, callingActivity: Activity) : GitOper
override fun execute() {
this.fetchCommand?.setCredentialsProvider(this.provider)
GitAsyncTask(callingActivity, false, this, Intent())
.execute(this.addCommand, this.fetchCommand, this.resetCommand)
.execute(this.addCommand, this.fetchCommand, this.resetCommand)
}
override fun onError(errorMessage: String) {
super.onError(errorMessage)
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the sync operation, " +
"\nPlease check the FAQ for possible reasons why this error might occur." +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage)
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
.show()
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the sync operation, " +
"\nPlease check the FAQ for possible reasons why this error might occur." +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage)
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> }
.show()
}
}

View file

@ -8,13 +8,13 @@ import android.app.Activity
import android.content.Intent
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import java.io.File
import org.eclipse.jgit.api.AddCommand
import org.eclipse.jgit.api.CommitCommand
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.PullCommand
import org.eclipse.jgit.api.PushCommand
import org.eclipse.jgit.api.StatusCommand
import java.io.File
/**
* Creates a new git operation
@ -23,6 +23,7 @@ import org.eclipse.jgit.api.StatusCommand
* @param callingActivity the calling activity
*/
class SyncOperation(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) {
private var addCommand: AddCommand? = null
private var statusCommand: StatusCommand? = null
private var commitCommand: CommitCommand? = null
@ -55,12 +56,12 @@ class SyncOperation(fileDir: File, callingActivity: Activity) : GitOperation(fil
override fun onError(errorMessage: String) {
super.onError(errorMessage)
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the sync operation, " +
"\nPlease check the FAQ for possible reasons why this error might occur." +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage)
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
.show()
.setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title))
.setMessage("Error occured during the sync operation, " +
"\nPlease check the FAQ for possible reasons why this error might occur." +
callingActivity.resources.getString(R.string.jgit_error_dialog_text) +
errorMessage)
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() }
.show()
}
}

View file

@ -9,8 +9,10 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.jcraft.jsch.Identity;
import com.jcraft.jsch.JSch;
@ -19,8 +21,7 @@ import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import com.zeapo.pwdstore.R;
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.transport.CredentialItem;
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.util.SshAuthenticationApiUtils;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class SshApiSessionFactory extends GitConfigSessionFactory {
/**
* Intent request code indicating a completed signature that should be posted to an outstanding
@ -57,7 +61,7 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
@NonNull
@Override
protected JSch getJSch(@NonNull final OpenSshConfig.Host hc, @NonNull FS fs)
throws JSchException {
throws JSchException {
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
jsch.addIdentity(identity, null);
@ -70,28 +74,28 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
session.setConfig("PreferredAuthentications", "publickey");
CredentialsProvider provider =
new CredentialsProvider() {
@Override
public boolean isInteractive() {
return false;
}
new CredentialsProvider() {
@Override
public boolean isInteractive() {
return false;
}
@Override
public boolean supports(CredentialItem... items) {
return true;
}
@Override
public boolean supports(CredentialItem... items) {
return true;
}
@Override
public boolean get(URIish uri, CredentialItem... items)
throws UnsupportedCredentialItem {
for (CredentialItem item : items) {
if (item instanceof CredentialItem.Username) {
((CredentialItem.Username) item).setValue(username);
}
@Override
public boolean get(URIish uri, CredentialItem... items)
throws UnsupportedCredentialItem {
for (CredentialItem item : items) {
if (item instanceof CredentialItem.Username) {
((CredentialItem.Username) item).setValue(username);
}
return true;
}
};
return true;
}
};
UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
session.setUserInfo(userInfo);
}
@ -114,14 +118,14 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
* Construct a new IdentityBuilder
*
* @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) {
this.callingActivity = callingActivity;
List<String> providers =
SshAuthenticationApiUtils.getAuthenticationProviderPackageNames(
callingActivity);
SshAuthenticationApiUtils.getAuthenticationProviderPackageNames(
callingActivity);
if (providers.isEmpty())
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));
settings =
PreferenceManager.getDefaultSharedPreferences(
callingActivity.getApplicationContext());
PreferenceManager.getDefaultSharedPreferences(
callingActivity.getApplicationContext());
keyId = settings.getString("ssh_openkeystore_keyid", null);
}
/** Free any resources associated with this IdentityBuilder */
/**
* Free any resources associated with this IdentityBuilder
*/
public void close() {
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.
*
* @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
* @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) {
Intent result = api.executeApi(request.toIntent());
@ -154,13 +160,13 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
switch (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, -1)) {
case SshAuthenticationApi.RESULT_CODE_ERROR:
SshAuthenticationApiError error =
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
// On an OpenKeychain SSH API error, clear out the stored keyid
settings.edit().putString("ssh_openkeystore_keyid", null).apply();
switch (error.getError()) {
// If the problem was just a bad keyid, reset to allow them to choose a
// different one
// If the problem was just a bad keyid, reset to allow them to choose a
// different one
case (SshAuthenticationApiError.NO_SUCH_KEY):
case (SshAuthenticationApiError.NO_AUTH_KEY):
keyId = null;
@ -169,7 +175,7 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
alg = null;
return executeApi(new KeySelectionRequest(), requestCode);
// Other errors are fatal
// Other errors are fatal
default:
throw new RuntimeException(error.getMessage());
}
@ -177,19 +183,19 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
break;
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
PendingIntent pendingIntent =
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
try {
callingActivity.startIntentSenderForResult(
pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0);
pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0);
return null;
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
throw new RuntimeException(
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
}
default:
throw new RuntimeException(
callingActivity.getString(R.string.ssh_api_unknown_error));
callingActivity.getString(R.string.ssh_api_unknown_error));
}
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
* @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) {
// First gate, need to initiate a connection to the service and wait for it to connect.
if (api == null) {
connection.connect(
new SshAuthenticationConnection.OnBound() {
@Override
public void onBound(ISshAuthenticationService sshAgent) {
api = new SshAuthenticationApi(callingActivity, sshAgent);
// We can immediately try the next phase without needing to post
// back
// though onActivityResult
callingActivity.onActivityResult(
requestCode, Activity.RESULT_OK, null);
}
new SshAuthenticationConnection.OnBound() {
@Override
public void onBound(ISshAuthenticationService sshAgent) {
api = new SshAuthenticationApi(callingActivity, sshAgent);
// We can immediately try the next phase without needing to post
// back
// though onActivityResult
callingActivity.onActivityResult(
requestCode, Activity.RESULT_OK, null);
}
@Override
public void onError() {
new MaterialAlertDialogBuilder(callingActivity)
.setMessage(
callingActivity.getString(
R.string.openkeychain_ssh_api_connect_fail))
.show();
}
});
@Override
public void onError() {
new MaterialAlertDialogBuilder(callingActivity)
.setMessage(
callingActivity.getString(
R.string.openkeychain_ssh_api_connect_fail))
.show();
}
});
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 {
private String keyId, description, alg;
private byte[] publicKey;
@ -283,12 +291,12 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
private byte[] signature;
ApiIdentity(
String keyId,
String description,
byte[] publicKey,
String alg,
Activity callingActivity,
SshAuthenticationApi api) {
String keyId,
String description,
byte[] publicKey,
String alg,
Activity callingActivity,
SshAuthenticationApi api) {
this.keyId = keyId;
this.description = description;
this.publicKey = publicKey;
@ -313,35 +321,35 @@ public class SshApiSessionFactory extends GitConfigSessionFactory {
*
* @param result The result intent to handle
* @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) {
switch (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, -1)) {
case SshAuthenticationApi.RESULT_CODE_ERROR:
SshAuthenticationApiError error =
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
result.getParcelableExtra(SshAuthenticationApi.EXTRA_ERROR);
throw new RuntimeException(error.getMessage());
case SshAuthenticationApi.RESULT_CODE_SUCCESS:
return result.getByteArrayExtra(SshAuthenticationApi.EXTRA_SIGNATURE);
case SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
PendingIntent pendingIntent =
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT);
try {
latch = new CountDownLatch(1);
callingActivity.startIntentSenderForResult(
pendingIntent.getIntentSender(), POST_SIGNATURE, null, 0, 0, 0);
pendingIntent.getIntentSender(), POST_SIGNATURE, null, 0, 0, 0);
return null;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
callingActivity.getString(R.string.ssh_api_pending_intent_failed));
}
default:
if (result.hasExtra(SshAuthenticationApi.EXTRA_CHALLENGE))
return handleSignResult(api.executeApi(result));
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
public void clear() {}
public void clear() {
}
}
}

View file

@ -11,46 +11,46 @@ internal object Phonemes {
private const val NOT_FIRST = 0x0008
private val elements = arrayOf(
Element("a", VOWEL),
Element("ae", VOWEL or DIPTHONG),
Element("ah", VOWEL or DIPTHONG),
Element("ai", VOWEL or DIPTHONG),
Element("b", CONSONANT),
Element("c", CONSONANT),
Element("ch", CONSONANT or DIPTHONG),
Element("d", CONSONANT),
Element("e", VOWEL),
Element("ee", VOWEL or DIPTHONG),
Element("ei", VOWEL or DIPTHONG),
Element("f", CONSONANT),
Element("g", CONSONANT),
Element("gh", CONSONANT or DIPTHONG or NOT_FIRST),
Element("h", CONSONANT),
Element("i", VOWEL),
Element("ie", VOWEL or DIPTHONG),
Element("j", CONSONANT),
Element("k", CONSONANT),
Element("l", CONSONANT),
Element("m", CONSONANT),
Element("n", CONSONANT),
Element("ng", CONSONANT or DIPTHONG or NOT_FIRST),
Element("o", VOWEL),
Element("oh", VOWEL or DIPTHONG),
Element("oo", VOWEL or DIPTHONG),
Element("p", CONSONANT),
Element("ph", CONSONANT or DIPTHONG),
Element("qu", CONSONANT or DIPTHONG),
Element("r", CONSONANT),
Element("s", CONSONANT),
Element("sh", CONSONANT or DIPTHONG),
Element("t", CONSONANT),
Element("th", CONSONANT or DIPTHONG),
Element("u", VOWEL),
Element("v", CONSONANT),
Element("w", CONSONANT),
Element("x", CONSONANT),
Element("y", CONSONANT),
Element("z", CONSONANT)
Element("a", VOWEL),
Element("ae", VOWEL or DIPTHONG),
Element("ah", VOWEL or DIPTHONG),
Element("ai", VOWEL or DIPTHONG),
Element("b", CONSONANT),
Element("c", CONSONANT),
Element("ch", CONSONANT or DIPTHONG),
Element("d", CONSONANT),
Element("e", VOWEL),
Element("ee", VOWEL or DIPTHONG),
Element("ei", VOWEL or DIPTHONG),
Element("f", CONSONANT),
Element("g", CONSONANT),
Element("gh", CONSONANT or DIPTHONG or NOT_FIRST),
Element("h", CONSONANT),
Element("i", VOWEL),
Element("ie", VOWEL or DIPTHONG),
Element("j", CONSONANT),
Element("k", CONSONANT),
Element("l", CONSONANT),
Element("m", CONSONANT),
Element("n", CONSONANT),
Element("ng", CONSONANT or DIPTHONG or NOT_FIRST),
Element("o", VOWEL),
Element("oh", VOWEL or DIPTHONG),
Element("oo", VOWEL or DIPTHONG),
Element("p", CONSONANT),
Element("ph", CONSONANT or DIPTHONG),
Element("qu", CONSONANT or DIPTHONG),
Element("r", CONSONANT),
Element("s", CONSONANT),
Element("sh", CONSONANT or DIPTHONG),
Element("t", CONSONANT),
Element("th", CONSONANT or DIPTHONG),
Element("u", VOWEL),
Element("v", CONSONANT),
Element("w", CONSONANT),
Element("x", CONSONANT),
Element("y", CONSONANT),
Element("z", CONSONANT)
)
private val NUM_ELEMENTS = elements.size
@ -110,7 +110,7 @@ internal object Phonemes {
}
// Don't allow VOWEL followed a Vowel/Dipthong pair
if (prev and VOWEL > 0 && flags and VOWEL > 0 &&
flags and DIPTHONG > 0
flags and DIPTHONG > 0
) {
continue
}
@ -125,7 +125,7 @@ internal object Phonemes {
// Handle UPPERS
if (pwFlags and PasswordGenerator.UPPERS > 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
password = password.substring(0, index) + str.toUpperCase()
featureFlags = featureFlags and PasswordGenerator.UPPERS.inv()
@ -169,7 +169,7 @@ internal object Phonemes {
cha = Character.forDigit(RandomNumberGenerator.number(10), 10)
character = cha.toString()
} while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
PasswordGenerator.AMBIGUOUS_STR.contains(character))
PasswordGenerator.AMBIGUOUS_STR.contains(character))
password += character
curSize++
@ -192,7 +192,7 @@ internal object Phonemes {
cha = PasswordGenerator.SYMBOLS_STR.toCharArray()[num]
character = cha.toString()
} while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
PasswordGenerator.AMBIGUOUS_STR.contains(character))
PasswordGenerator.AMBIGUOUS_STR.contains(character))
password += character
curSize++
@ -205,7 +205,7 @@ internal object Phonemes {
VOWEL
} else {
if (prev and VOWEL > 0 || flags and DIPTHONG > 0 ||
RandomNumberGenerator.number(10) > 3
RandomNumberGenerator.number(10) > 3
) {
CONSONANT
} else {

View file

@ -53,7 +53,7 @@ internal object RandomPasswordGenerator {
cha = bank.toCharArray()[num]
character = cha.toString()
if (pwFlags and PasswordGenerator.AMBIGUOUS > 0 &&
PasswordGenerator.AMBIGUOUS_STR.contains(character)) {
PasswordGenerator.AMBIGUOUS_STR.contains(character)) {
continue
}
if (pwFlags and PasswordGenerator.NO_VOWELS > 0 && PasswordGenerator.VOWELS_STR.contains(character)) {

View file

@ -127,7 +127,8 @@ class PasswordBuilder(ctx: Context) {
CapsType.TitleCase -> {
s = capitalize(s)
}
CapsType.lowercase, CapsType.As_iS -> {}
CapsType.lowercase, CapsType.As_iS -> {
}
}
}
password.append(s)

View file

@ -16,9 +16,9 @@ import androidx.core.content.getSystemService
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
import org.apache.commons.io.FileUtils
import java.io.File
import java.nio.charset.StandardCharsets
import org.apache.commons.io.FileUtils
class ShowSshKeyFragment : DialogFragment() {
@ -41,7 +41,8 @@ class ShowSshKeyFragment : DialogFragment() {
ad.setOnShowListener {
val b = ad.getButton(AlertDialog.BUTTON_NEUTRAL)
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())
clipboard.setPrimaryClip(clip)
}

View file

@ -15,9 +15,9 @@ class SshKeyGenActivity : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(android.R.id.content, SshKeyGenFragment())
.commit()
.beginTransaction()
.replace(android.R.id.content, SshKeyGenFragment())
.commit()
}
}

View file

@ -19,11 +19,11 @@ import com.jcraft.jsch.JSch
import com.jcraft.jsch.KeyPair
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.databinding.FragmentSshKeygenBinding
import java.io.File
import java.io.FileOutputStream
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
class SshKeyGenFragment : Fragment() {
@ -96,12 +96,12 @@ class SshKeyGenFragment : Fragment() {
prefs.edit { putBoolean("use_generated_key", true) }
} else {
MaterialAlertDialogBuilder(activity)
.setTitle(activity.getString(R.string.error_generate_ssh_key))
.setMessage(activity.getString(R.string.ssh_key_error_dialog_text) + e.message)
.setPositiveButton(activity.getString(R.string.dialog_ok)) { _, _ ->
requireActivity().finish()
}
.show()
.setTitle(activity.getString(R.string.error_generate_ssh_key))
.setMessage(activity.getString(R.string.ssh_key_error_dialog_text) + e.message)
.setPositiveButton(activity.getString(R.string.dialog_ok)) { _, _ ->
requireActivity().finish()
}
.show()
}
hideKeyboard()
}

View file

@ -80,6 +80,7 @@ open class PasswordItemRecyclerAdapter :
class PasswordItemDetailsLookup(private val recyclerView: RecyclerView) :
ItemDetailsLookup<String>() {
override fun getItemDetails(event: MotionEvent): ItemDetails<String>? {
val view = recyclerView.findChildViewUnder(event.x, event.y) ?: return null
return (recyclerView.getChildViewHolder(view) as PasswordItemViewHolder).itemDetails

View file

@ -23,6 +23,7 @@ import com.zeapo.pwdstore.pwgen.PasswordGenerator.setPrefs
/** A placeholder fragment containing a simple view. */
class PasswordGeneratorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
val callingActivity = requireActivity()
@ -31,7 +32,7 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
val monoTypeface = Typeface.createFromAsset(callingActivity.assets, "fonts/sourcecodepro.ttf")
builder.setView(view)
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.symbols)?.isChecked = prefs.getBoolean("y", false)

View file

@ -117,13 +117,13 @@ class XkPasswordGeneratorDialogFragment : DialogFragment() {
private fun makeAndSetPassword(passwordText: AppCompatTextView) {
try {
passwordText.text = PasswordBuilder(requireContext())
.setNumberOfWords(Integer.valueOf(editNumWords.text.toString()))
.setMinimumWordLength(DEFAULT_MIN_WORD_LENGTH)
.setMaximumWordLength(DEFAULT_MAX_WORD_LENGTH)
.setSeparator(editSeparator.text.toString())
.appendNumbers(if (cbNumbers.isChecked) Integer.parseInt(spinnerNumbersCount.selectedItem as String) else 0)
.appendSymbols(if (cbSymbols.isChecked) Integer.parseInt(spinnerSymbolsCount.selectedItem as String) else 0)
.setCapitalization(CapsType.valueOf(spinnerCapsType.selectedItem.toString())).create()
.setNumberOfWords(Integer.valueOf(editNumWords.text.toString()))
.setMinimumWordLength(DEFAULT_MIN_WORD_LENGTH)
.setMaximumWordLength(DEFAULT_MAX_WORD_LENGTH)
.setSeparator(editSeparator.text.toString())
.appendNumbers(if (cbNumbers.isChecked) Integer.parseInt(spinnerNumbersCount.selectedItem as String) else 0)
.appendSymbols(if (cbSymbols.isChecked) Integer.parseInt(spinnerSymbolsCount.selectedItem as String) else 0)
.setCapitalization(CapsType.valueOf(spinnerCapsType.selectedItem.toString())).create()
} catch (e: PasswordGenerator.PasswordGeneratorExeption) {
Toast.makeText(requireActivity(), e.message, Toast.LENGTH_SHORT).show()
tag("xkpw").e(e, "failure generating xkpasswd")

View file

@ -61,11 +61,11 @@ object BiometricAuthenticator {
}
val biometricPrompt = BiometricPrompt(activity, { handler.post(it) }, authCallback)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(activity.getString(dialogTitleRes))
.setDeviceCredentialAllowed(true)
.build()
.setTitle(activity.getString(dialogTitleRes))
.setDeviceCredentialAllowed(true)
.build()
if (BiometricManager.from(activity).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS ||
activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true) {
activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true) {
biometricPrompt.authenticate(promptInfo)
} else {
callback(Result.HardwareUnavailableOrDisabled)

View file

@ -36,11 +36,11 @@ fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
return EncryptedSharedPreferences.create(
fileName,
masterKeyAlias,
this,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
fileName,
masterKeyAlias,
this,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
@ -55,7 +55,7 @@ fun <T : View> AlertDialog.requestInputFocusOnView(@IdRes id: Int) {
setOnFocusChangeListener { v, _ ->
v.post {
context.getSystemService<InputMethodManager>()
?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
}
}
requestFocus()

View file

@ -4,24 +4,28 @@
*/
package com.zeapo.pwdstore.utils;
import org.apache.commons.codec.binary.Base32;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base32;
import timber.log.Timber;
public class Otp {
private static final Base32 BASE_32 = new Base32();
private Otp() {}
private Otp() {
}
public static String calculateCode(
String secret, long counter, String algorithm, String digits) {
String secret, long counter, String algorithm, String digits) {
String[] steam = {
"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"

View file

@ -14,14 +14,15 @@ data class PasswordItem(
val file: File,
val rootDir: File
) : Comparable<PasswordItem> {
val fullPathToParent = file.absolutePath
.replace(rootDir.absolutePath, "")
.replace(file.name, "")
.replace(rootDir.absolutePath, "")
.replace(file.name, "")
val longName = PgpActivity.getLongName(
fullPathToParent,
rootDir.absolutePath,
toString())
fullPathToParent,
rootDir.absolutePath,
toString())
override fun equals(other: Any?): Boolean {
return (other is PasswordItem) && (other.file == file)

View file

@ -8,9 +8,6 @@ import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
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.eclipse.jgit.api.Git
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.RemoteConfig
import org.eclipse.jgit.transport.URIish
import java.io.File
import java.io.FileFilter
import java.util.Comparator
open class PasswordRepository protected constructor() {
@ -26,7 +26,7 @@ open class PasswordRepository protected constructor() {
FOLDER_FIRST(Comparator { p1: PasswordItem, p2: PasswordItem ->
(p1.type + p1.name)
.compareTo(p2.type + p2.name, ignoreCase = true)
.compareTo(p2.type + p2.name, ignoreCase = true)
}),
INDEPENDENT(Comparator { p1: PasswordItem, p2: PasswordItem ->
@ -62,8 +62,8 @@ open class PasswordRepository protected constructor() {
val builder = FileRepositoryBuilder()
try {
repository = builder.setGitDir(localDir)
.readEnvironment()
.build()
.readEnvironment()
.build()
} catch (e: Exception) {
e.printStackTrace()
return null
@ -81,8 +81,8 @@ open class PasswordRepository protected constructor() {
if (repository != null) {
// Check if remote exists
return repository!!.config.getSubsections("remote").isNotEmpty() &&
repository!!.objectDatabase.exists() &&
repository!!.allRefs.isNotEmpty()
repository!!.objectDatabase.exists() &&
repository!!.allRefs.isNotEmpty()
}
return false
}
@ -196,9 +196,9 @@ open class PasswordRepository protected constructor() {
if (path == null || !path.exists()) return ArrayList()
val directories = (path.listFiles(FileFilterUtils.directoryFileFilter() as FileFilter)
?: emptyArray()).toList()
?: emptyArray()).toList()
val files = (path.listFiles(FileFilterUtils.suffixFileFilter(".gpg") as FileFilter)
?: emptyArray()).toList()
?: emptyArray()).toList()
val items = ArrayList<File>()
items.addAll(directories)

View file

@ -1,5 +1,5 @@
<?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
android:duration="300"
android:fromXScale="1.0"

View file

@ -1,5 +1,5 @@
<?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
android:duration="300"
android:fromXScale="0"

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false"
android:color="#00FFFFFF" />
<item android:color="#00FFFFFF" android:state_checked="false" />
<item android:color="@color/button_color" />
</selector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnPrimary"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorOnPrimary">
<path
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:viewportHeight="24">
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnPrimary"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorOnPrimary">
<path
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:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z" />
</vector>

View file

@ -3,23 +3,24 @@
android:height="108dp"
android:viewportWidth="110.34687"
android:viewportHeight="110.34687">
<group android:translateX="24.828047"
android:translateY="24.828047">
<path
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:strokeWidth="5.349"
android:fillColor="#00000000"
android:strokeColor="#013e5b"/>
<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:fillColor="#00c7a0"/>
<path
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"
android:strokeWidth=".35344"
android:fillColor="#fff"/>
<path
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"
android:fillColor="#3bdbbc"/>
<group
android:translateX="24.828047"
android:translateY="24.828047">
<path
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:strokeWidth="5.349"
android:strokeColor="#013e5b" />
<path
android:fillColor="#00c7a0"
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="#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"
android:strokeWidth=".35344" />
<path
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>
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorOnPrimary"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?colorOnPrimary">
<path
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:viewportHeight="24">
<path
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" />
</vector>

View file

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
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>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
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>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
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"/>
<path
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" />
</vector>

View file

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
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>

View file

@ -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:
https://stackoverflow.com/a/36424426/297261
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector>
<item android:drawable="@color/list_multiselect_background" android:state_selected="true" />
<item android:drawable="@android:color/transparent"/>
</selector>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
<item>
<selector>
<item
android:drawable="@color/list_multiselect_background"
android:state_selected="true" />
<item android:drawable="@android:color/transparent" />
</selector>
</item>
<item android:drawable="?android:attr/selectableItemBackground" />
</layer-list>

View file

@ -3,44 +3,44 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:padding="@dimen/activity_horizontal_margin"
tools:context="com.zeapo.pwdstore.git.GitOperationActivity"
android:background="?android:attr/windowBackground">
tools:context="com.zeapo.pwdstore.git.GitOperationActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
style="@style/TextAppearance.MaterialComponents.Headline5"
android:id="@+id/server_label"
android:textStyle="bold"
android:textSize="24sp"
android:text="@string/server_name"
style="@style/TextAppearance.MaterialComponents.Headline5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/server_name"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/TextAppearance.MaterialComponents.Headline6"
android:id="@+id/label_server_protocol"
style="@style/TextAppearance.MaterialComponents.Headline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/server_protocol"
android:layout_margin="8dp"
app:layout_constraintTop_toBottomOf="@id/server_label"
app:layout_constraintStart_toStartOf="parent" />
android:text="@string/server_protocol"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/server_label" />
<com.google.android.material.button.MaterialButtonToggleGroup
style="@style/TextAppearance.MaterialComponents.Headline1"
android:id="@+id/clone_protocol_group"
style="@style/TextAppearance.MaterialComponents.Headline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintTop_toBottomOf="@id/label_server_protocol"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_server_protocol"
app:selectionRequired="true"
app:singleSelection="true">
@ -61,11 +61,12 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/server_user_layout"
android:hint="@string/server_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/server_user"
app:layout_constraintTop_toBottomOf="@id/clone_protocol_group">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/server_user"
android:layout_width="match_parent"
@ -79,14 +80,14 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
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_constraintEnd_toStartOf="@id/label_server_port">
app:layout_constraintTop_toBottomOf="@id/server_user_layout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/server_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/server_url"
android:inputType="textWebEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
@ -97,10 +98,10 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/server_port_hint"
app:layout_constraintStart_toEndOf="@id/label_server_url"
app:layout_constraintTop_toBottomOf="@id/server_user_layout"
app:layout_constraintDimensionRatio="1:0.8"
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
android:id="@+id/server_port"
@ -123,19 +124,19 @@
android:id="@+id/server_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textWebEmailAddress"/>
android:inputType="textWebEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatTextView
style="@style/TextAppearance.MaterialComponents.Headline6"
android:id="@+id/label_connection_mode"
style="@style/TextAppearance.MaterialComponents.Headline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/connection_mode"
android:layout_margin="8dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="@string/connection_mode"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_server_path" />
@ -144,8 +145,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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
android:id="@+id/connection_mode_ssh_key"
@ -179,11 +180,11 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/save_button"
android:text="@string/crypto_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/connection_mode_group"
app:layout_constraintEnd_toEndOf="parent" />
android:text="@string/crypto_save"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/connection_mode_group" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View file

@ -3,8 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_horizontal_margin"
android:background="?android:attr/windowBackground"
android:padding="@dimen/activity_horizontal_margin"
tools:context="com.zeapo.pwdstore.git.GitConfigActivity"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="81dp">
@ -15,8 +15,8 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/git_user_name_hint"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteY="64dp">
<com.google.android.material.textfield.TextInputEditText
@ -33,8 +33,8 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
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
android:id="@+id/git_user_email"
@ -50,20 +50,20 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
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
style="@style/TextAppearance.MaterialComponents.Headline5"
android:textStyle="bold"
android:textSize="24sp"
android:id="@+id/git_tools_title"
style="@style/TextAppearance.MaterialComponents.Headline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/hackish_tools"
app:layout_constraintTop_toBottomOf="@id/save_button"
app:layout_constraintStart_toStartOf="parent" />
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/save_button" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/commit_hash_label"
@ -71,8 +71,8 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
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
android:id="@+id/git_commit_hash"
@ -80,9 +80,9 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/git_tools_title"
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
android:id="@+id/git_abort_rebase"

View file

@ -42,15 +42,16 @@
android:inputType="text"
tools:text="example.com" />
</com.google.android.material.textfield.TextInputLayout>
<ViewSwitcher
android:id="@+id/rvPasswordSwitcher"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/activity_vertical_margin"
app:layout_constraintBottom_toTopOf="@id/strictDomainSearch"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/searchLayout"
android:layout_height="0dp">
app:layout_constraintTop_toBottomOf="@id/searchLayout">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvPassword"
@ -84,7 +85,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rvPasswordSwitcher"
app:layout_constraintVertical_bias="1.0"
tools:text="Phishing-resistant search"/>
tools:text="Phishing-resistant search" />
<Switch
android:id="@+id/shouldMatch"

View file

@ -2,13 +2,13 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PasswordStore"
android:orientation="vertical">
android:orientation="vertical"
tools:context=".PasswordStore">
<LinearLayout
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
android:orientation="vertical" />
</LinearLayout>

View file

@ -7,10 +7,10 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp"
android:paddingLeft="24dp"
android:paddingTop="20dp"
android:paddingRight="24dp"
android:paddingTop="20dp">
android:paddingBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
@ -21,19 +21,19 @@
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
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
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
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
android:layout_width="wrap_content"
@ -44,10 +44,10 @@
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="114dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:src="@drawable/autofill_ins_3"
android:contentDescription="@string/autofill_ins_3_hint" />
android:layout_marginBottom="8dp"
android:contentDescription="@string/autofill_ins_3_hint"
android:src="@drawable/autofill_ins_3" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"

View file

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/autofill_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
tools:listitem="@layout/autofill_row_layout"
tools:itemCount="20"/>
tools:itemCount="20"
tools:listitem="@layout/autofill_row_layout" />
<ProgressBar
android:id="@+id/progress_bar"
@ -24,16 +24,16 @@
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:src="@drawable/ic_add_white_48dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
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:pressedTranslationZ="12dp"
app:backgroundTint="?attr/colorSecondary"
app:rippleColor="?attr/colorSecondary"
app:borderWidth="0dp"
android:layout_margin="@dimen/fab_compat_margin"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"/>
app:rippleColor="?attr/colorSecondary" />
</RelativeLayout>

View file

@ -1,37 +1,37 @@
<?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:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
xmlns:android="http://schemas.android.com/apk/res/android">
android:paddingRight="@dimen/activity_horizontal_margin">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/app_icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/app_icon_hint"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/app_icon"
android:layout_width="48dp"
android:layout_height="48dp"
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_height="match_parent"
android:layout_marginStart="8dp"
android:gravity="center_vertical"
android:orientation="vertical" >
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/secondary_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColor" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/secondary_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColor" />
</LinearLayout>
</LinearLayout>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/windowBackground"
android:orientation="vertical"
tools:context="com.zeapo.pwdstore.crypto.PgpActivity">
@ -58,8 +58,8 @@
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/divider"
app:layout_constraintTop_toBottomOf="@id/crypto_password_last_changed"
tools:ignore="ContentDescription" />
@ -70,8 +70,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
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
android:id="@+id/crypto_password_show_label"
@ -79,9 +79,9 @@
android:layout_height="wrap_content"
android:text="@string/password"
android:textColor="?android:attr/textColor"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textStyle="bold" />
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/crypto_password_show"
@ -90,16 +90,16 @@
android:layout_gravity="fill"
android:gravity="bottom"
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"
android:typeface="monospace" />
app:layout_constraintStart_toEndOf="@id/crypto_password_show_label" />
<com.google.android.material.button.MaterialButton
android:id="@+id/crypto_password_toggle_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/show_password"
android:layout_marginTop="8dp"
android:text="@string/show_password"
app:layout_constraintTop_toBottomOf="@id/crypto_password_show_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
@ -116,15 +116,15 @@
android:id="@+id/crypto_copy_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:background="?android:attr/windowBackground"
android:contentDescription="@string/copy_username"
android:src="@drawable/ic_content_copy"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible"/>
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/crypto_username_show_label"
@ -139,84 +139,84 @@
android:visibility="invisible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible"/>
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/crypto_username_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/crypto_username_show_label"
android:layout_alignParentStart="true"
android:layout_toStartOf="@id/crypto_copy_username"
android:textColor="?android:attr/textColor"
android:textIsSelectable="true"
android:typeface="monospace"
android:visibility="invisible"
app:layout_constraintTop_toBottomOf="@id/crypto_username_show_label"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"/>
app:layout_constraintTop_toBottomOf="@id/crypto_username_show_label"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/crypto_copy_otp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_below="@id/crypto_username_show"
android:layout_alignParentEnd="true"
android:background="?android:attr/windowBackground"
android:contentDescription="@string/copy_otp"
android:src="@drawable/ic_content_copy"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="@id/crypto_otp_show_label"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible"/>
app:layout_constraintTop_toTopOf="@id/crypto_otp_show_label"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/crypto_otp_show_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/crypto_username_show"
android:layout_alignParentStart="true"
android:layout_toStartOf="@id/crypto_copy_otp"
android:text="@string/otp"
android:textColor="?android:attr/textColor"
app:layout_constraintTop_toBottomOf="@id/crypto_username_show"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
android:textStyle="bold" />
app:layout_constraintTop_toBottomOf="@id/crypto_username_show" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/crypto_otp_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/crypto_otp_show_label"
android:layout_alignParentStart="true"
android:layout_toStartOf="@id/crypto_copy_otp"
android:textColor="?android:attr/textColor"
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
android:id="@+id/crypto_extra_show_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/crypto_otp_show"
android:layout_alignParentStart="true"
android:text="@string/extra_content"
android:textColor="?android:attr/textColor"
app:layout_constraintTop_toBottomOf="@id/crypto_otp_show"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
android:textStyle="bold" />
app:layout_constraintTop_toBottomOf="@id/crypto_otp_show" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/crypto_extra_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/crypto_extra_show_label"
android:layout_alignParentStart="true"
android:textColor="?android:attr/textColor"
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
android:id="@+id/crypto_extra_toggle_show"
@ -225,13 +225,13 @@
android:layout_height="wrap_content"
android:layout_below="@id/crypto_extra_show"
android:layout_alignParentStart="true"
android:backgroundTint="?attr/colorSecondary"
android:checked="false"
android:paddingTop="8dp"
android:textColor="?android:attr/windowBackground"
android:textOff="@string/show_extra"
android:textOn="@string/hide_extra"
app:layout_constraintTop_toBottomOf="@id/crypto_extra_show"
android:backgroundTint="?attr/colorSecondary"/>
app:layout_constraintTop_toBottomOf="@id/crypto_extra_show" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/windowBackground"
android:orientation="vertical"
android:padding="@dimen/activity_horizontal_margin"
@ -14,8 +14,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:textColor="?android:attr/textColor"
android:enabled="false"
android:textColor="?android:attr/textColor"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -23,17 +23,18 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/name_input_layout"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
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
android:id="@+id/crypto_password_file_edit"
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
@ -43,13 +44,14 @@
android:layout_margin="8dp"
android:hint="@string/crypto_pass_label"
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
android:id="@+id/crypto_password_edit"
android:inputType="textVisiblePassword"
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.button.MaterialButton
@ -58,8 +60,8 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
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
android:id="@+id/extra_input_layout"
@ -67,14 +69,14 @@
android:layout_height="wrap_content"
android:layout_margin="8dp"
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
android:id="@+id/crypto_extra_edit"
android:inputType="textMultiLine|textVisiblePassword"
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>

View file

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@ -17,7 +15,7 @@
android:id="@+id/folder_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textVisiblePassword"/>
android:inputType="textNoSuggestions|textVisiblePassword" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View file

@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="20dp"
android:paddingLeft="24dp"
android:paddingTop="20dp"
android:paddingRight="24dp"
android:paddingTop="20dp">
android:paddingBottom="20dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="URL">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/webURL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"/>
android:inputType="textUri" />
</com.google.android.material.textfield.TextInputLayout>
<RadioGroup
@ -56,14 +56,14 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"/>
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/matchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+"
android:id="@+id/matchButton"
android:layout_gravity="center_horizontal"
android:text="+"
tools:ignore="HardcodedText" />
<RadioButton
@ -72,7 +72,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:checked="false"
android:text="@string/autofill_apps_never"/>
android:text="@string/autofill_apps_never" />
</RadioGroup>

View file

@ -7,10 +7,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="20dp"
android:paddingRight="24dp"
android:paddingBottom="20dp"
tools:context=".MainActivityFragment">
<androidx.appcompat.widget.AppCompatTextView

View file

@ -7,10 +7,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp"
android:paddingLeft="24dp"
android:paddingTop="20dp"
android:paddingRight="24dp"
android:paddingTop="20dp">
android:paddingBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/public_key"

View file

@ -18,18 +18,20 @@
android:text="@string/ssh_keygen_length" />
<com.google.android.material.button.MaterialButtonToggleGroup
style="@style/TextAppearance.MaterialComponents.Headline1"
android:id="@+id/key_length_group"
style="@style/TextAppearance.MaterialComponents.Headline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/key_length_2048"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/key_length_2048" />
<com.google.android.material.button.MaterialButton
android:id="@+id/key_length_4096"
style="?attr/materialButtonOutlinedStyle"
@ -49,8 +51,8 @@
android:id="@+id/passphrase"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:fontFamily="@font/sourcecodepro"
android:importantForAccessibility="no"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>

View file

@ -1,8 +1,7 @@
<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_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?attr/colorPrimary"
android:orientation="vertical">
@ -11,37 +10,37 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher"
android:contentDescription="@string/app_icon_hint"
app:layout_constraintTop_toTopOf="parent"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/app_name"
android:layout_width="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_centerHorizontal="true"
android:text="@string/app_name"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/white"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@+id/app_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintTop_toBottomOf="@+id/app_icon" />
<com.google.android.material.button.MaterialButton
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="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_alignParentEnd="true"
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_constraintTop_toTopOf="parent" />
@ -49,13 +48,13 @@
android:id="@+id/use_local_directory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:onClick="createNewRepository"
android:text="@string/initialize"
android:textSize="12sp"
android:layout_marginTop="48dp"
app:layout_constraintTop_toBottomOf="@id/app_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintTop_toBottomOf="@id/app_name" />
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
@ -63,8 +62,8 @@
android:onClick="cloneExistingRepository"
android:text="@string/clone"
android:textSize="12sp"
app:layout_constraintTop_toBottomOf="@id/use_local_directory"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintTop_toBottomOf="@id/use_local_directory" />
</androidx.constraintlayout.widget.ConstraintLayout>

Some files were not shown because too many files have changed in this diff Show more