* introduce FAB for search

* introduce TOTP preview on PwEntryView

first steps towards #803
This commit is contained in:
Philipp Crocoll
2024-01-17 07:07:46 +01:00
parent fdcd4321e0
commit f297ebcd40
8 changed files with 176 additions and 15 deletions

View File

@@ -72,8 +72,9 @@ namespace keepass2android
} }
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default); private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
private bool? _hasTotpEntries;
public bool ReloadRequested { get; set; } public bool ReloadRequested { get; set; }
public bool DidOpenFileChange() public bool DidOpenFileChange()
{ {
@@ -104,8 +105,9 @@ namespace keepass2android
SearchHelper = new SearchDbHelper(app); SearchHelper = new SearchDbHelper(app);
_databaseFormat = databaseFormat; _databaseFormat = databaseFormat;
_hasTotpEntries = null;
CanWrite = databaseFormat.CanWrite && !fileStorage.IsReadOnly(iocInfo); CanWrite = databaseFormat.CanWrite && !fileStorage.IsReadOnly(iocInfo);
} }
/// <summary> /// <summary>
@@ -200,8 +202,21 @@ namespace keepass2android
trans.CommitWrite(); trans.CommitWrite();
} }
_hasTotpEntries = null;
}
}
public bool HasTotpEntries
{
get
{
if (_hasTotpEntries == null)
{
_hasTotpEntries = true;
}
return _hasTotpEntries.Value;
}
}
private void PopulateGlobals(PwGroup currentGroup, bool checkForDuplicateUuids ) private void PopulateGlobals(PwGroup currentGroup, bool checkForDuplicateUuids )
{ {

View File

@@ -39,6 +39,8 @@ using Android.Support.V4.View;
using Android.Views.Autofill; using Android.Views.Autofill;
using CursorAdapter = Android.Support.V4.Widget.CursorAdapter; using CursorAdapter = Android.Support.V4.Widget.CursorAdapter;
using Object = Java.Lang.Object; using Object = Java.Lang.Object;
using Android.Text;
using KeeTrayTOTP.Libraries;
namespace keepass2android namespace keepass2android
{ {
@@ -115,6 +117,7 @@ namespace keepass2android
FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = (showAddGroup || showAddEntry) ? ViewStates.Visible : ViewStates.Gone; FindViewById(Resource.Id.fabAddNew).Visibility = (showAddGroup || showAddEntry) ? ViewStates.Visible : ViewStates.Gone;
FindViewById(Resource.Id.fabSearch).Visibility = (showAddGroup || showAddEntry) ? ViewStates.Visible : ViewStates.Gone;
} }
UpdateBottomBarElementVisibility(Resource.Id.insert_element, false); UpdateBottomBarElementVisibility(Resource.Id.insert_element, false);
@@ -262,6 +265,7 @@ namespace keepass2android
private bool hasCalledOtherActivity = false; private bool hasCalledOtherActivity = false;
private IMenuItem searchItem; private IMenuItem searchItem;
private IMenuItem searchItemDummy; private IMenuItem searchItemDummy;
private bool isPaused;
protected override void OnResume() protected override void OnResume()
{ {
@@ -281,8 +285,39 @@ namespace keepass2android
RefreshIfDirty(); RefreshIfDirty();
SetSearchItemVisibility(); SetSearchItemVisibility();
}
isPaused = false;
System.Threading.Tasks.Task.Run(UpdateTotpCountdown);
}
private async System.Threading.Tasks.Task UpdateTotpCountdown()
{
while (!isPaused )
{
RunOnUiThread(() =>
{
var listView = FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment)
.ListView;
if (listView != null)
{
int count = listView.Count;
for (int i = 0; i < count; i++)
{
var item = listView.GetChildAt(i);
if (item is PwEntryView)
{
var entryView = (PwEntryView)item;
entryView.UpdateTotp();
}
}
}
});
await System.Threading.Tasks.Task.Delay(1000);
}
}
private void UpdateInfotexts() private void UpdateInfotexts()
{ {
@@ -390,6 +425,13 @@ namespace keepass2android
} }
protected override void OnPause()
{
base.OnPause();
isPaused = true;
}
private void UpdatePostNotificationsPermissionInfo(bool hideForever=false) private void UpdatePostNotificationsPermissionInfo(bool hideForever=false)
{ {
const string prefsKey = "DidShowNotificationPermissionInfo"; const string prefsKey = "DidShowNotificationPermissionInfo";
@@ -572,6 +614,17 @@ namespace keepass2android
}; };
} }
if (FindViewById(Resource.Id.fabSearch) != null)
{
FindViewById(Resource.Id.fabSearch).Click += (sender, args) =>
{
if (searchView?.Iconified != false)
ActivateSearchView();
else
searchView.Iconified = true;
};
}
if (FindViewById(Resource.Id.fabCancelAddNew) != null) if (FindViewById(Resource.Id.fabCancelAddNew) != null)
{ {
FindViewById(Resource.Id.fabAddNew).Click += (sender, args) => FindViewById(Resource.Id.fabAddNew).Click += (sender, args) =>
@@ -580,6 +633,7 @@ namespace keepass2android
FindViewById(Resource.Id.fabAddNewGroup).Visibility = AddGroupEnabled ? ViewStates.Visible : ViewStates.Gone; FindViewById(Resource.Id.fabAddNewGroup).Visibility = AddGroupEnabled ? ViewStates.Visible : ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = AddEntryEnabled ? ViewStates.Visible : ViewStates.Gone; FindViewById(Resource.Id.fabAddNewEntry).Visibility = AddEntryEnabled ? ViewStates.Visible : ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabSearch).Visibility = ViewStates.Gone;
}; };
FindViewById(Resource.Id.fabCancelAddNew).Click += (sender, args) => FindViewById(Resource.Id.fabCancelAddNew).Click += (sender, args) =>
@@ -588,6 +642,7 @@ namespace keepass2android
FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Visible; FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Visible;
FindViewById(Resource.Id.fabSearch).Visibility = ViewStates.Visible;
}; };
@@ -1028,6 +1083,7 @@ namespace keepass2android
searchView.Iconified = false; searchView.Iconified = false;
AppTask.CanActivateSearchViewOnStart = false; AppTask.CanActivateSearchViewOnStart = false;
} }
@@ -1267,6 +1323,7 @@ namespace keepass2android
FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNewGroup).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNewEntry).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Gone; FindViewById(Resource.Id.fabAddNew).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fabSearch).Visibility = ViewStates.Gone;
UpdateBottomBarElementVisibility(Resource.Id.insert_element, true); UpdateBottomBarElementVisibility(Resource.Id.insert_element, true);
UpdateBottomBarElementVisibility(Resource.Id.cancel_insert_element, true); UpdateBottomBarElementVisibility(Resource.Id.cancel_insert_element, true);
@@ -1330,6 +1387,7 @@ namespace keepass2android
} }
ListView.ItemClick += (sender, args) => ((GroupListItemView)args.View).OnClick(); ListView.ItemClick += (sender, args) => ((GroupListItemView)args.View).OnClick();
StyleListView(); StyleListView();

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -61,6 +61,28 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:text="group detail" android:text="group detail"
style="@style/GroupDetailInSearchResult" /> style="@style/GroupDetailInSearchResult" />
<LinearLayout
android:id="@+id/totp_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/totp_text"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:text=""/>
<ProgressBar
android:id="@+id/TotpCountdownProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="30dp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<ImageView android:id="@+id/right_arrow" <ImageView android:id="@+id/right_arrow"

View File

@@ -400,5 +400,14 @@
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_marginBottom="160dp" android:layout_marginBottom="160dp"
android:visibility="gone"/> android:visibility="gone"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom|right"
android:src="@drawable/ic_fab_search"
android:layout_marginRight="16dp"
android:layout_marginBottom="88dp"
android:visibility="gone"/>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>
</RelativeLayout> </RelativeLayout>

View File

@@ -1988,6 +1988,12 @@
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_totp.png" /> <AndroidResource Include="Resources\drawable-xhdpi\ic_entry_totp.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-mdpi\ic_fab_search.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_fab_search.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -26,6 +26,9 @@ using Android.Text;
using Android.Text.Style; using Android.Text.Style;
using Android.Preferences; using Android.Preferences;
using KeePass.Util.Spr; using KeePass.Util.Spr;
using KeeTrayTOTP.Libraries;
using PluginTOTP;
using Microsoft.Graph;
namespace keepass2android.view namespace keepass2android.view
@@ -37,8 +40,11 @@ namespace keepass2android.view
private readonly TextView _textView; private readonly TextView _textView;
private readonly TextView _textviewDetails; private readonly TextView _textviewDetails;
private readonly TextView _textgroupFullPath; private readonly TextView _textgroupFullPath;
private readonly ProgressBar _totpCountdown;
private readonly TextView _totpText;
private readonly LinearLayout _totpLayout;
private int _pos; private int _pos;
private int? _defaultTextColor; private int? _defaultTextColor;
@@ -82,7 +88,11 @@ namespace keepass2android.view
_textgroupFullPath = (TextView)ev.FindViewById(Resource.Id.group_detail); _textgroupFullPath = (TextView)ev.FindViewById(Resource.Id.group_detail);
_textgroupFullPath.TextSize = PrefsUtil.GetListDetailTextSize(groupActivity); _textgroupFullPath.TextSize = PrefsUtil.GetListDetailTextSize(groupActivity);
_showDetail = PreferenceManager.GetDefaultSharedPreferences(groupActivity).GetBoolean( _totpCountdown = ev.FindViewById<ProgressBar>(Resource.Id.TotpCountdownProgressBar);
_totpText = ev.FindViewById<TextView>(Resource.Id.totp_text);
_totpLayout = ev.FindViewById<LinearLayout>(Resource.Id.totp_layout);
_showDetail = PreferenceManager.GetDefaultSharedPreferences(groupActivity).GetBoolean(
groupActivity.GetString(Resource.String.ShowUsernameInList_key), groupActivity.GetString(Resource.String.ShowUsernameInList_key),
Resources.GetBoolean(Resource.Boolean.ShowUsernameInList_default)); Resources.GetBoolean(Resource.Boolean.ShowUsernameInList_default));
@@ -112,20 +122,20 @@ namespace keepass2android.view
ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible; ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible; ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
Database db = App.Kp2a.FindDatabaseForElement(_entry); _db = App.Kp2a.FindDatabaseForElement(_entry);
ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon); ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon);
bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now; bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now;
if (isExpired) if (isExpired)
{ {
db.DrawableFactory.AssignDrawableTo(iv, Context, db.KpDatabase, PwIcon.Expired, PwUuid.Zero, false); _db.DrawableFactory.AssignDrawableTo(iv, Context, _db.KpDatabase, PwIcon.Expired, PwUuid.Zero, false);
} else } else
{ {
db.DrawableFactory.AssignDrawableTo(iv, Context, db.KpDatabase, pw.IconId, pw.CustomIconUuid, false); _db.DrawableFactory.AssignDrawableTo(iv, Context, _db.KpDatabase, pw.IconId, pw.CustomIconUuid, false);
} }
String title = pw.Strings.ReadSafe(PwDefs.TitleField); String title = pw.Strings.ReadSafe(PwDefs.TitleField);
title = SprEngine.Compile(title, new SprContext(_entry, db.KpDatabase, SprCompileFlags.All)); title = SprEngine.Compile(title, new SprContext(_entry, _db.KpDatabase, SprCompileFlags.All));
var str = new SpannableString(title); var str = new SpannableString(title);
if (isExpired) if (isExpired)
@@ -146,7 +156,7 @@ namespace keepass2android.view
_textView.SetTextColor(new Color((int)_defaultTextColor)); _textView.SetTextColor(new Color((int)_defaultTextColor));
String detail = pw.Strings.ReadSafe(PwDefs.UserNameField); String detail = pw.Strings.ReadSafe(PwDefs.UserNameField);
detail = SprEngine.Compile(detail, new SprContext(_entry, db.KpDatabase, SprCompileFlags.All)); detail = SprEngine.Compile(detail, new SprContext(_entry, _db.KpDatabase, SprCompileFlags.All));
if ((_showDetail == false) || (String.IsNullOrEmpty(detail))) if ((_showDetail == false) || (String.IsNullOrEmpty(detail)))
{ {
@@ -173,7 +183,7 @@ namespace keepass2android.view
String groupDetail = pw.ParentGroup.GetFullPath(); String groupDetail = pw.ParentGroup.GetFullPath();
if (App.Kp2a.OpenDatabases.Count() > 1) if (App.Kp2a.OpenDatabases.Count() > 1)
{ {
groupDetail += "(" + App.Kp2a.GetFileStorage(db.Ioc).GetDisplayName(db.Ioc) + ")"; groupDetail += "(" + App.Kp2a.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")";
} }
var strGroupDetail = new SpannableString (groupDetail); var strGroupDetail = new SpannableString (groupDetail);
@@ -186,7 +196,25 @@ namespace keepass2android.view
_textgroupFullPath.Visibility = ViewStates.Visible; _textgroupFullPath.Visibility = ViewStates.Visible;
} }
} //try to get totp data
UpdateTotp();
if (_totpData?.IsTotpEntry == true)
{
_totpLayout.Visibility = ViewStates.Visible;
}
else
{
_totpLayout.Visibility = ViewStates.Gone;
}
}
public void ConvertView(PwEntry pw, int pos) public void ConvertView(PwEntry pw, int pos)
{ {
@@ -248,6 +276,29 @@ namespace keepass2android.view
{ {
LaunchEntry(); LaunchEntry();
} }
}
private TotpData _totpData;
private Database _db;
public void UpdateTotp()
{
_totpData = new Kp2aTotp().TryGetTotpData(new PwEntryOutput(_entry, _db));
if (_totpData == null)
return;
Kp2aLog.Log("UpdateTotp");
TOTPProvider prov = new TOTPProvider(_totpData);
string totp = prov.GenerateByByte(_totpData.TotpSecret);
_totpText.Text = totp;
var progressBar = _totpCountdown;
progressBar.Progress = prov.Timer;
progressBar.Max = prov.Duration;
}
}
} }