From 9eab59dcbeb9ebc9ca92d582a2feb34870869f20 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 8 Mar 2021 09:48:56 +0100 Subject: [PATCH 01/10] fix broken steam support --- src/keepass2android/Totp/TrayTotpPluginAdapter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android/Totp/TrayTotpPluginAdapter.cs b/src/keepass2android/Totp/TrayTotpPluginAdapter.cs index ee18beeb..4db3fd2b 100644 --- a/src/keepass2android/Totp/TrayTotpPluginAdapter.cs +++ b/src/keepass2android/Totp/TrayTotpPluginAdapter.cs @@ -117,6 +117,8 @@ namespace PluginTOTP string[] Settings = SettingsGet(entryFields); res.Duration = Settings[0]; res.Length = Settings[1]; + if (res.Length == "S") + res.Encoder = TotpData.EncoderSteam; if (ValidUrl) { NoTimeCorrection = true; From 7037fbfe946c729238f523c40397876cc7aa6803 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 8 Mar 2021 09:49:21 +0100 Subject: [PATCH 02/10] fix URL has two "Open URL" context menu entries --- src/keepass2android/EntryActivity.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/keepass2android/EntryActivity.cs b/src/keepass2android/EntryActivity.cs index 4cf27862..8f067424 100644 --- a/src/keepass2android/EntryActivity.cs +++ b/src/keepass2android/EntryActivity.cs @@ -888,9 +888,10 @@ namespace keepass2android popupItems.Add(new CopyToClipboardPopupMenuIcon(this, _stringViews[fieldKey])); if (isProtected) popupItems.Add(new ToggleVisibilityPopupMenuItem(this)); - if (_stringViews[fieldKey].Text.StartsWith(KeePass.AndroidAppScheme) + if (fieldKey != PwDefs.UrlField //url already has a go-to-url menu + && (_stringViews[fieldKey].Text.StartsWith(KeePass.AndroidAppScheme) || _stringViews[fieldKey].Text.StartsWith("http://") - || _stringViews[fieldKey].Text.StartsWith("https://")) + || _stringViews[fieldKey].Text.StartsWith("https://"))) { popupItems.Add(new GotoUrlMenuItem(this, fieldKey)); } From 92ffe596ce2714fb82e69c33386c37d45b06bb0a Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 8 Mar 2021 09:49:48 +0100 Subject: [PATCH 03/10] additional logging for keyboard issue --- src/java/KP2ASoftkeyboard_AS/.idea/gradle.xml | 5 ++++- .../main/java/keepass2android/softkeyboard/KP2AKeyboard.java | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/java/KP2ASoftkeyboard_AS/.idea/gradle.xml b/src/java/KP2ASoftkeyboard_AS/.idea/gradle.xml index 92c29613..c1831971 100644 --- a/src/java/KP2ASoftkeyboard_AS/.idea/gradle.xml +++ b/src/java/KP2ASoftkeyboard_AS/.idea/gradle.xml @@ -1,11 +1,14 @@ + diff --git a/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java b/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java index 2caa74b4..0443c488 100644 --- a/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java +++ b/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/KP2AKeyboard.java @@ -627,6 +627,10 @@ public class KP2AKeyboard extends InputMethodService updateShowKp2aMode(); Log.d("KP2AK", "updateKeyboardMode -> setKM"); + + Log.d("KP2AK", "variation = " + variation); + Log.d("KP2AK", "input type = " + attribute.inputType); + if ((mShowKp2aKeyboard) && (mKp2aEnableSimpleKeyboard)) { mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_KP2A, attribute.imeOptions); From 09537689cfe017a1f94572d9bb62124426263b49 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 8 Mar 2021 09:50:09 +0100 Subject: [PATCH 04/10] additional logging for https://github.com/PhilippC/keepass2android/issues/1257 --- .../java/keepass2android/javafilestorage/PCloudFileStorage.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/PCloudFileStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/PCloudFileStorage.java index d2dfa115..94180db9 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/PCloudFileStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/PCloudFileStorage.java @@ -247,12 +247,14 @@ public class PCloudFileStorage extends JavaFileStorageBase } private void handleAuthResult(FileStorageSetupActivity activity, AuthorizationData authorizationData) { + if (authorizationData.result == AuthorizationResult.ACCESS_GRANTED) { String authToken = authorizationData.token; String apiHost = authorizationData.apiHost; setAuthToken(authToken, apiHost); finishActivityWithSuccess(activity); } else { + android.util.Log.d("KP2A", "Auth failed with " + authorizationData.result.toString() + ", code=" + authorizationData.authCode + ", error=" + authorizationData.errorMessage); Activity castedActivity = (Activity)activity; Intent resultData = new Intent(); resultData.putExtra(EXTRA_ERROR_MESSAGE, "Authentication failed!"); From 2a4c0a84274c05be6986c0a0ce2885791a42ce4d Mon Sep 17 00:00:00 2001 From: TiloHeidasch <56626655+TiloHeidasch@users.noreply.github.com> Date: Tue, 16 Mar 2021 11:45:39 +0100 Subject: [PATCH 05/10] Fixes Typo --- src/keepass2android/Resources/values-de/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index d63a66c8..e708eb89 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -558,7 +558,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Die Datei ist nur kurzzeitig für Keepass2Android verfügbar. The gewählte Datei ist schreibgeschützt. The gewählte Datei kann aufgrund von Beschränkungen in Android 4.4+ von Keepass2Android nicht geändert werden. - Um sie zu benutzen, musst sie an einen anderen Speicherort kopiert werden. + Um die Datei zu benutzen, muss sie an einen anderen Speicherort kopiert werden. Um sie zu bearbeiten, muss sie an einen anderen Speicherort kopiert werden. Tippe auf OK, um einen Speicherort zu wählen. Datenbank ist schreibgeschützt From 84ac5fef4f1b438862d2e19785a232f27c7222d0 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 29 Mar 2021 10:11:02 +0200 Subject: [PATCH 06/10] remove option "Binary directory" (no longer used) --- src/keepass2android/EntryActivity.cs | 5 ++--- src/keepass2android/Resources/values/config.xml | 2 +- src/keepass2android/Resources/values/strings.xml | 2 -- src/keepass2android/Resources/xml/preferences.xml | 8 +------- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/keepass2android/EntryActivity.cs b/src/keepass2android/EntryActivity.cs index 8f067424..cf195524 100644 --- a/src/keepass2android/EntryActivity.cs +++ b/src/keepass2android/EntryActivity.cs @@ -606,11 +606,10 @@ namespace keepass2android ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this); - string binaryDirectory = prefs.GetString(GetString(Resource.String.BinaryDirectory_key), - GetString(Resource.String.BinaryDirectory_default)); + if (writeToCacheDirectory) { - binaryDirectory = CacheDir.Path + File.Separator + AttachmentContentProvider.AttachmentCacheSubDir; + string binaryDirectory = CacheDir.Path + File.Separator + AttachmentContentProvider.AttachmentCacheSubDir; string filepart = key; Java.Lang.String javaFilename = new Java.Lang.String(filepart); diff --git a/src/keepass2android/Resources/values/config.xml b/src/keepass2android/Resources/values/config.xml index 38c93f9c..dd962bef 100644 --- a/src/keepass2android/Resources/values/config.xml +++ b/src/keepass2android/Resources/values/config.xml @@ -75,7 +75,7 @@ RememberRecentFiles_key defaultUsername databaseName - binaryDirectory + /mnt/sdcard/keepass2android/binaries/ true true diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index 0b63b250..d253a4f6 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -325,8 +325,6 @@ If enabled, the length of the QuickUnlock code is not displayed on the QuickUnlock screen. QuickUnlock failed: incorrect password! - File attachments directory - Directory where file attachments are saved to. Save attachment Please select where to save the attachment. Export to file... diff --git a/src/keepass2android/Resources/xml/preferences.xml b/src/keepass2android/Resources/xml/preferences.xml index 3d55bf82..2a52e746 100644 --- a/src/keepass2android/Resources/xml/preferences.xml +++ b/src/keepass2android/Resources/xml/preferences.xml @@ -509,13 +509,7 @@ android:key="@string/FileHandling_prefs_key" android:title="@string/FileHandling_prefs"/> - + Date: Thu, 13 May 2021 16:20:17 +0200 Subject: [PATCH 07/10] implement editor for TOTP settings in EntryEditActivity, closes https://github.com/PhilippC/keepass2android/issues/770 --- src/keepass2android/EntryEditActivity.cs | 225 +++++++++++++++++- .../baseline_schedule_white_24.png | Bin 0 -> 539 bytes .../drawable/baseline_schedule_24.xml | 13 + .../layout/configure_totp_dialog.xml | 69 ++++++ .../Resources/layout/entry_edit.xml | 13 + .../Resources/values/config.xml | 6 + .../Resources/values/strings.xml | 10 +- .../Totp/KeeWebOtpPluginAdapter.cs | 4 +- .../Totp/Keepass2TotpPluginAdapter.cs | 2 +- src/keepass2android/Totp/Kp2aTotp.cs | 17 ++ src/keepass2android/Totp/TOTPProvider.cs | 2 +- src/keepass2android/Totp/TotpData.cs | 23 +- .../Totp/TrayTotpPluginAdapter.cs | 2 +- src/keepass2android/keepass2android.csproj | 18 +- 14 files changed, 389 insertions(+), 15 deletions(-) create mode 100644 src/keepass2android/Resources/drawable-xhdpi/baseline_schedule_white_24.png create mode 100644 src/keepass2android/Resources/drawable/baseline_schedule_24.xml create mode 100644 src/keepass2android/Resources/layout/configure_totp_dialog.xml diff --git a/src/keepass2android/EntryEditActivity.cs b/src/keepass2android/EntryEditActivity.cs index be3506f4..43d23c24 100644 --- a/src/keepass2android/EntryEditActivity.cs +++ b/src/keepass2android/EntryEditActivity.cs @@ -33,12 +33,17 @@ using KeePassLib.Security; using Android.Content.PM; using System.IO; using System.Globalization; +using System.Net; +using System.Text; +using Android.Content.Res; using Android.Database; using Android.Graphics; using Android.Graphics.Drawables; using Android.Util; using keepass2android.Io; using KeePassLib.Serialization; +using KeeTrayTOTP.Libraries; +using PluginTOTP; using Debug = System.Diagnostics.Debug; using File = System.IO.File; using Object = Java.Lang.Object; @@ -287,7 +292,31 @@ namespace keepass2android EditAdvancedString(ees.FindViewById(Resource.Id.edit_extra)); }; SetAddExtraStringEnabled(); - FindViewById(Resource.Id.entry_extras_container).Visibility = + + + Button configureTotpButton = (Button)FindViewById(Resource.Id.configure_totp); + + configureTotpButton.Visibility = CanConfigureOtpSettings() ? ViewStates.Gone : ViewStates.Visible; + configureTotpButton.Click += (sender, e) => + { + bool added = false; + View ees = FindExtraEditSection("otp"); + if (ees == null) + { + LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container); + + KeyValuePair pair = + new KeyValuePair("otp", new ProtectedString(true, "")); + ees = CreateExtraStringView(pair); + container.AddView(ees); + added = true; + } + + + EditTotpString(ees.FindViewById(Resource.Id.edit_extra)); + }; + + FindViewById(Resource.Id.entry_extras_container).Visibility = State.EditMode.ShowAddExtras || State.Entry.Strings.Any(s => !PwDefs.IsStandardField(s.Key)) ? ViewStates.Visible : ViewStates.Gone; FindViewById(Resource.Id.entry_binaries_container).Visibility = State.EditMode.ShowAddAttachments || State.Entry.Binaries.Any() ? ViewStates.Visible : ViewStates.Gone; @@ -402,9 +431,17 @@ namespace keepass2android private void SetAddExtraStringEnabled() { ((Button)FindViewById(Resource.Id.add_advanced)).Visibility = (!App.Kp2a.CurrentDb.DatabaseFormat.CanHaveCustomFields || !State.EditMode.ShowAddExtras) ? ViewStates.Gone : ViewStates.Visible; + ((Button)FindViewById(Resource.Id.configure_totp)).Visibility = CanConfigureOtpSettings() ? ViewStates.Gone : ViewStates.Visible; } - private void MakePasswordVisibleOrHidden() + private bool CanConfigureOtpSettings() + { + return (!App.Kp2a.CurrentDb.DatabaseFormat.CanHaveCustomFields || !State.EditMode.ShowAddExtras) + && (new Kp2aTotp().TryGetAdapter(new PwEntryOutput(State.Entry, App.Kp2a.CurrentDb)) == null || (State.Entry.Strings.GetKeys().Contains("otp"))) //only allow to edit KeeWeb/KeepassXC style otps + ; + } + + private void MakePasswordVisibleOrHidden() { EditText password = (EditText) FindViewById(Resource.Id.entry_password); TextView confpassword = (TextView) FindViewById(Resource.Id.entry_confpassword); @@ -942,7 +979,8 @@ namespace keepass2android binariesGroup.Visibility = ViewStates.Visible; FindViewById(Resource.Id.entry_binaries_container).Visibility = ViewStates.Visible; ((Button)FindViewById(Resource.Id.add_advanced)).Visibility = ViewStates.Visible; - FindViewById(Resource.Id.entry_extras_container).Visibility = ViewStates.Visible; + ((Button)FindViewById(Resource.Id.configure_totp)).Visibility = ViewStates.Visible; + FindViewById(Resource.Id.entry_extras_container).Visibility = ViewStates.Visible; return true; case Android.Resource.Id.Home: @@ -1020,6 +1058,7 @@ namespace keepass2android if (type == "bool") { RelativeLayout ees = (RelativeLayout)LayoutInflater.Inflate(Resource.Layout.entry_edit_section_bool, null); + ees.Tag = pair.Key; var keyView = ((TextView)ees.FindViewById(Resource.Id.extrakey)); var checkbox = ((CheckBox)ees.FindViewById(Resource.Id.checkbox)); var valueView = ((TextView)ees.FindViewById(Resource.Id.value)); @@ -1037,6 +1076,7 @@ namespace keepass2android else if (type == "file") { RelativeLayout ees = (RelativeLayout)LayoutInflater.Inflate(Resource.Layout.entry_edit_section_file, null); + ees.Tag = pair.Key; var keyView = ((TextView)ees.FindViewById(Resource.Id.extrakey)); var titleView = ((TextView)ees.FindViewById(Resource.Id.title)); keyView.Text = pair.Key; @@ -1054,6 +1094,7 @@ namespace keepass2android else { RelativeLayout ees = (RelativeLayout)LayoutInflater.Inflate(Resource.Layout.entry_edit_section, null); + ees.Tag = pair.Key; var keyView = ((TextView)ees.FindViewById(Resource.Id.extrakey)); var titleView = ((TextView)ees.FindViewById(Resource.Id.title)); keyView.Text = pair.Key; @@ -1090,8 +1131,184 @@ namespace keepass2android } } + + private void EditTotpString(View sender) + { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + View dlgView = LayoutInflater.Inflate(Resource.Layout. + configure_totp_dialog, null); - private void EditAdvancedString(View sender) + + + builder.SetView(dlgView); + builder.SetNegativeButton(Android.Resource.String.Cancel, (o, args) => { }); + builder.SetPositiveButton(Android.Resource.String.Ok, (o, args) => + { + + var targetField = ((TextView)((View)sender.Parent).FindViewById(Resource.Id.value)); + if (targetField != null) + { + string entryTitle = Util.GetEditText(this, Resource.Id.entry_title); + string username = Util.GetEditText(this, Resource.Id.entry_user_name); + string secret = dlgView.FindViewById(Resource.Id.totp_secret_key).Text; + string totpLength = dlgView.FindViewById(Resource.Id.totp_length).Text; + string timeStep = dlgView.FindViewById(Resource.Id.totp_time_step).Text; + var checkedTotpId = (int)dlgView.FindViewById(Resource.Id.totp_encoding).CheckedRadioButtonId; + TotpEncoding encoding = (checkedTotpId == Resource.Id.totp_encoding_steam) + ? TotpEncoding.Steam : (checkedTotpId == Resource.Id.totp_encoding_rfc6238 ? TotpEncoding.Default : TotpEncoding.Custom); + var algorithm = (int)dlgView.FindViewById(Resource.Id.totp_algorithm).SelectedItemPosition; + + targetField.Text = BuildOtpString(entryTitle, username, secret, totpLength, timeStep, encoding, algorithm); + } + else + { + Toast.MakeText(this, "did not find target field", ToastLength.Long).Show(); + } + + + //not calling State.Entry.Strings.Set(...). We only do this when the user saves the changes. + State.EntryModified = true; + + }); + Dialog dialog = builder.Create(); + + dlgView.FindViewById(Resource.Id.totp_encoding_custom).CheckedChange += (o, args) => + { + dlgView.FindViewById(Resource.Id.totp_custom_settings_group).Visibility = args.IsChecked ? ViewStates.Visible : ViewStates.Gone; + }; + + + //copy values from entry into dialog + View ees = (View)sender.Parent; + TotpData totpData = new Kp2aTotp().TryGetTotpData(new PwEntryOutput(State.Entry, App.Kp2a.CurrentDb)); + if (totpData != null) + { + dlgView.FindViewById(Resource.Id.totp_secret_key).Text = totpData.TotpSeed; + if (totpData.Encoder == TotpData.EncoderSteam) + { + dlgView.FindViewById(Resource.Id.totp_encoding_steam).Checked = true; + } + else if ((totpData.Encoder == TotpData.EncoderRfc6238) && (totpData.IsDefaultRfc6238)) + { + dlgView.FindViewById(Resource.Id.totp_encoding_rfc6238).Checked = true; + } + else + { + dlgView.FindViewById(Resource.Id.totp_encoding_custom).Checked = true; + } + + dlgView.FindViewById(Resource.Id.totp_length).Text = totpData.Length; + dlgView.FindViewById(Resource.Id.totp_time_step).Text = totpData.Duration; + dlgView.FindViewById (Resource.Id.totp_algorithm).SetSelection(totpData.HashAlgorithm == TotpData.HashSha1 ? 0 : ( + totpData.HashAlgorithm == TotpData.HashSha256 ? 1: + (totpData.HashAlgorithm == TotpData.HashSha256 ? 2 : 0))); + + dlgView.FindViewById(Resource.Id.totp_custom_settings_group).Visibility = dlgView.FindViewById(Resource.Id.totp_encoding_custom).Checked ? ViewStates.Visible : ViewStates.Gone; + } + + _passwordFont.ApplyTo(dlgView.FindViewById(Resource.Id.totp_secret_key)); + Util.SetNoPersonalizedLearning(dlgView); + + + + dialog.Show(); + + } + + string SanitizeInput(string encodedData) + { + if (encodedData.Length <= 0) + { + return encodedData; + } + + StringBuilder newEncodedDataBuilder = new StringBuilder(encodedData); + int i = 0; + foreach (var ch in encodedData) + { + switch (ch) + { + case '0': + newEncodedDataBuilder[i++] = 'O'; + break; + case '1': + newEncodedDataBuilder[i++] = 'L'; + break; + case '8': + newEncodedDataBuilder[i++] = 'B'; + break; + default: + if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('2' <= ch && ch <= '7')) + { + newEncodedDataBuilder[i++] = ch; + } + + break; + } + } + + string newEncodedData = newEncodedDataBuilder.ToString().Substring(0, i); + + return AddPadding(newEncodedData); + + } + + + string AddPadding(string encodedData) + { + if (encodedData.Length <= 0 || encodedData.Length % 8 == 0) { + return encodedData; + } + + int rBytes = encodedData.Length % 8; + // rBytes must be a member of {2, 4, 5, 7} + if (1 == rBytes || 3 == rBytes || 6 == rBytes) { + return encodedData; + } + + string newEncodedData = encodedData; + for (int nPads = 8 - rBytes; nPads > 0; --nPads) + { + newEncodedData += "="; + } + + return newEncodedData; + } + + enum TotpEncoding + { + Default, Steam, Custom + } + + private string BuildOtpString(string entryTitle, string userName, string secret, string totpLength, string timeStep, TotpEncoding encoding, int algorithm) + { + string entryEncoded = string.IsNullOrWhiteSpace(entryTitle) + ? "Keepass2Android" + : System.Uri.EscapeUriString(entryTitle); + return $"otpauth://totp/{entryEncoded}:{System.Uri.EscapeUriString(userName)}?" + + $"secret={SanitizeInput(secret)}" + + $"&issuer={ entryEncoded}" + + (encoding != TotpEncoding.Custom? "" : $"&period={timeStep}&digits={totpLength}&algorithm={AlgorithmIndexToString(algorithm)}") + + (encoding == TotpEncoding.Steam ? "&encoder=steam" : ""); + + } + + private string AlgorithmIndexToString(in int algorithm) + { + switch (algorithm) + { + case 0: + return "SHA1"; + case 1: + return "SHA256"; + case 2: + return "SHA512"; + default: + return ""; + } + } + + private void EditAdvancedString(View sender) { AlertDialog.Builder builder = new AlertDialog.Builder(this); View dlgView = LayoutInflater.Inflate(Resource.Layout. diff --git a/src/keepass2android/Resources/drawable-xhdpi/baseline_schedule_white_24.png b/src/keepass2android/Resources/drawable-xhdpi/baseline_schedule_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..8cf5cc8a51a61cfb7903c8e7ac88ab7ddd3873e2 GIT binary patch literal 539 zcmV+$0_6RPP)NzzhW%b}QL<1T>O;0Ii5O*b$X#$!>H+kE}$eT@4BG7B*XJkdd%aXm%Cy zQ@C>t^L1w?ZX$8obME=y`#+yoh=2J5!XS%mb4G_p09@L%s4>q#e&;3jc_2#e*kvZW z^GTY#ktBT%n8@OOjV`+K%t|`v1&)8*@*0NC{i$1?+rtLhHMkS(dYigAztAOu&^OD(8sN!5BTfOYAm6;ySk zs*($!BE58is%NR1%LOp!m0M8dg=Z`mz?hdRIRKc?2B1w5@0>7|o+6zfFLNucUf5tL zU63`>R0xLIQBCcJr8H@(QE1X~mUGqpPrt7%afPPQDniM6WmB(JXf(SBvYJ}WPN!Xm zlJ(?Gu!MH4GjKvrO=}OF$`yuh>~^ojrg literal 0 HcmV?d00001 diff --git a/src/keepass2android/Resources/drawable/baseline_schedule_24.xml b/src/keepass2android/Resources/drawable/baseline_schedule_24.xml new file mode 100644 index 00000000..86533bf0 --- /dev/null +++ b/src/keepass2android/Resources/drawable/baseline_schedule_24.xml @@ -0,0 +1,13 @@ + + + + diff --git a/src/keepass2android/Resources/layout/configure_totp_dialog.xml b/src/keepass2android/Resources/layout/configure_totp_dialog.xml new file mode 100644 index 00000000..d4138447 --- /dev/null +++ b/src/keepass2android/Resources/layout/configure_totp_dialog.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/keepass2android/Resources/layout/entry_edit.xml b/src/keepass2android/Resources/layout/entry_edit.xml index 5943f9be..8f13456f 100644 --- a/src/keepass2android/Resources/layout/entry_edit.xml +++ b/src/keepass2android/Resources/layout/entry_edit.xml @@ -177,6 +177,19 @@ android:layout_weight="1" android:layout_height="wrap_content" android:text="@string/add_extra_string"/> + +