Feature sync on refresh (#937)

* Added new option: Sync on refresh

* Removed unused field

* Fixed refreshing on disappearing & unnecessary codes removed

* Requested changes

* Calling storage service instead of a dedicated service function (mobile-specific)
This commit is contained in:
aaxdev 2020-08-05 19:19:27 +02:00 committed by GitHub
parent c5a71c4304
commit 3b4ef4d238
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 4338 additions and 2786 deletions

View file

@ -16,22 +16,35 @@
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" /> <ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems> </ContentPage.ToolbarItems>
<ScrollView> <ScrollView Padding="0, 0, 0, 20">
<StackLayout Spacing="10" <StackLayout Padding="0" Spacing="20">
Padding="10, 5" <StackLayout StyleClass="box">
VerticalOptions="Center" <StackLayout StyleClass="box-row, box-row-switch">
HorizontalOptions="FillAndExpand"> <Label
<Button Text="{u:I18n SyncVaultNow}" Text="{u:I18n EnableSyncOnRefresh}"
Clicked="Sync_Clicked"></Button> StyleClass="box-label, box-label-regular"
<Label StyleClass="text-muted, text-sm" HorizontalTextAlignment="Center"> HorizontalOptions="StartAndExpand" />
<Label.FormattedText> <Switch
<FormattedString> IsToggled="{Binding EnableSyncOnRefresh}"
<Span Text="{u:I18n LastSync}" /> StyleClass="box-value"
<Span Text=" " /> HorizontalOptions="End" />
<Span Text="{Binding LastSync}" /> </StackLayout>
</FormattedString> <Label
</Label.FormattedText> Text="{u:I18n EnableSyncOnRefreshDescription}"
</Label> StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout StyleClass="box">
<Button Text="{u:I18n SyncVaultNow}" Clicked="Sync_Clicked"></Button>
<Label StyleClass="text-muted, text-sm" HorizontalTextAlignment="Center">
<Label.FormattedText>
<FormattedString>
<Span Text="{u:I18n LastSync}" />
<Span Text=" " />
<Span Text="{Binding LastSync}" />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>

View file

@ -21,7 +21,7 @@ namespace Bit.App.Pages
protected async override void OnAppearing() protected async override void OnAppearing()
{ {
base.OnAppearing(); base.OnAppearing();
await _vm.SetLastSyncAsync(); await _vm.InitAsync();
} }
private async void Sync_Clicked(object sender, EventArgs e) private async void Sync_Clicked(object sender, EventArgs e)

View file

@ -1,5 +1,6 @@
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Resources; using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
@ -11,25 +12,56 @@ namespace Bit.App.Pages
{ {
private readonly IDeviceActionService _deviceActionService; private readonly IDeviceActionService _deviceActionService;
private readonly IPlatformUtilsService _platformUtilsService; private readonly IPlatformUtilsService _platformUtilsService;
private readonly IStorageService _storageService;
private readonly ISyncService _syncService; private readonly ISyncService _syncService;
private string _lastSync = "--"; private string _lastSync = "--";
private bool _inited;
private bool _syncOnRefresh;
public SyncPageViewModel() public SyncPageViewModel()
{ {
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService"); _deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService"); _platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService"); _syncService = ServiceContainer.Resolve<ISyncService>("syncService");
PageTitle = AppResources.Sync; PageTitle = AppResources.Sync;
} }
public bool EnableSyncOnRefresh
{
get => _syncOnRefresh;
set
{
if (SetProperty(ref _syncOnRefresh, value))
{
var task = UpdateSyncOnRefreshAsync();
}
}
}
public string LastSync public string LastSync
{ {
get => _lastSync; get => _lastSync;
set => SetProperty(ref _lastSync, value); set => SetProperty(ref _lastSync, value);
} }
public async Task InitAsync()
{
await SetLastSyncAsync();
EnableSyncOnRefresh = await _storageService.GetAsync<bool>(Constants.SyncOnRefreshKey);
_inited = true;
}
public async Task UpdateSyncOnRefreshAsync()
{
if (_inited)
{
await _storageService.SaveAsync(Constants.SyncOnRefreshKey, _syncOnRefresh);
}
}
public async Task SetLastSyncAsync() public async Task SetLastSyncAsync()
{ {
var last = await _syncService.GetLastSyncAsync(); var last = await _syncService.GetLastSyncAsync();

View file

@ -194,6 +194,7 @@ namespace Bit.App.Pages
base.OnDisappearing(); base.OnDisappearing();
IsBusy = false; IsBusy = false;
_broadcasterService.Unsubscribe(_pageName); _broadcasterService.Unsubscribe(_pageName);
_vm.DisableRefreshing();
} }
private async void RowSelected(object sender, SelectedItemChangedEventArgs e) private async void RowSelected(object sender, SelectedItemChangedEventArgs e)

View file

@ -27,6 +27,7 @@ namespace Bit.App.Pages
private bool _showNoData; private bool _showNoData;
private bool _showList; private bool _showList;
private bool _websiteIconsEnabled; private bool _websiteIconsEnabled;
private bool _syncRefreshing;
private string _noDataText; private string _noDataText;
private List<CipherView> _allCiphers; private List<CipherView> _allCiphers;
private Dictionary<string, int> _folderCounts = new Dictionary<string, int>(); private Dictionary<string, int> _folderCounts = new Dictionary<string, int>();
@ -44,6 +45,7 @@ namespace Bit.App.Pages
private readonly IPlatformUtilsService _platformUtilsService; private readonly IPlatformUtilsService _platformUtilsService;
private readonly IMessagingService _messagingService; private readonly IMessagingService _messagingService;
private readonly IStateService _stateService; private readonly IStateService _stateService;
private readonly IStorageService _storageService;
public GroupingsPageViewModel() public GroupingsPageViewModel()
{ {
@ -57,6 +59,7 @@ namespace Bit.App.Pages
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService"); _platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService"); _messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService"); _stateService = ServiceContainer.Resolve<IStateService>("stateService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
Loading = true; Loading = true;
PageTitle = AppResources.MyVault; PageTitle = AppResources.MyVault;
@ -94,6 +97,11 @@ namespace Bit.App.Pages
get => _refreshing; get => _refreshing;
set => SetProperty(ref _refreshing, value); set => SetProperty(ref _refreshing, value);
} }
public bool SyncRefreshing
{
get => _syncRefreshing;
set => SetProperty(ref _syncRefreshing, value);
}
public bool Loading public bool Loading
{ {
get => _loading; get => _loading;
@ -149,6 +157,13 @@ namespace Bit.App.Pages
{ {
return; return;
} }
if (await _storageService.GetAsync<bool>(Constants.SyncOnRefreshKey) && Refreshing && !SyncRefreshing)
{
SyncRefreshing = true;
await _syncService.FullSyncAsync(false);
return;
}
_doingLoad = true; _doingLoad = true;
LoadedOnce = true; LoadedOnce = true;
ShowNoData = false; ShowNoData = false;
@ -266,12 +281,18 @@ namespace Bit.App.Pages
_doingLoad = false; _doingLoad = false;
Loaded = true; Loaded = true;
Loading = false; Loading = false;
Refreshing = false;
ShowNoData = (MainPage && !HasCiphers) || !groupedItems.Any(); ShowNoData = (MainPage && !HasCiphers) || !groupedItems.Any();
ShowList = !ShowNoData; ShowList = !ShowNoData;
DisableRefreshing();
} }
} }
public void DisableRefreshing()
{
Refreshing = false;
SyncRefreshing = false;
}
public async Task SelectCipherAsync(CipherView cipher) public async Task SelectCipherAsync(CipherView cipher)
{ {
var page = new ViewPage(cipher.Id); var page = new ViewPage(cipher.Id);

File diff suppressed because it is too large Load diff

View file

@ -1674,4 +1674,10 @@
<value>Do you really want to send to the trash?</value> <value>Do you really want to send to the trash?</value>
<comment>Confirmation alert message when soft-deleting a cipher.</comment> <comment>Confirmation alert message when soft-deleting a cipher.</comment>
</data> </data>
<data name="EnableSyncOnRefresh" xml:space="preserve">
<value>Enable sync on refresh</value>
</data>
<data name="EnableSyncOnRefreshDescription" xml:space="preserve">
<value>Syncing vault with pull down gesture.</value>
</data>
</root> </root>

View file

@ -7,7 +7,6 @@ namespace Bit.Core.Abstractions
public interface ISyncService public interface ISyncService
{ {
bool SyncInProgress { get; set; } bool SyncInProgress { get; set; }
Task<bool> FullSyncAsync(bool forceSync, bool allowThrowOnError = false); Task<bool> FullSyncAsync(bool forceSync, bool allowThrowOnError = false);
Task<DateTime?> GetLastSyncAsync(); Task<DateTime?> GetLastSyncAsync();
Task SetLastSyncAsync(DateTime date); Task SetLastSyncAsync(DateTime date);

View file

@ -4,6 +4,7 @@
{ {
public const string AndroidAppProtocol = "androidapp://"; public const string AndroidAppProtocol = "androidapp://";
public const string iOSAppProtocol = "iosapp://"; public const string iOSAppProtocol = "iosapp://";
public static string SyncOnRefreshKey = "syncOnRefresh";
public static string VaultTimeoutKey = "lockOption"; public static string VaultTimeoutKey = "lockOption";
public static string VaultTimeoutActionKey = "vaultTimeoutAction"; public static string VaultTimeoutActionKey = "vaultTimeoutAction";
public static string LastActiveKey = "lastActive"; public static string LastActiveKey = "lastActive";