vault list grouping page
@ -1075,6 +1075,21 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\xml\autofillservice.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\cube.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\cube.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\cube.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\cube.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\cube.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
@ -195,6 +195,7 @@ namespace Bit.Android
|
||||
container.RegisterSingleton<IKeyDerivationService, BouncyCastleKeyDerivationService>();
|
||||
container.RegisterSingleton<IAuthService, AuthService>();
|
||||
container.RegisterSingleton<IFolderService, FolderService>();
|
||||
container.RegisterSingleton<ICollectionService, CollectionService>();
|
||||
container.RegisterSingleton<ICipherService, CipherService>();
|
||||
container.RegisterSingleton<ISyncService, SyncService>();
|
||||
container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
|
||||
|
265
src/Android/Resources/Resource.Designer.cs
generated
@ -2464,391 +2464,394 @@ namespace Bit.Android
|
||||
public const int common_plus_signin_btn_text_light_pressed = 2130837633;
|
||||
|
||||
// aapt resource value: 0x7f020082
|
||||
public const int design_fab_background = 2130837634;
|
||||
public const int cube = 2130837634;
|
||||
|
||||
// aapt resource value: 0x7f020083
|
||||
public const int design_snackbar_background = 2130837635;
|
||||
public const int design_fab_background = 2130837635;
|
||||
|
||||
// aapt resource value: 0x7f020084
|
||||
public const int download = 2130837636;
|
||||
public const int design_snackbar_background = 2130837636;
|
||||
|
||||
// aapt resource value: 0x7f020085
|
||||
public const int envelope = 2130837637;
|
||||
public const int download = 2130837637;
|
||||
|
||||
// aapt resource value: 0x7f020086
|
||||
public const int eye = 2130837638;
|
||||
public const int envelope = 2130837638;
|
||||
|
||||
// aapt resource value: 0x7f020087
|
||||
public const int eye_slash = 2130837639;
|
||||
public const int eye = 2130837639;
|
||||
|
||||
// aapt resource value: 0x7f020088
|
||||
public const int fa_lock = 2130837640;
|
||||
public const int eye_slash = 2130837640;
|
||||
|
||||
// aapt resource value: 0x7f020089
|
||||
public const int fa_lock_selected = 2130837641;
|
||||
public const int fa_lock = 2130837641;
|
||||
|
||||
// aapt resource value: 0x7f02008a
|
||||
public const int fingerprint = 2130837642;
|
||||
public const int fa_lock_selected = 2130837642;
|
||||
|
||||
// aapt resource value: 0x7f02008b
|
||||
public const int fingerprint_white = 2130837643;
|
||||
public const int fingerprint = 2130837643;
|
||||
|
||||
// aapt resource value: 0x7f02008c
|
||||
public const int folder = 2130837644;
|
||||
public const int fingerprint_white = 2130837644;
|
||||
|
||||
// aapt resource value: 0x7f02008d
|
||||
public const int globe = 2130837645;
|
||||
public const int folder = 2130837645;
|
||||
|
||||
// aapt resource value: 0x7f02008e
|
||||
public const int hockeyapp_btn_background = 2130837646;
|
||||
public const int globe = 2130837646;
|
||||
|
||||
// aapt resource value: 0x7f02008f
|
||||
public const int ic_audiotrack = 2130837647;
|
||||
public const int hockeyapp_btn_background = 2130837647;
|
||||
|
||||
// aapt resource value: 0x7f020090
|
||||
public const int ic_audiotrack_light = 2130837648;
|
||||
public const int ic_audiotrack = 2130837648;
|
||||
|
||||
// aapt resource value: 0x7f020091
|
||||
public const int ic_bluetooth_grey = 2130837649;
|
||||
public const int ic_audiotrack_light = 2130837649;
|
||||
|
||||
// aapt resource value: 0x7f020092
|
||||
public const int ic_bluetooth_white = 2130837650;
|
||||
public const int ic_bluetooth_grey = 2130837650;
|
||||
|
||||
// aapt resource value: 0x7f020093
|
||||
public const int ic_cast_dark = 2130837651;
|
||||
public const int ic_bluetooth_white = 2130837651;
|
||||
|
||||
// aapt resource value: 0x7f020094
|
||||
public const int ic_cast_disabled_light = 2130837652;
|
||||
public const int ic_cast_dark = 2130837652;
|
||||
|
||||
// aapt resource value: 0x7f020095
|
||||
public const int ic_cast_grey = 2130837653;
|
||||
public const int ic_cast_disabled_light = 2130837653;
|
||||
|
||||
// aapt resource value: 0x7f020096
|
||||
public const int ic_cast_light = 2130837654;
|
||||
public const int ic_cast_grey = 2130837654;
|
||||
|
||||
// aapt resource value: 0x7f020097
|
||||
public const int ic_cast_off_light = 2130837655;
|
||||
public const int ic_cast_light = 2130837655;
|
||||
|
||||
// aapt resource value: 0x7f020098
|
||||
public const int ic_cast_on_0_light = 2130837656;
|
||||
public const int ic_cast_off_light = 2130837656;
|
||||
|
||||
// aapt resource value: 0x7f020099
|
||||
public const int ic_cast_on_1_light = 2130837657;
|
||||
public const int ic_cast_on_0_light = 2130837657;
|
||||
|
||||
// aapt resource value: 0x7f02009a
|
||||
public const int ic_cast_on_2_light = 2130837658;
|
||||
public const int ic_cast_on_1_light = 2130837658;
|
||||
|
||||
// aapt resource value: 0x7f02009b
|
||||
public const int ic_cast_on_light = 2130837659;
|
||||
public const int ic_cast_on_2_light = 2130837659;
|
||||
|
||||
// aapt resource value: 0x7f02009c
|
||||
public const int ic_cast_white = 2130837660;
|
||||
public const int ic_cast_on_light = 2130837660;
|
||||
|
||||
// aapt resource value: 0x7f02009d
|
||||
public const int ic_close_dark = 2130837661;
|
||||
public const int ic_cast_white = 2130837661;
|
||||
|
||||
// aapt resource value: 0x7f02009e
|
||||
public const int ic_close_light = 2130837662;
|
||||
public const int ic_close_dark = 2130837662;
|
||||
|
||||
// aapt resource value: 0x7f02009f
|
||||
public const int ic_collapse = 2130837663;
|
||||
public const int ic_close_light = 2130837663;
|
||||
|
||||
// aapt resource value: 0x7f0200a0
|
||||
public const int ic_collapse_00000 = 2130837664;
|
||||
public const int ic_collapse = 2130837664;
|
||||
|
||||
// aapt resource value: 0x7f0200a1
|
||||
public const int ic_collapse_00001 = 2130837665;
|
||||
public const int ic_collapse_00000 = 2130837665;
|
||||
|
||||
// aapt resource value: 0x7f0200a2
|
||||
public const int ic_collapse_00002 = 2130837666;
|
||||
public const int ic_collapse_00001 = 2130837666;
|
||||
|
||||
// aapt resource value: 0x7f0200a3
|
||||
public const int ic_collapse_00003 = 2130837667;
|
||||
public const int ic_collapse_00002 = 2130837667;
|
||||
|
||||
// aapt resource value: 0x7f0200a4
|
||||
public const int ic_collapse_00004 = 2130837668;
|
||||
public const int ic_collapse_00003 = 2130837668;
|
||||
|
||||
// aapt resource value: 0x7f0200a5
|
||||
public const int ic_collapse_00005 = 2130837669;
|
||||
public const int ic_collapse_00004 = 2130837669;
|
||||
|
||||
// aapt resource value: 0x7f0200a6
|
||||
public const int ic_collapse_00006 = 2130837670;
|
||||
public const int ic_collapse_00005 = 2130837670;
|
||||
|
||||
// aapt resource value: 0x7f0200a7
|
||||
public const int ic_collapse_00007 = 2130837671;
|
||||
public const int ic_collapse_00006 = 2130837671;
|
||||
|
||||
// aapt resource value: 0x7f0200a8
|
||||
public const int ic_collapse_00008 = 2130837672;
|
||||
public const int ic_collapse_00007 = 2130837672;
|
||||
|
||||
// aapt resource value: 0x7f0200a9
|
||||
public const int ic_collapse_00009 = 2130837673;
|
||||
public const int ic_collapse_00008 = 2130837673;
|
||||
|
||||
// aapt resource value: 0x7f0200aa
|
||||
public const int ic_collapse_00010 = 2130837674;
|
||||
public const int ic_collapse_00009 = 2130837674;
|
||||
|
||||
// aapt resource value: 0x7f0200ab
|
||||
public const int ic_collapse_00011 = 2130837675;
|
||||
public const int ic_collapse_00010 = 2130837675;
|
||||
|
||||
// aapt resource value: 0x7f0200ac
|
||||
public const int ic_collapse_00012 = 2130837676;
|
||||
public const int ic_collapse_00011 = 2130837676;
|
||||
|
||||
// aapt resource value: 0x7f0200ad
|
||||
public const int ic_collapse_00013 = 2130837677;
|
||||
public const int ic_collapse_00012 = 2130837677;
|
||||
|
||||
// aapt resource value: 0x7f0200ae
|
||||
public const int ic_collapse_00014 = 2130837678;
|
||||
public const int ic_collapse_00013 = 2130837678;
|
||||
|
||||
// aapt resource value: 0x7f0200af
|
||||
public const int ic_collapse_00015 = 2130837679;
|
||||
public const int ic_collapse_00014 = 2130837679;
|
||||
|
||||
// aapt resource value: 0x7f0200b0
|
||||
public const int ic_errorstatus = 2130837680;
|
||||
public const int ic_collapse_00015 = 2130837680;
|
||||
|
||||
// aapt resource value: 0x7f0200b1
|
||||
public const int ic_expand = 2130837681;
|
||||
public const int ic_errorstatus = 2130837681;
|
||||
|
||||
// aapt resource value: 0x7f0200b2
|
||||
public const int ic_expand_00000 = 2130837682;
|
||||
public const int ic_expand = 2130837682;
|
||||
|
||||
// aapt resource value: 0x7f0200b3
|
||||
public const int ic_expand_00001 = 2130837683;
|
||||
public const int ic_expand_00000 = 2130837683;
|
||||
|
||||
// aapt resource value: 0x7f0200b4
|
||||
public const int ic_expand_00002 = 2130837684;
|
||||
public const int ic_expand_00001 = 2130837684;
|
||||
|
||||
// aapt resource value: 0x7f0200b5
|
||||
public const int ic_expand_00003 = 2130837685;
|
||||
public const int ic_expand_00002 = 2130837685;
|
||||
|
||||
// aapt resource value: 0x7f0200b6
|
||||
public const int ic_expand_00004 = 2130837686;
|
||||
public const int ic_expand_00003 = 2130837686;
|
||||
|
||||
// aapt resource value: 0x7f0200b7
|
||||
public const int ic_expand_00005 = 2130837687;
|
||||
public const int ic_expand_00004 = 2130837687;
|
||||
|
||||
// aapt resource value: 0x7f0200b8
|
||||
public const int ic_expand_00006 = 2130837688;
|
||||
public const int ic_expand_00005 = 2130837688;
|
||||
|
||||
// aapt resource value: 0x7f0200b9
|
||||
public const int ic_expand_00007 = 2130837689;
|
||||
public const int ic_expand_00006 = 2130837689;
|
||||
|
||||
// aapt resource value: 0x7f0200ba
|
||||
public const int ic_expand_00008 = 2130837690;
|
||||
public const int ic_expand_00007 = 2130837690;
|
||||
|
||||
// aapt resource value: 0x7f0200bb
|
||||
public const int ic_expand_00009 = 2130837691;
|
||||
public const int ic_expand_00008 = 2130837691;
|
||||
|
||||
// aapt resource value: 0x7f0200bc
|
||||
public const int ic_expand_00010 = 2130837692;
|
||||
public const int ic_expand_00009 = 2130837692;
|
||||
|
||||
// aapt resource value: 0x7f0200bd
|
||||
public const int ic_expand_00011 = 2130837693;
|
||||
public const int ic_expand_00010 = 2130837693;
|
||||
|
||||
// aapt resource value: 0x7f0200be
|
||||
public const int ic_expand_00012 = 2130837694;
|
||||
public const int ic_expand_00011 = 2130837694;
|
||||
|
||||
// aapt resource value: 0x7f0200bf
|
||||
public const int ic_expand_00013 = 2130837695;
|
||||
public const int ic_expand_00012 = 2130837695;
|
||||
|
||||
// aapt resource value: 0x7f0200c0
|
||||
public const int ic_expand_00014 = 2130837696;
|
||||
public const int ic_expand_00013 = 2130837696;
|
||||
|
||||
// aapt resource value: 0x7f0200c1
|
||||
public const int ic_expand_00015 = 2130837697;
|
||||
public const int ic_expand_00014 = 2130837697;
|
||||
|
||||
// aapt resource value: 0x7f0200c2
|
||||
public const int ic_media_pause = 2130837698;
|
||||
public const int ic_expand_00015 = 2130837698;
|
||||
|
||||
// aapt resource value: 0x7f0200c3
|
||||
public const int ic_media_play = 2130837699;
|
||||
public const int ic_media_pause = 2130837699;
|
||||
|
||||
// aapt resource value: 0x7f0200c4
|
||||
public const int ic_media_route_disabled_mono_dark = 2130837700;
|
||||
public const int ic_media_play = 2130837700;
|
||||
|
||||
// aapt resource value: 0x7f0200c5
|
||||
public const int ic_media_route_off_mono_dark = 2130837701;
|
||||
public const int ic_media_route_disabled_mono_dark = 2130837701;
|
||||
|
||||
// aapt resource value: 0x7f0200c6
|
||||
public const int ic_media_route_on_0_mono_dark = 2130837702;
|
||||
public const int ic_media_route_off_mono_dark = 2130837702;
|
||||
|
||||
// aapt resource value: 0x7f0200c7
|
||||
public const int ic_media_route_on_1_mono_dark = 2130837703;
|
||||
public const int ic_media_route_on_0_mono_dark = 2130837703;
|
||||
|
||||
// aapt resource value: 0x7f0200c8
|
||||
public const int ic_media_route_on_2_mono_dark = 2130837704;
|
||||
public const int ic_media_route_on_1_mono_dark = 2130837704;
|
||||
|
||||
// aapt resource value: 0x7f0200c9
|
||||
public const int ic_media_route_on_mono_dark = 2130837705;
|
||||
public const int ic_media_route_on_2_mono_dark = 2130837705;
|
||||
|
||||
// aapt resource value: 0x7f0200ca
|
||||
public const int ic_pause_dark = 2130837706;
|
||||
public const int ic_media_route_on_mono_dark = 2130837706;
|
||||
|
||||
// aapt resource value: 0x7f0200cb
|
||||
public const int ic_pause_light = 2130837707;
|
||||
public const int ic_pause_dark = 2130837707;
|
||||
|
||||
// aapt resource value: 0x7f0200cc
|
||||
public const int ic_play_dark = 2130837708;
|
||||
public const int ic_pause_light = 2130837708;
|
||||
|
||||
// aapt resource value: 0x7f0200cd
|
||||
public const int ic_play_light = 2130837709;
|
||||
public const int ic_play_dark = 2130837709;
|
||||
|
||||
// aapt resource value: 0x7f0200ce
|
||||
public const int ic_speaker_dark = 2130837710;
|
||||
public const int ic_play_light = 2130837710;
|
||||
|
||||
// aapt resource value: 0x7f0200cf
|
||||
public const int ic_speaker_group_dark = 2130837711;
|
||||
public const int ic_speaker_dark = 2130837711;
|
||||
|
||||
// aapt resource value: 0x7f0200d0
|
||||
public const int ic_speaker_group_light = 2130837712;
|
||||
public const int ic_speaker_group_dark = 2130837712;
|
||||
|
||||
// aapt resource value: 0x7f0200d1
|
||||
public const int ic_speaker_light = 2130837713;
|
||||
public const int ic_speaker_group_light = 2130837713;
|
||||
|
||||
// aapt resource value: 0x7f0200d2
|
||||
public const int ic_successstatus = 2130837714;
|
||||
public const int ic_speaker_light = 2130837714;
|
||||
|
||||
// aapt resource value: 0x7f0200d3
|
||||
public const int ic_tv_dark = 2130837715;
|
||||
public const int ic_successstatus = 2130837715;
|
||||
|
||||
// aapt resource value: 0x7f0200d4
|
||||
public const int ic_tv_light = 2130837716;
|
||||
public const int ic_tv_dark = 2130837716;
|
||||
|
||||
// aapt resource value: 0x7f0200d5
|
||||
public const int icon = 2130837717;
|
||||
public const int ic_tv_light = 2130837717;
|
||||
|
||||
// aapt resource value: 0x7f0200d6
|
||||
public const int id = 2130837718;
|
||||
public const int icon = 2130837718;
|
||||
|
||||
// aapt resource value: 0x7f0200d7
|
||||
public const int ion_chevron_right = 2130837719;
|
||||
public const int id = 2130837719;
|
||||
|
||||
// aapt resource value: 0x7f0200d8
|
||||
public const int launch = 2130837720;
|
||||
public const int ion_chevron_right = 2130837720;
|
||||
|
||||
// aapt resource value: 0x7f0200d9
|
||||
public const int lightbulb = 2130837721;
|
||||
public const int launch = 2130837721;
|
||||
|
||||
// aapt resource value: 0x7f0200da
|
||||
public const int list_selector = 2130837722;
|
||||
public const int lightbulb = 2130837722;
|
||||
|
||||
// aapt resource value: 0x7f0200db
|
||||
public const int @lock = 2130837723;
|
||||
public const int list_selector = 2130837723;
|
||||
|
||||
// aapt resource value: 0x7f0200dc
|
||||
public const int login = 2130837724;
|
||||
public const int @lock = 2130837724;
|
||||
|
||||
// aapt resource value: 0x7f0200dd
|
||||
public const int logo = 2130837725;
|
||||
public const int login = 2130837725;
|
||||
|
||||
// aapt resource value: 0x7f0200de
|
||||
public const int more = 2130837726;
|
||||
public const int logo = 2130837726;
|
||||
|
||||
// aapt resource value: 0x7f0200df
|
||||
public const int mr_dialog_material_background_dark = 2130837727;
|
||||
public const int more = 2130837727;
|
||||
|
||||
// aapt resource value: 0x7f0200e0
|
||||
public const int mr_dialog_material_background_light = 2130837728;
|
||||
public const int mr_dialog_material_background_dark = 2130837728;
|
||||
|
||||
// aapt resource value: 0x7f0200e1
|
||||
public const int mr_ic_audiotrack_light = 2130837729;
|
||||
public const int mr_dialog_material_background_light = 2130837729;
|
||||
|
||||
// aapt resource value: 0x7f0200e2
|
||||
public const int mr_ic_cast_dark = 2130837730;
|
||||
public const int mr_ic_audiotrack_light = 2130837730;
|
||||
|
||||
// aapt resource value: 0x7f0200e3
|
||||
public const int mr_ic_cast_light = 2130837731;
|
||||
public const int mr_ic_cast_dark = 2130837731;
|
||||
|
||||
// aapt resource value: 0x7f0200e4
|
||||
public const int mr_ic_close_dark = 2130837732;
|
||||
public const int mr_ic_cast_light = 2130837732;
|
||||
|
||||
// aapt resource value: 0x7f0200e5
|
||||
public const int mr_ic_close_light = 2130837733;
|
||||
public const int mr_ic_close_dark = 2130837733;
|
||||
|
||||
// aapt resource value: 0x7f0200e6
|
||||
public const int mr_ic_media_route_connecting_mono_dark = 2130837734;
|
||||
public const int mr_ic_close_light = 2130837734;
|
||||
|
||||
// aapt resource value: 0x7f0200e7
|
||||
public const int mr_ic_media_route_connecting_mono_light = 2130837735;
|
||||
public const int mr_ic_media_route_connecting_mono_dark = 2130837735;
|
||||
|
||||
// aapt resource value: 0x7f0200e8
|
||||
public const int mr_ic_media_route_mono_dark = 2130837736;
|
||||
public const int mr_ic_media_route_connecting_mono_light = 2130837736;
|
||||
|
||||
// aapt resource value: 0x7f0200e9
|
||||
public const int mr_ic_media_route_mono_light = 2130837737;
|
||||
public const int mr_ic_media_route_mono_dark = 2130837737;
|
||||
|
||||
// aapt resource value: 0x7f0200ea
|
||||
public const int mr_ic_pause_dark = 2130837738;
|
||||
public const int mr_ic_media_route_mono_light = 2130837738;
|
||||
|
||||
// aapt resource value: 0x7f0200eb
|
||||
public const int mr_ic_pause_light = 2130837739;
|
||||
public const int mr_ic_pause_dark = 2130837739;
|
||||
|
||||
// aapt resource value: 0x7f0200ec
|
||||
public const int mr_ic_play_dark = 2130837740;
|
||||
public const int mr_ic_pause_light = 2130837740;
|
||||
|
||||
// aapt resource value: 0x7f0200ed
|
||||
public const int mr_ic_play_light = 2130837741;
|
||||
public const int mr_ic_play_dark = 2130837741;
|
||||
|
||||
// aapt resource value: 0x7f0200ee
|
||||
public const int note = 2130837742;
|
||||
public const int mr_ic_play_light = 2130837742;
|
||||
|
||||
// aapt resource value: 0x7f0200ef
|
||||
public const int notification_sm = 2130837743;
|
||||
|
||||
// aapt resource value: 0x7f020102
|
||||
public const int notification_template_icon_bg = 2130837762;
|
||||
public const int note = 2130837743;
|
||||
|
||||
// aapt resource value: 0x7f0200f0
|
||||
public const int paperclip = 2130837744;
|
||||
public const int notification_sm = 2130837744;
|
||||
|
||||
// aapt resource value: 0x7f020103
|
||||
public const int notification_template_icon_bg = 2130837763;
|
||||
|
||||
// aapt resource value: 0x7f0200f1
|
||||
public const int plus = 2130837745;
|
||||
public const int paperclip = 2130837745;
|
||||
|
||||
// aapt resource value: 0x7f0200f2
|
||||
public const int refresh = 2130837746;
|
||||
public const int plus = 2130837746;
|
||||
|
||||
// aapt resource value: 0x7f0200f3
|
||||
public const int roundedbg = 2130837747;
|
||||
public const int refresh = 2130837747;
|
||||
|
||||
// aapt resource value: 0x7f0200f4
|
||||
public const int roundedbgdark = 2130837748;
|
||||
public const int roundedbg = 2130837748;
|
||||
|
||||
// aapt resource value: 0x7f0200f5
|
||||
public const int search = 2130837749;
|
||||
public const int roundedbgdark = 2130837749;
|
||||
|
||||
// aapt resource value: 0x7f0200f6
|
||||
public const int share = 2130837750;
|
||||
public const int search = 2130837750;
|
||||
|
||||
// aapt resource value: 0x7f0200f7
|
||||
public const int share_tools = 2130837751;
|
||||
public const int share = 2130837751;
|
||||
|
||||
// aapt resource value: 0x7f0200f8
|
||||
public const int shield = 2130837752;
|
||||
public const int share_tools = 2130837752;
|
||||
|
||||
// aapt resource value: 0x7f0200f9
|
||||
public const int splash_screen = 2130837753;
|
||||
public const int shield = 2130837753;
|
||||
|
||||
// aapt resource value: 0x7f0200fa
|
||||
public const int star = 2130837754;
|
||||
public const int splash_screen = 2130837754;
|
||||
|
||||
// aapt resource value: 0x7f0200fb
|
||||
public const int star_selected = 2130837755;
|
||||
public const int star = 2130837755;
|
||||
|
||||
// aapt resource value: 0x7f0200fc
|
||||
public const int tools = 2130837756;
|
||||
public const int star_selected = 2130837756;
|
||||
|
||||
// aapt resource value: 0x7f0200fd
|
||||
public const int tools_selected = 2130837757;
|
||||
public const int tools = 2130837757;
|
||||
|
||||
// aapt resource value: 0x7f0200fe
|
||||
public const int trash = 2130837758;
|
||||
public const int tools_selected = 2130837758;
|
||||
|
||||
// aapt resource value: 0x7f0200ff
|
||||
public const int upload = 2130837759;
|
||||
public const int trash = 2130837759;
|
||||
|
||||
// aapt resource value: 0x7f020100
|
||||
public const int user = 2130837760;
|
||||
public const int upload = 2130837760;
|
||||
|
||||
// aapt resource value: 0x7f020101
|
||||
public const int yubikey = 2130837761;
|
||||
public const int user = 2130837761;
|
||||
|
||||
// aapt resource value: 0x7f020102
|
||||
public const int yubikey = 2130837762;
|
||||
|
||||
static Drawable()
|
||||
{
|
||||
|
BIN
src/Android/Resources/drawable-hdpi/cube.png
Normal file
After Width: | Height: | Size: 738 B |
BIN
src/Android/Resources/drawable-xhdpi/cube.png
Normal file
After Width: | Height: | Size: 941 B |
BIN
src/Android/Resources/drawable-xxhdpi/cube.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/Android/Resources/drawable-xxxhdpi/cube.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/Android/Resources/drawable/cube.png
Normal file
After Width: | Height: | Size: 533 B |
14
src/App/Abstractions/Services/ICollectionService.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Models;
|
||||
using System;
|
||||
|
||||
namespace Bit.App.Abstractions
|
||||
{
|
||||
public interface ICollectionService
|
||||
{
|
||||
Task<Collection> GetByIdAsync(string id);
|
||||
Task<IEnumerable<Collection>> GetAllAsync();
|
||||
Task<IEnumerable<Tuple<string, string>>> GetAllCipherAssociationsAsync();
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@
|
||||
<Compile Include="Abstractions\Repositories\IDeviceApiRepository.cs" />
|
||||
<Compile Include="Abstractions\Repositories\ISettingsRepository.cs" />
|
||||
<Compile Include="Abstractions\Services\IAppSettingsService.cs" />
|
||||
<Compile Include="Abstractions\Services\ICollectionService.cs" />
|
||||
<Compile Include="Abstractions\Services\IMemoryService.cs" />
|
||||
<Compile Include="Abstractions\Services\IPushNotificationListener.cs" />
|
||||
<Compile Include="Abstractions\Services\IPushNotification.cs" />
|
||||
@ -75,6 +76,7 @@
|
||||
<Compile Include="Controls\ExtendedContentPage.cs" />
|
||||
<Compile Include="Controls\LabeledRightDetailCell.cs" />
|
||||
<Compile Include="Controls\MemoryContentView.cs" />
|
||||
<Compile Include="Controls\SectionHeaderViewCell.cs" />
|
||||
<Compile Include="Controls\StepperCell.cs" />
|
||||
<Compile Include="Controls\ExtendedTableView.cs" />
|
||||
<Compile Include="Controls\ExtendedPicker.cs" />
|
||||
@ -90,6 +92,7 @@
|
||||
<Compile Include="Controls\FormEntryCell.cs" />
|
||||
<Compile Include="Controls\PinControl.cs" />
|
||||
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
|
||||
<Compile Include="Controls\VaultGroupingViewCell.cs" />
|
||||
<Compile Include="Controls\VaultListViewCell.cs" />
|
||||
<Compile Include="Enums\DeviceType.cs" />
|
||||
<Compile Include="Enums\FieldType.cs" />
|
||||
@ -189,6 +192,7 @@
|
||||
<Compile Include="Pages\Vault\VaultCustomFieldsPage.cs" />
|
||||
<Compile Include="Pages\Vault\VaultAutofillListCiphersPage.cs" />
|
||||
<Compile Include="Pages\Vault\VaultAttachmentsPage.cs" />
|
||||
<Compile Include="Pages\Vault\VaultListGroupingsPage.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Abstractions\Repositories\ICipherRepository.cs" />
|
||||
<Compile Include="Repositories\AttachmentRepository.cs" />
|
||||
@ -350,6 +354,7 @@
|
||||
<DependentUpon>AppResources.zh-Hant.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Services\AppSettingsService.cs" />
|
||||
<Compile Include="Services\CollectionService.cs" />
|
||||
<Compile Include="Services\SettingsService.cs" />
|
||||
<Compile Include="Services\TokenService.cs" />
|
||||
<Compile Include="Services\AppIdService.cs" />
|
||||
|
43
src/App/Controls/SectionHeaderViewCell.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class SectionHeaderViewCell : ExtendedViewCell
|
||||
{
|
||||
public SectionHeaderViewCell(string bindingName, string countBindingName = null, Thickness? padding = null)
|
||||
{
|
||||
var label = new Label
|
||||
{
|
||||
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
|
||||
Style = (Style)Application.Current.Resources["text-muted"],
|
||||
VerticalTextAlignment = TextAlignment.Center,
|
||||
HorizontalOptions = LayoutOptions.StartAndExpand
|
||||
};
|
||||
|
||||
label.SetBinding(Label.TextProperty, bindingName);
|
||||
|
||||
var stackLayout = new StackLayout
|
||||
{
|
||||
Padding = padding ?? new Thickness(16, 8, 0, 8),
|
||||
Children = { label },
|
||||
Orientation = StackOrientation.Horizontal
|
||||
};
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(countBindingName))
|
||||
{
|
||||
var countLabel = new Label
|
||||
{
|
||||
LineBreakMode = LineBreakMode.NoWrap,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
|
||||
Style = (Style)Application.Current.Resources["text-muted"],
|
||||
HorizontalOptions = LayoutOptions.End
|
||||
};
|
||||
countLabel.SetBinding(Label.TextProperty, countBindingName);
|
||||
stackLayout.Children.Add(countLabel);
|
||||
}
|
||||
|
||||
View = stackLayout;
|
||||
BackgroundColor = Color.FromHex("efeff4");
|
||||
}
|
||||
}
|
||||
}
|
79
src/App/Controls/VaultGroupingViewCell.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using Bit.App.Models.Page;
|
||||
using FFImageLoading.Forms;
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class VaultGroupingViewCell : ExtendedViewCell
|
||||
{
|
||||
public static readonly BindableProperty GroupingParameterProeprty = BindableProperty.Create(nameof(GroupingParameter),
|
||||
typeof(VaultListPageModel.Grouping), typeof(VaultGroupingViewCell), null);
|
||||
|
||||
public VaultGroupingViewCell()
|
||||
{
|
||||
Icon = new CachedImage
|
||||
{
|
||||
WidthRequest = 20,
|
||||
HeightRequest = 20,
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
VerticalOptions = LayoutOptions.Center,
|
||||
Source = "folder.png",
|
||||
Margin = new Thickness(0, 0, 10, 0)
|
||||
};
|
||||
|
||||
Label = new Label
|
||||
{
|
||||
LineBreakMode = LineBreakMode.TailTruncation,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
|
||||
HorizontalOptions = LayoutOptions.StartAndExpand
|
||||
};
|
||||
Label.SetBinding(Label.TextProperty, nameof(VaultListPageModel.Grouping.Name));
|
||||
|
||||
CountLabel = new Label
|
||||
{
|
||||
LineBreakMode = LineBreakMode.NoWrap,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
|
||||
Style = (Style)Application.Current.Resources["text-muted"],
|
||||
HorizontalOptions = LayoutOptions.End
|
||||
};
|
||||
CountLabel.SetBinding(Label.TextProperty, nameof(VaultListPageModel.Grouping.CipherCount));
|
||||
|
||||
var stackLayout = new StackLayout
|
||||
{
|
||||
Spacing = 0,
|
||||
Padding = new Thickness(16, 8),
|
||||
Children = { Icon, Label, CountLabel },
|
||||
Orientation = StackOrientation.Horizontal
|
||||
};
|
||||
|
||||
if(Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
Label.TextColor = Color.Black;
|
||||
}
|
||||
|
||||
View = stackLayout;
|
||||
BackgroundColor = Color.White;
|
||||
SetBinding(GroupingParameterProeprty, new Binding("."));
|
||||
}
|
||||
|
||||
public VaultListPageModel.Grouping GroupingParameter
|
||||
{
|
||||
get => GetValue(GroupingParameterProeprty) as VaultListPageModel.Grouping;
|
||||
set { SetValue(GroupingParameterProeprty, value); }
|
||||
}
|
||||
public CachedImage Icon { get; private set; }
|
||||
public Label Label { get; private set; }
|
||||
public Label CountLabel { get; private set; }
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
if(BindingContext is VaultListPageModel.Grouping grouping)
|
||||
{
|
||||
Icon.Source = grouping.Folder ? "folder.png" : "cube.png";
|
||||
}
|
||||
|
||||
base.OnBindingContextChanged();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using Bit.App.Models.Page;
|
||||
using FFImageLoading.Forms;
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
|
@ -165,6 +165,52 @@ namespace Bit.App.Models.Page
|
||||
public string Name { get; set; } = AppResources.FolderNone;
|
||||
}
|
||||
|
||||
public class Section : List<Grouping>
|
||||
{
|
||||
public Section(List<Grouping> groupings, string name)
|
||||
{
|
||||
AddRange(groupings);
|
||||
Name = name.ToUpperInvariant();
|
||||
ItemCount = groupings.Count;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public int ItemCount { get; set; }
|
||||
}
|
||||
|
||||
public class Grouping
|
||||
{
|
||||
public Grouping(string name, int count)
|
||||
{
|
||||
Id = null;
|
||||
Name = name;
|
||||
Folder = true;
|
||||
CipherCount = count;
|
||||
}
|
||||
|
||||
public Grouping(Models.Folder folder, int count)
|
||||
{
|
||||
Id = folder.Id;
|
||||
Name = folder.Name?.Decrypt();
|
||||
Folder = true;
|
||||
CipherCount = count;
|
||||
}
|
||||
|
||||
public Grouping(Collection collection, int count)
|
||||
{
|
||||
Id = collection.Id;
|
||||
Name = collection.Name?.Decrypt(collection.OrganizationId);
|
||||
Collection = true;
|
||||
CipherCount = count;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; } = AppResources.FolderNone;
|
||||
public int CipherCount { get; set; }
|
||||
public bool Folder { get; set; }
|
||||
public bool Collection { get; set; }
|
||||
}
|
||||
|
||||
public class AutofillGrouping : List<AutofillCipher>
|
||||
{
|
||||
public AutofillGrouping(List<AutofillCipher> logins, string name)
|
||||
|
@ -13,7 +13,7 @@ namespace Bit.App.Pages
|
||||
|
||||
var settingsNavigation = new ExtendedNavigationPage(new SettingsPage());
|
||||
var favoritesNavigation = new ExtendedNavigationPage(new VaultListCiphersPage(true));
|
||||
var vaultNavigation = new ExtendedNavigationPage(new VaultListCiphersPage(false));
|
||||
var vaultNavigation = new ExtendedNavigationPage(new VaultListGroupingsPage());
|
||||
var toolsNavigation = new ExtendedNavigationPage(new ToolsPage());
|
||||
|
||||
favoritesNavigation.Icon = "star.png";
|
||||
|
@ -99,7 +99,8 @@ namespace Bit.App.Pages
|
||||
IsGroupingEnabled = true,
|
||||
ItemsSource = PresentationCiphersGroup,
|
||||
HasUnevenRows = true,
|
||||
GroupHeaderTemplate = new DataTemplate(() => new HeaderViewCell()),
|
||||
GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(
|
||||
nameof(VaultListPageModel.AutofillGrouping.Name))),
|
||||
ItemTemplate = new DataTemplate(() => new VaultListViewCell(
|
||||
(VaultListPageModel.Cipher l) => MoreClickedAsync(l)))
|
||||
};
|
||||
@ -359,29 +360,5 @@ namespace Bit.App.Pages
|
||||
TimeSpan.FromSeconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
private class HeaderViewCell : ExtendedViewCell
|
||||
{
|
||||
public HeaderViewCell()
|
||||
{
|
||||
var label = new Label
|
||||
{
|
||||
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
|
||||
Style = (Style)Application.Current.Resources["text-muted"],
|
||||
VerticalTextAlignment = TextAlignment.Center
|
||||
};
|
||||
|
||||
label.SetBinding(Label.TextProperty, nameof(VaultListPageModel.AutofillGrouping.Name));
|
||||
|
||||
var grid = new ContentView
|
||||
{
|
||||
Padding = new Thickness(16, 8, 0, 8),
|
||||
Content = label
|
||||
};
|
||||
|
||||
View = grid;
|
||||
BackgroundColor = Color.FromHex("efeff4");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
296
src/App/Pages/Vault/VaultListGroupingsPage.cs
Normal file
@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Acr.UserDialogs;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Models.Page;
|
||||
using Bit.App.Resources;
|
||||
using Xamarin.Forms;
|
||||
using XLabs.Ioc;
|
||||
using Bit.App.Utilities;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Bit.App.Enums;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public class VaultListGroupingsPage : ExtendedContentPage
|
||||
{
|
||||
private readonly IFolderService _folderService;
|
||||
private readonly ICollectionService _collectionService;
|
||||
private readonly ICipherService _cipherService;
|
||||
private readonly IUserDialogs _userDialogs;
|
||||
private readonly IConnectivity _connectivity;
|
||||
private readonly IDeviceActionService _deviceActionService;
|
||||
private readonly ISyncService _syncService;
|
||||
private readonly IPushNotificationService _pushNotification;
|
||||
private readonly IDeviceInfoService _deviceInfoService;
|
||||
private readonly ISettings _settings;
|
||||
private readonly IAppSettingsService _appSettingsService;
|
||||
private readonly IGoogleAnalyticsService _googleAnalyticsService;
|
||||
private CancellationTokenSource _filterResultsCancellationTokenSource;
|
||||
|
||||
public VaultListGroupingsPage()
|
||||
: base(true)
|
||||
{
|
||||
_folderService = Resolver.Resolve<IFolderService>();
|
||||
_collectionService = Resolver.Resolve<ICollectionService>();
|
||||
_cipherService = Resolver.Resolve<ICipherService>();
|
||||
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||
_syncService = Resolver.Resolve<ISyncService>();
|
||||
_pushNotification = Resolver.Resolve<IPushNotificationService>();
|
||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||
_settings = Resolver.Resolve<ISettings>();
|
||||
_appSettingsService = Resolver.Resolve<IAppSettingsService>();
|
||||
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
public ExtendedObservableCollection<VaultListPageModel.Section> PresentationSections { get; private set; }
|
||||
= new ExtendedObservableCollection<VaultListPageModel.Section>();
|
||||
public ListView ListView { get; set; }
|
||||
public SearchBar Search { get; set; }
|
||||
public StackLayout NoDataStackLayout { get; set; }
|
||||
public StackLayout ResultsStackLayout { get; set; }
|
||||
public ActivityIndicator LoadingIndicator { get; set; }
|
||||
private AddCipherToolBarItem AddCipherItem { get; set; }
|
||||
|
||||
private void Init()
|
||||
{
|
||||
AddCipherItem = new AddCipherToolBarItem(this);
|
||||
ToolbarItems.Add(AddCipherItem);
|
||||
|
||||
ListView = new ListView(ListViewCachingStrategy.RecycleElement)
|
||||
{
|
||||
IsGroupingEnabled = true,
|
||||
ItemsSource = PresentationSections,
|
||||
HasUnevenRows = true,
|
||||
GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(
|
||||
nameof(VaultListPageModel.Section.Name), nameof(VaultListPageModel.Section.ItemCount),
|
||||
new Thickness(16, Helpers.OnPlatform(20, 12, 12), 16, 12))),
|
||||
ItemTemplate = new DataTemplate(() => new VaultGroupingViewCell())
|
||||
};
|
||||
|
||||
if(Device.RuntimePlatform == Device.iOS)
|
||||
{
|
||||
ListView.RowHeight = -1;
|
||||
}
|
||||
|
||||
Search = new SearchBar
|
||||
{
|
||||
Placeholder = AppResources.SearchVault,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Button)),
|
||||
CancelButtonColor = Color.FromHex("3c8dbc")
|
||||
};
|
||||
// Bug with searchbar on android 7, ref https://bugzilla.xamarin.com/show_bug.cgi?id=43975
|
||||
if(Device.RuntimePlatform == Device.Android && _deviceInfoService.Version >= 24)
|
||||
{
|
||||
Search.HeightRequest = 50;
|
||||
}
|
||||
|
||||
Title = AppResources.MyVault;
|
||||
|
||||
ResultsStackLayout = new StackLayout
|
||||
{
|
||||
Children = { Search, ListView },
|
||||
Spacing = 0
|
||||
};
|
||||
|
||||
var noDataLabel = new Label
|
||||
{
|
||||
Text = AppResources.NoItems,
|
||||
HorizontalTextAlignment = TextAlignment.Center,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
|
||||
Style = (Style)Application.Current.Resources["text-muted"]
|
||||
};
|
||||
|
||||
NoDataStackLayout = new StackLayout
|
||||
{
|
||||
Children = { noDataLabel },
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
||||
Padding = new Thickness(20, 0),
|
||||
Spacing = 20
|
||||
};
|
||||
|
||||
var addCipherButton = new ExtendedButton
|
||||
{
|
||||
Text = AppResources.AddAnItem,
|
||||
Command = new Command(() => AddCipher()),
|
||||
Style = (Style)Application.Current.Resources["btn-primaryAccent"]
|
||||
};
|
||||
|
||||
NoDataStackLayout.Children.Add(addCipherButton);
|
||||
|
||||
LoadingIndicator = new ActivityIndicator
|
||||
{
|
||||
IsRunning = true,
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
||||
HorizontalOptions = LayoutOptions.Center
|
||||
};
|
||||
|
||||
Content = LoadingIndicator;
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
MessagingCenter.Subscribe<ISyncService, bool>(_syncService, "SyncCompleted", (sender, success) =>
|
||||
{
|
||||
if(success)
|
||||
{
|
||||
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
||||
}
|
||||
});
|
||||
|
||||
ListView.ItemSelected += GroupingSelected;
|
||||
//Search.TextChanged += SearchBar_TextChanged;
|
||||
//Search.SearchButtonPressed += SearchBar_SearchButtonPressed;
|
||||
AddCipherItem?.InitEvents();
|
||||
|
||||
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
||||
}
|
||||
|
||||
protected override void OnDisappearing()
|
||||
{
|
||||
base.OnDisappearing();
|
||||
MessagingCenter.Unsubscribe<ISyncService, bool>(_syncService, "SyncCompleted");
|
||||
|
||||
ListView.ItemSelected -= GroupingSelected;
|
||||
//Search.TextChanged -= SearchBar_TextChanged;
|
||||
//Search.SearchButtonPressed -= SearchBar_SearchButtonPressed;
|
||||
AddCipherItem?.Dispose();
|
||||
}
|
||||
|
||||
private void AdjustContent()
|
||||
{
|
||||
if(PresentationSections.Count > 0 || !string.IsNullOrWhiteSpace(Search.Text))
|
||||
{
|
||||
Content = ResultsStackLayout;
|
||||
}
|
||||
else
|
||||
{
|
||||
Content = NoDataStackLayout;
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationTokenSource FetchAndLoadVault()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
_filterResultsCancellationTokenSource?.Cancel();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var sections = new List<VaultListPageModel.Section>();
|
||||
var ciphers = await _cipherService.GetAllAsync();
|
||||
var collectionsDict = (await _collectionService.GetAllCipherAssociationsAsync())
|
||||
.GroupBy(c => c.Item2).ToDictionary(g => g.Key, v => v.ToList());
|
||||
|
||||
var folderCounts = new Dictionary<string, int> { ["none"] = 0 };
|
||||
foreach(var cipher in ciphers)
|
||||
{
|
||||
if(cipher.FolderId != null)
|
||||
{
|
||||
if(!folderCounts.ContainsKey(cipher.FolderId))
|
||||
{
|
||||
folderCounts.Add(cipher.FolderId, 0);
|
||||
}
|
||||
folderCounts[cipher.FolderId]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
folderCounts["none"]++;
|
||||
}
|
||||
}
|
||||
|
||||
var folders = await _folderService.GetAllAsync();
|
||||
var folderGroupings = folders?
|
||||
.Select(f => new VaultListPageModel.Grouping(f, folderCounts.ContainsKey(f.Id) ? folderCounts[f.Id] : 0))
|
||||
.OrderBy(g => g.Name).ToList();
|
||||
folderGroupings.Add(new VaultListPageModel.Grouping(AppResources.FolderNone, folderCounts["none"]));
|
||||
if(folderGroupings?.Any() ?? false)
|
||||
{
|
||||
sections.Add(new VaultListPageModel.Section(folderGroupings, AppResources.Folders));
|
||||
}
|
||||
|
||||
var collections = await _collectionService.GetAllAsync();
|
||||
var collectionGroupings = collections?
|
||||
.Select(c => new VaultListPageModel.Grouping(c,
|
||||
collectionsDict.ContainsKey(c.Id) ? collectionsDict[c.Id].Count() : 0))
|
||||
.OrderBy(g => g.Name).ToList();
|
||||
if(collectionGroupings?.Any() ?? false)
|
||||
{
|
||||
sections.Add(new VaultListPageModel.Section(collectionGroupings, AppResources.Collections));
|
||||
}
|
||||
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
if(sections.Any())
|
||||
{
|
||||
PresentationSections.ResetWithRange(sections);
|
||||
}
|
||||
|
||||
AdjustContent();
|
||||
});
|
||||
}, cts.Token);
|
||||
|
||||
return cts;
|
||||
}
|
||||
|
||||
private void GroupingSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
{
|
||||
var grouping = e.SelectedItem as VaultListPageModel.Grouping;
|
||||
if(grouping == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
((ListView)sender).SelectedItem = null;
|
||||
}
|
||||
|
||||
private async void AddCipher()
|
||||
{
|
||||
var type = await _userDialogs.ActionSheetAsync(AppResources.SelectTypeAdd, AppResources.Cancel, null, null,
|
||||
AppResources.TypeLogin, AppResources.TypeCard, AppResources.TypeIdentity, AppResources.TypeSecureNote);
|
||||
|
||||
var selectedType = CipherType.SecureNote;
|
||||
if(type == AppResources.Cancel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if(type == AppResources.TypeLogin)
|
||||
{
|
||||
selectedType = CipherType.Login;
|
||||
}
|
||||
else if(type == AppResources.TypeCard)
|
||||
{
|
||||
selectedType = CipherType.Card;
|
||||
}
|
||||
else if(type == AppResources.TypeIdentity)
|
||||
{
|
||||
selectedType = CipherType.Identity;
|
||||
}
|
||||
|
||||
var page = new VaultAddCipherPage(selectedType);
|
||||
await Navigation.PushForDeviceAsync(page);
|
||||
}
|
||||
|
||||
private class AddCipherToolBarItem : ExtendedToolbarItem
|
||||
{
|
||||
private readonly VaultListGroupingsPage _page;
|
||||
|
||||
public AddCipherToolBarItem(VaultListGroupingsPage page)
|
||||
: base(() => page.AddCipher())
|
||||
{
|
||||
_page = page;
|
||||
Text = AppResources.Add;
|
||||
Icon = "plus.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
src/App/Resources/AppResources.Designer.cs
generated
@ -673,6 +673,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Collections.
|
||||
/// </summary>
|
||||
public static string Collections {
|
||||
get {
|
||||
return ResourceManager.GetString("Collections", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Coming Soon!.
|
||||
/// </summary>
|
||||
|
@ -1194,4 +1194,7 @@
|
||||
<data name="GoToMyVault" xml:space="preserve">
|
||||
<value>Go to my vault</value>
|
||||
</data>
|
||||
<data name="Collections" xml:space="preserve">
|
||||
<value>Collections</value>
|
||||
</data>
|
||||
</root>
|
52
src/App/Services/CollectionService.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models;
|
||||
|
||||
namespace Bit.App.Services
|
||||
{
|
||||
public class CollectionService : ICollectionService
|
||||
{
|
||||
private readonly ICollectionRepository _collectionRepository;
|
||||
private readonly ICipherCollectionRepository _cipherCollectionRepository;
|
||||
private readonly IAuthService _authService;
|
||||
|
||||
public CollectionService(
|
||||
ICollectionRepository collectionRepository,
|
||||
ICipherCollectionRepository cipherCollectionRepository,
|
||||
IAuthService authService)
|
||||
{
|
||||
_collectionRepository = collectionRepository;
|
||||
_cipherCollectionRepository = cipherCollectionRepository;
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
public async Task<Collection> GetByIdAsync(string id)
|
||||
{
|
||||
var data = await _collectionRepository.GetByIdAsync(id);
|
||||
if(data == null || data.UserId != _authService.UserId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var collection = new Collection(data);
|
||||
return collection;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Collection>> GetAllAsync()
|
||||
{
|
||||
var data = await _collectionRepository.GetAllByUserIdAsync(_authService.UserId);
|
||||
var collections = data.Select(c => new Collection(c));
|
||||
return collections;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Tuple<string, string>>> GetAllCipherAssociationsAsync()
|
||||
{
|
||||
var data = await _cipherCollectionRepository.GetAllByUserIdAsync(_authService.UserId);
|
||||
var assocs = data.Select(cc => new Tuple<string, string>(cc.CipherId, cc.CollectionId));
|
||||
return assocs;
|
||||
}
|
||||
}
|
||||
}
|
@ -277,6 +277,7 @@ namespace Bit.iOS.Extension
|
||||
container.RegisterSingleton<IKeyDerivationService, CommonCryptoKeyDerivationService>();
|
||||
container.RegisterSingleton<IAuthService, AuthService>();
|
||||
container.RegisterSingleton<IFolderService, FolderService>();
|
||||
container.RegisterSingleton<ICollectionService, CollectionService>();
|
||||
container.RegisterSingleton<ICipherService, CipherService>();
|
||||
container.RegisterSingleton<ISyncService, SyncService>();
|
||||
container.RegisterSingleton<IPasswordGenerationService, PasswordGenerationService>();
|
||||
|
@ -255,6 +255,7 @@ namespace Bit.iOS
|
||||
container.RegisterSingleton<IKeyDerivationService, CommonCryptoKeyDerivationService>();
|
||||
container.RegisterSingleton<IAuthService, AuthService>();
|
||||
container.RegisterSingleton<IFolderService, FolderService>();
|
||||
container.RegisterSingleton<ICollectionService, CollectionService>();
|
||||
container.RegisterSingleton<ICipherService, CipherService>();
|
||||
container.RegisterSingleton<ISyncService, SyncService>();
|
||||
container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
|
||||
|
BIN
src/iOS/Resources/cube.png
Normal file
After Width: | Height: | Size: 533 B |
BIN
src/iOS/Resources/cube@2x.png
Normal file
After Width: | Height: | Size: 941 B |
BIN
src/iOS/Resources/cube@3x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -817,6 +817,15 @@
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\note%403x.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\cube.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\cube%402x.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\cube%403x.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
|