diff --git a/src/App/Pages/SyncPage.cs b/src/App/Pages/SyncPage.cs index d129293e9..70ac80df2 100644 --- a/src/App/Pages/SyncPage.cs +++ b/src/App/Pages/SyncPage.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Acr.UserDialogs; using Bit.App.Abstractions; +using Plugin.Connectivity.Abstractions; using Xamarin.Forms; using XLabs.Ioc; @@ -11,11 +12,13 @@ namespace Bit.App.Pages { private readonly ISyncService _syncService; private readonly IUserDialogs _userDialogs; + private readonly IConnectivity _connectivity; public SyncPage() { _syncService = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); + _connectivity = Resolver.Resolve(); Init(); } @@ -34,10 +37,21 @@ namespace Bit.App.Pages Title = "Sync"; Content = stackLayout; Icon = "fa-refresh"; + + if(!_connectivity.IsConnected) + { + AlertNoConnection(); + } } public async Task SyncAsync() { + if(!_connectivity.IsConnected) + { + AlertNoConnection(); + return; + } + _userDialogs.ShowLoading("Syncing...", MaskType.Black); var succeeded = await _syncService.SyncAsync(); _userDialogs.HideLoading(); @@ -50,5 +64,10 @@ namespace Bit.App.Pages _userDialogs.ErrorToast("Syncing failed."); } } + + public void AlertNoConnection() + { + DisplayAlert("No internet connection", "Adding a new folder required an internet connection. Please connect to the internet before continuing.", "Ok"); + } } } diff --git a/src/App/Pages/VaultAddSitePage.cs b/src/App/Pages/VaultAddSitePage.cs index 584321ec2..c7e56f3aa 100644 --- a/src/App/Pages/VaultAddSitePage.cs +++ b/src/App/Pages/VaultAddSitePage.cs @@ -6,6 +6,7 @@ using System.Text; using Acr.UserDialogs; using Bit.App.Abstractions; using Bit.App.Models; +using Plugin.Connectivity.Abstractions; using Xamarin.Forms; using XLabs.Ioc; @@ -19,6 +20,7 @@ namespace Bit.App.Pages var siteService = Resolver.Resolve(); var folderService = Resolver.Resolve(); var userDialogs = Resolver.Resolve(); + var connectivity = Resolver.Resolve(); var folders = folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt()); @@ -57,6 +59,12 @@ namespace Bit.App.Pages var saveToolBarItem = new ToolbarItem("Save", null, async () => { + if(!connectivity.IsConnected) + { + AlertNoConnection(); + return; + } + if(string.IsNullOrWhiteSpace(uriEntry.Text)) { await DisplayAlert("An error has occurred", "The Uri field is required.", "Ok"); @@ -95,6 +103,17 @@ namespace Bit.App.Pages Title = "Add Site"; Content = scrollView; ToolbarItems.Add(saveToolBarItem); + + if(!connectivity.IsConnected) + { + AlertNoConnection(); + } + } + + public void AlertNoConnection() + { + DisplayAlert("No internet connection", "Adding a new folder required an internet connection. Please connect to the internet before continuing.", "Ok"); } } } + diff --git a/src/App/Services/AuthService.cs b/src/App/Services/AuthService.cs index 988633db2..f309f466e 100644 --- a/src/App/Services/AuthService.cs +++ b/src/App/Services/AuthService.cs @@ -1,10 +1,8 @@ using System; -using System.Net.Http; using System.Text; using System.Threading.Tasks; using Bit.App.Abstractions; using Bit.App.Models.Api; -using Newtonsoft.Json; using Plugin.Settings.Abstractions; namespace Bit.App.Services diff --git a/src/App/Services/SyncService.cs b/src/App/Services/SyncService.cs index 46e05629d..0b614f168 100644 --- a/src/App/Services/SyncService.cs +++ b/src/App/Services/SyncService.cs @@ -3,43 +3,56 @@ using System.Linq; using System.Threading.Tasks; using Bit.App.Abstractions; using Bit.App.Models.Data; +using Plugin.Settings.Abstractions; namespace Bit.App.Services { public class SyncService : ISyncService { + private const string LastSyncKey = "lastSync"; + private readonly IFolderApiRepository _folderApiRepository; private readonly ISiteApiRepository _siteApiRepository; private readonly IFolderRepository _folderRepository; private readonly ISiteRepository _siteRepository; private readonly IAuthService _authService; + private readonly ISettings _settings; public SyncService( IFolderApiRepository folderApiRepository, ISiteApiRepository siteApiRepository, IFolderRepository folderRepository, ISiteRepository siteRepository, - IAuthService authService) + IAuthService authService, + ISettings settings) { _folderApiRepository = folderApiRepository; _siteApiRepository = siteApiRepository; _folderRepository = folderRepository; _siteRepository = siteRepository; _authService = authService; + _settings = settings; } public async Task SyncAsync() { - // TODO: store now in settings and only fetch from last time stored - var now = DateTime.UtcNow.AddYears(-100); + var now = DateTime.UtcNow; + var lastSync = _settings.GetValueOrDefault(LastSyncKey, now.AddYears(-100)); - var siteTask = await SyncSitesAsync(now); - var folderTask = await SyncFoldersAsync(now); + var siteTask = SyncSitesAsync(lastSync); + var folderTask = SyncFoldersAsync(lastSync); + await Task.WhenAll(siteTask, folderTask); - return siteTask && folderTask; + if(await siteTask && await folderTask && folderTask.Exception == null && siteTask.Exception == null) + { + _settings.AddOrUpdateValue(LastSyncKey, now); + return true; + } + + return false; } - private async Task SyncFoldersAsync(DateTime now) + private async Task SyncFoldersAsync(DateTime lastSync) { var folderResponse = await _folderApiRepository.GetAsync(); if(!folderResponse.Succeeded) @@ -48,12 +61,12 @@ namespace Bit.App.Services } var serverFolders = folderResponse.Result.Data; - var folders = await _folderRepository.GetAllByUserIdAsync(_authService.UserId); + var localFolders = await _folderRepository.GetAllByUserIdAsync(_authService.UserId); - foreach(var serverFolder in serverFolders.Where(f => f.RevisionDate >= now)) + foreach(var serverFolder in serverFolders.Where(f => f.RevisionDate >= lastSync)) { var data = new FolderData(serverFolder, _authService.UserId); - var existingLocalFolder = folders.SingleOrDefault(f => f.Id == serverFolder.Id); + var existingLocalFolder = localFolders.SingleOrDefault(f => f.Id == serverFolder.Id); if(existingLocalFolder == null) { await _folderRepository.InsertAsync(data); @@ -64,7 +77,7 @@ namespace Bit.App.Services } } - foreach(var folder in folders.Where(localFolder => !serverFolders.Any(serverFolder => serverFolder.Id == localFolder.Id))) + foreach(var folder in localFolders.Where(localFolder => !serverFolders.Any(serverFolder => serverFolder.Id == localFolder.Id))) { await _folderRepository.DeleteAsync(folder.Id); } @@ -72,7 +85,7 @@ namespace Bit.App.Services return true; } - private async Task SyncSitesAsync(DateTime now) + private async Task SyncSitesAsync(DateTime lastSync) { var siteResponse = await _siteApiRepository.GetAsync(); if(!siteResponse.Succeeded) @@ -81,12 +94,12 @@ namespace Bit.App.Services } var serverSites = siteResponse.Result.Data; - var sites = await _siteRepository.GetAllByUserIdAsync(_authService.UserId); + var localSites = await _siteRepository.GetAllByUserIdAsync(_authService.UserId); - foreach(var serverSite in serverSites.Where(s => s.RevisionDate >= now)) + foreach(var serverSite in serverSites.Where(s => s.RevisionDate >= lastSync)) { var data = new SiteData(serverSite, _authService.UserId); - var existingLocalSite = sites.SingleOrDefault(s => s.Id == serverSite.Id); + var existingLocalSite = localSites.SingleOrDefault(s => s.Id == serverSite.Id); if(existingLocalSite == null) { await _siteRepository.InsertAsync(data); @@ -97,7 +110,7 @@ namespace Bit.App.Services } } - foreach(var site in sites.Where(localSite => !serverSites.Any(serverSite => serverSite.Id == localSite.Id))) + foreach(var site in localSites.Where(localSite => !serverSites.Any(serverSite => serverSite.Id == localSite.Id))) { await _siteRepository.DeleteAsync(site.Id); }