add some info texts, especialy for novice users to avoid some common misunderstandings. closes #46, closes #47

This commit is contained in:
Philipp Crocoll
2018-01-23 23:09:17 +01:00
parent c4f8af2311
commit b993be4658
15 changed files with 1257 additions and 996 deletions

View File

@@ -28,6 +28,11 @@ namespace keepass2android.Io
get { yield return "content"; }
}
public bool UserShouldBackup
{
get { return true; }
}
public void Delete(IOConnectionInfo ioc)
{
throw new NotImplementedException();

View File

@@ -59,6 +59,11 @@ namespace keepass2android.Io
public abstract IEnumerable<string> SupportedProtocols { get; }
public bool UserShouldBackup
{
get { return true; }
}
public void Delete(IOConnectionInfo ioc)
{
//todo check if directory

View File

@@ -84,6 +84,11 @@ namespace keepass2android.Io
public IEnumerable<string> SupportedProtocols { get { return _cachedStorage.SupportedProtocols; } }
public bool UserShouldBackup
{
get { return _cachedStorage.UserShouldBackup; }
}
public void DeleteFile(IOConnectionInfo ioc)
{
if (IsCached(ioc))

View File

@@ -11,6 +11,10 @@ namespace keepass2android.Io
}
public override bool UserShouldBackup
{
get { return false; }
}
}
public partial class DropboxAppFolderFileStorage: JavaFileStorage
@@ -20,6 +24,10 @@ namespace keepass2android.Io
{
}
public override bool UserShouldBackup
{
get { return false; }
}
}

View File

@@ -22,6 +22,10 @@ namespace keepass2android.Io
}
public override bool UserShouldBackup
{
get { return false; }
}
}
}
#endif

View File

@@ -48,6 +48,11 @@ namespace keepass2android.Io
/// </summary>
IEnumerable<string> SupportedProtocols { get; }
/// <summary>
/// returns true if users should backup files on this file storage (if the file is important). Can be false for cloud providers with built-in versioning or backups.
/// </summary>
bool UserShouldBackup { get; }
/// <summary>
/// Deletes the given file or directory.
/// </summary>

View File

@@ -22,6 +22,7 @@ namespace keepass2android.Io
protected string Protocol { get { return _jfs.ProtocolId; } }
public virtual IEnumerable<string> SupportedProtocols { get { yield return Protocol; } }
public abstract bool UserShouldBackup { get; }
private readonly IJavaFileStorage _jfs;

View File

@@ -161,6 +161,11 @@ namespace keepass2android.Io
}
}
public bool UserShouldBackup
{
get { return true; }
}
public void Delete(IOConnectionInfo ioc)
{
try

View File

@@ -32,6 +32,11 @@ namespace keepass2android.Io
get { return _baseStorage.SupportedProtocols; }
}
public bool UserShouldBackup
{
get { return _baseStorage.UserShouldBackup; }
}
public void Delete(IOConnectionInfo ioc)
{
_baseStorage.Delete(ioc);

View File

@@ -33,6 +33,11 @@ namespace keepass2android.Io
yield return "onedrive";
}
}
public override bool UserShouldBackup
{
get { return false; }
}
}
}
#endif

View File

@@ -11,6 +11,10 @@ namespace keepass2android.Io
}
public override bool UserShouldBackup
{
get { return true; }
}
}

View File

@@ -33,6 +33,11 @@ namespace keepass2android.Io
}
}
public override bool UserShouldBackup
{
get { return true; }
}
public static string Owncloud2Webdav(string owncloudUrl)
{
string owncloudPrefix = "owncloud://";

View File

@@ -53,6 +53,7 @@ namespace keepass2android
{ Resource.Id.cancel_insert_element, 20 },
{ Resource.Id.insert_element, 20 },
{ Resource.Id.autofill_infotext, 10 },
{ Resource.Id.infotext, 11 },
{ Resource.Id.select_other_entry, 20},
{ Resource.Id.add_url_entry, 20},
};
@@ -337,6 +338,102 @@ namespace keepass2android
}
string lastInfoText;
if (IsTimeForInfotext(out lastInfoText))
{
FingerprintUnlockMode um;
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.GetDb().Ioc), ""), out um);
bool isFingerprintEnabled = (um == FingerprintUnlockMode.FullUnlock);
string masterKeyKey = "MasterKey" + isFingerprintEnabled;
string emergencyKey = "Emergency";
string backupKey = "Backup";
List<string> applicableInfoTextKeys = new List<string> {masterKeyKey};
if (App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc).UserShouldBackup)
{
applicableInfoTextKeys.Add(backupKey);
}
if (App.Kp2a.GetDb().Entries.Count > 15)
{
applicableInfoTextKeys.Add(emergencyKey);
}
List<string> enabledInfoTextKeys = new List<string>();
foreach (string key in applicableInfoTextKeys)
{
if (!InfoTextWasDisabled(key))
enabledInfoTextKeys.Add(key);
}
if (enabledInfoTextKeys.Any())
{
string infoTextKey = "", infoHead = "", infoMain = "", infoNote = "";
if (enabledInfoTextKeys.Count > 1)
{
foreach (string key in enabledInfoTextKeys)
if (key == lastInfoText)
{
enabledInfoTextKeys.Remove(key);
break;
}
infoTextKey = enabledInfoTextKeys[new Random().Next(enabledInfoTextKeys.Count)];
}
if (infoTextKey == masterKeyKey)
{
infoHead = GetString(Resource.String.masterkey_infotext_head);
infoMain = GetString(Resource.String.masterkey_infotext_main);
if (isFingerprintEnabled)
infoNote = GetString(Resource.String.masterkey_infotext_fingerprint_note);
}
else if (infoTextKey == emergencyKey)
{
infoHead = GetString(Resource.String.emergency_infotext_head);
infoMain = GetString(Resource.String.emergency_infotext_main);
}
else if (infoTextKey == backupKey)
{
infoHead = GetString(Resource.String.backup_infotext_head);
infoMain = GetString(Resource.String.backup_infotext_main);
infoNote = GetString(Resource.String.backup_infotext_note, GetString(Resource.String.menu_app_settings), GetString(Resource.String.menu_db_settings), GetString(Resource.String.export_prefs));
}
FindViewById<TextView>(Resource.Id.info_head).Text = infoHead;
FindViewById<TextView>(Resource.Id.info_main).Text = infoMain;
var additionalInfoText = FindViewById<TextView>(Resource.Id.info_additional);
additionalInfoText.Text = infoNote;
additionalInfoText.Visibility = string.IsNullOrEmpty(infoNote) ? ViewStates.Gone : ViewStates.Visible;
if (infoTextKey != "")
{
RegisterInfoTextDisplay(infoTextKey);
FindViewById(Resource.Id.info_ok).Click += (sender, args) =>
{
UpdateBottomBarElementVisibility(Resource.Id.infotext, false);
};
FindViewById(Resource.Id.info_dont_show_again).Click += (sender, args) =>
{
UpdateBottomBarElementVisibility(Resource.Id.infotext, false);
DisableInfoTextDisplay(infoTextKey);
};
UpdateBottomBarElementVisibility(Resource.Id.infotext, true);
}
}
}
SetResult(KeePass.ExitNormal);
@@ -345,6 +442,41 @@ namespace keepass2android
}
private bool IsTimeForInfotext(out string lastInfoText)
{
DateTime lastDisplayTime = new DateTime(_prefs.GetLong("LastInfoTextTime", 0));
lastInfoText = _prefs.GetString("LastInfoTextKey", "");
#if DEBUG
return DateTime.UtcNow - lastDisplayTime > TimeSpan.FromSeconds(10);
#else
return DateTime.UtcNow - lastDisplayTime > TimeSpan.FromDays(3);
#endif
}
private void DisableInfoTextDisplay(string infoTextKey)
{
_prefs
.Edit()
.PutBoolean("InfoTextDisabled_" + infoTextKey, true)
.Commit();
}
private void RegisterInfoTextDisplay(string infoTextKey)
{
_prefs
.Edit()
.PutLong("LastInfoTextTime", DateTime.UtcNow.Ticks)
.PutString("LastInfoTextKey", infoTextKey)
.Commit();
}
private bool InfoTextWasDisabled(string infoTextKey)
{
return _prefs.GetBoolean("InfoTextDisabled_" + infoTextKey, false);
}
private void UpdateAutofillInfo()
{
bool canShowAutofillInfo = false;

View File

@@ -77,6 +77,63 @@
style="@style/BottomBarButton" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/infotext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:orientation="vertical">
<TextView android:id="@+id/info_head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_margin="6dp"
android:layout_marginBottom="2dp"
/>
<TextView android:id="@+id/info_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_margin="6dp"
android:layout_marginBottom="2dp"
/>
<TextView android:id="@+id/info_additional"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_margin="6dp"
android:layout_marginBottom="2dp"
/>
<RelativeLayout
android:id="@+id/info_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false">
<Button
android:id="@+id/info_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:paddingTop="4dp"
android:text="@string/understand"
style="@style/BottomBarButton" />
<Button
android:id="@+id/info_dont_show_again"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingTop="4dp"
android:text="@string/dont_show_again"
style="@style/BottomBarButton" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View File

@@ -1050,4 +1050,19 @@ Initial public release
<string name="autofill_sign_in_prompt">Fill with Keepass2Android</string>
<string name="invalid_link_association">Could not associate web domain %1$s with app %2$s</string>
<string name="understand">I understand</string>
<string name="dont_show_again">Do not show again</string>
<string name="masterkey_infotext_head">Do you remember your master password?</string>
<string name="masterkey_infotext_main">Note that you will not be able to open your database without the master key. There is no way to "reset" the master password.</string>
<string name="masterkey_infotext_fingerprint_note">Also note that fingerprint unlock might be disabled by Android at any time.</string>
<string name="backup_infotext_head">Is your database backed up?</string>
<string name="backup_infotext_main">Keepass2Android stores your passwords in a file on a location of your choice. Are you sure you can still access this file when your phone gets lost or stolen, or when the file gets destroyed or deleted? Please make sure you always have an up-to-date backup at a safe place!</string>
<string name="backup_infotext_note">To create a backup now, go to %1$s > %2$s > %3$s.</string>
<string name="emergency_infotext_head">Are you prepared for emergency cases?</string>
<string name="emergency_infotext_main">Did you ever consider what happens if you are no longer able to access your password database? What if you have an accident? It is good practice to pass your master key to some trusted person for emergency cases. Nobody will have access to your passwords otherwise.</string>
</resources>