mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 09:58:27 +03:00
Init HttpClient with each Api Request. Guarg agsint connectivity issues when making API calls.
This commit is contained in:
parent
a4e6f49959
commit
7d62a89a51
15 changed files with 402 additions and 172 deletions
src
Android
App
Abstractions/Repositories
App.csApp.csprojPages
Repositories
AccountsApiRepository.csApiRepository.csAuthApiRepository.csBaseApiRepository.csCipherApiRepository.csDeviceApiRepository.csFolderApiRepository.csSiteApiRepository.cs
Utilities
iOS
|
@ -10,6 +10,8 @@ using Bit.App.Abstractions;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using Plugin.Fingerprint.Abstractions;
|
using Plugin.Fingerprint.Abstractions;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
using Acr.UserDialogs;
|
||||||
|
|
||||||
namespace Bit.Android
|
namespace Bit.Android
|
||||||
{
|
{
|
||||||
|
@ -25,6 +27,8 @@ namespace Bit.Android
|
||||||
|
|
||||||
LoadApplication(new App.App(
|
LoadApplication(new App.App(
|
||||||
Resolver.Resolve<IAuthService>(),
|
Resolver.Resolve<IAuthService>(),
|
||||||
|
Resolver.Resolve<IConnectivity>(),
|
||||||
|
Resolver.Resolve<IUserDialogs>(),
|
||||||
Resolver.Resolve<IDatabaseService>(),
|
Resolver.Resolve<IDatabaseService>(),
|
||||||
Resolver.Resolve<ISyncService>(),
|
Resolver.Resolve<ISyncService>(),
|
||||||
Resolver.Resolve<IFingerprint>(),
|
Resolver.Resolve<IFingerprint>(),
|
||||||
|
|
|
@ -14,6 +14,6 @@ namespace Bit.App.Abstractions
|
||||||
Task<ApiResult<ListResponse<TResponse>>> GetAsync();
|
Task<ApiResult<ListResponse<TResponse>>> GetAsync();
|
||||||
Task<ApiResult<TResponse>> PostAsync(TRequest requestObj);
|
Task<ApiResult<TResponse>> PostAsync(TRequest requestObj);
|
||||||
Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj);
|
Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj);
|
||||||
Task<ApiResult<object>> DeleteAsync(TId id);
|
Task<ApiResult> DeleteAsync(TId id);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,12 +10,17 @@ using Plugin.Fingerprint.Abstractions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
using System.Net;
|
||||||
|
using Acr.UserDialogs;
|
||||||
|
|
||||||
namespace Bit.App
|
namespace Bit.App
|
||||||
{
|
{
|
||||||
public class App : Application
|
public class App : Application
|
||||||
{
|
{
|
||||||
private readonly IDatabaseService _databaseService;
|
private readonly IDatabaseService _databaseService;
|
||||||
|
private readonly IConnectivity _connectivity;
|
||||||
|
private readonly IUserDialogs _userDialogs;
|
||||||
private readonly ISyncService _syncService;
|
private readonly ISyncService _syncService;
|
||||||
private readonly IAuthService _authService;
|
private readonly IAuthService _authService;
|
||||||
private readonly IFingerprint _fingerprint;
|
private readonly IFingerprint _fingerprint;
|
||||||
|
@ -23,12 +28,16 @@ namespace Bit.App
|
||||||
|
|
||||||
public App(
|
public App(
|
||||||
IAuthService authService,
|
IAuthService authService,
|
||||||
|
IConnectivity connectivity,
|
||||||
|
IUserDialogs userDialogs,
|
||||||
IDatabaseService databaseService,
|
IDatabaseService databaseService,
|
||||||
ISyncService syncService,
|
ISyncService syncService,
|
||||||
IFingerprint fingerprint,
|
IFingerprint fingerprint,
|
||||||
ISettings settings)
|
ISettings settings)
|
||||||
{
|
{
|
||||||
_databaseService = databaseService;
|
_databaseService = databaseService;
|
||||||
|
_connectivity = connectivity;
|
||||||
|
_userDialogs = userDialogs;
|
||||||
_syncService = syncService;
|
_syncService = syncService;
|
||||||
_authService = authService;
|
_authService = authService;
|
||||||
_fingerprint = fingerprint;
|
_fingerprint = fingerprint;
|
||||||
|
@ -47,9 +56,36 @@ namespace Bit.App
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
|
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
|
||||||
{
|
{
|
||||||
var syncTask = _syncService.IncrementalSyncAsync();
|
|
||||||
await CheckLockAsync(args);
|
await CheckLockAsync(args);
|
||||||
await syncTask;
|
if(_connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
var attempt = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _syncService.IncrementalSyncAsync();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch(WebException)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Failed to sync.");
|
||||||
|
if(attempt >= 1)
|
||||||
|
{
|
||||||
|
await _userDialogs.AlertAsync("Unable to automatically sync.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
attempt++;
|
||||||
|
}
|
||||||
|
} while(attempt <= 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Not connected.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", async (sender, args) =>
|
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", async (sender, args) =>
|
||||||
|
@ -58,12 +94,35 @@ namespace Bit.App
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStart()
|
protected async override void OnStart()
|
||||||
{
|
{
|
||||||
// Handle when your app starts
|
// Handle when your app starts
|
||||||
var lockTask = CheckLockAsync(false);
|
await CheckLockAsync(false);
|
||||||
_databaseService.CreateTables();
|
_databaseService.CreateTables();
|
||||||
var syncTask = _syncService.FullSyncAsync();
|
if(_connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
var attempt = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _syncService.FullSyncAsync();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch(WebException)
|
||||||
|
{
|
||||||
|
if(attempt >= 1)
|
||||||
|
{
|
||||||
|
await _userDialogs.AlertAsync("Unable to automatically sync. Manual sync required.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
attempt++;
|
||||||
|
}
|
||||||
|
} while(attempt <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
Debug.WriteLine("OnStart");
|
Debug.WriteLine("OnStart");
|
||||||
}
|
}
|
||||||
|
@ -79,14 +138,14 @@ namespace Bit.App
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResume()
|
protected async override void OnResume()
|
||||||
{
|
{
|
||||||
// Handle when your app resumes
|
// Handle when your app resumes
|
||||||
Debug.WriteLine("OnResume");
|
Debug.WriteLine("OnResume");
|
||||||
|
|
||||||
if(Device.OS == TargetPlatform.Android)
|
if(Device.OS == TargetPlatform.Android)
|
||||||
{
|
{
|
||||||
var task = CheckLockAsync(false);
|
await CheckLockAsync(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lockPinPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as LockPinPage;
|
var lockPinPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as LockPinPage;
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
<Compile Include="Pages\VaultListSitesPage.cs" />
|
<Compile Include="Pages\VaultListSitesPage.cs" />
|
||||||
<Compile Include="Utilities\Extentions.cs" />
|
<Compile Include="Utilities\Extentions.cs" />
|
||||||
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
|
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
|
||||||
|
<Compile Include="Utilities\ApiHttpClient.cs" />
|
||||||
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
|
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -12,6 +12,7 @@ using XLabs.Ioc;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using PushNotification.Plugin.Abstractions;
|
using PushNotification.Plugin.Abstractions;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -20,6 +21,7 @@ namespace Bit.App.Pages
|
||||||
private readonly IFolderService _folderService;
|
private readonly IFolderService _folderService;
|
||||||
private readonly ISiteService _siteService;
|
private readonly ISiteService _siteService;
|
||||||
private readonly IUserDialogs _userDialogs;
|
private readonly IUserDialogs _userDialogs;
|
||||||
|
private readonly IConnectivity _connectivity;
|
||||||
private readonly IClipboardService _clipboardService;
|
private readonly IClipboardService _clipboardService;
|
||||||
private readonly IPushNotification _pushNotification;
|
private readonly IPushNotification _pushNotification;
|
||||||
private readonly ISettings _settings;
|
private readonly ISettings _settings;
|
||||||
|
@ -30,6 +32,7 @@ namespace Bit.App.Pages
|
||||||
_favorites = favorites;
|
_favorites = favorites;
|
||||||
_folderService = Resolver.Resolve<IFolderService>();
|
_folderService = Resolver.Resolve<IFolderService>();
|
||||||
_siteService = Resolver.Resolve<ISiteService>();
|
_siteService = Resolver.Resolve<ISiteService>();
|
||||||
|
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
_clipboardService = Resolver.Resolve<IClipboardService>();
|
_clipboardService = Resolver.Resolve<IClipboardService>();
|
||||||
_pushNotification = Resolver.Resolve<IPushNotification>();
|
_pushNotification = Resolver.Resolve<IPushNotification>();
|
||||||
|
@ -77,7 +80,7 @@ namespace Bit.App.Pages
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
LoadFoldersAsync().Wait();
|
LoadFoldersAsync().Wait();
|
||||||
|
|
||||||
if(Device.OS == TargetPlatform.iOS && !_favorites)
|
if(_connectivity.IsConnected && Device.OS == TargetPlatform.iOS && !_favorites)
|
||||||
{
|
{
|
||||||
if(!_settings.GetValueOrDefault<bool>(Constants.PushPromptShown))
|
if(!_settings.GetValueOrDefault<bool>(Constants.PushPromptShown))
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,22 +3,34 @@ using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public class AccountsApiRepository : BaseApiRepository, IAccountsApiRepository
|
public class AccountsApiRepository : BaseApiRepository, IAccountsApiRepository
|
||||||
{
|
{
|
||||||
|
public AccountsApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "accounts";
|
protected override string ApiRoute => "accounts";
|
||||||
|
|
||||||
public virtual async Task<ApiResult> PostRegisterAsync(RegisterRequest requestObj)
|
public virtual async Task<ApiResult> PostRegisterAsync(RegisterRequest requestObj)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Post,
|
Method = HttpMethod.Post,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/register")),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/register")),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync(response);
|
return await HandleErrorAsync(response);
|
||||||
|
@ -27,4 +39,5 @@ namespace Bit.App.Repositories
|
||||||
return ApiResult.Success(response.StatusCode);
|
return ApiResult.Success(response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
|
@ -13,18 +14,26 @@ namespace Bit.App.Repositories
|
||||||
where TRequest : class
|
where TRequest : class
|
||||||
where TResponse : class
|
where TResponse : class
|
||||||
{
|
{
|
||||||
public ApiRepository()
|
public ApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public virtual async Task<ApiResult<TResponse>> GetByIdAsync(TId id)
|
public virtual async Task<ApiResult<TResponse>> GetByIdAsync(TId id)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<TResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<TResponse>(response);
|
return await HandleErrorAsync<TResponse>(response);
|
||||||
|
@ -34,16 +43,24 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<ListResponse<TResponse>>> GetAsync()
|
public virtual async Task<ApiResult<ListResponse<TResponse>>> GetAsync()
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<ListResponse<TResponse>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<ListResponse<TResponse>>(response);
|
return await HandleErrorAsync<ListResponse<TResponse>>(response);
|
||||||
|
@ -53,16 +70,24 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<TResponse>>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<ListResponse<TResponse>>(responseContent);
|
||||||
return ApiResult<ListResponse<TResponse>>.Success(responseObj, response.StatusCode);
|
return ApiResult<ListResponse<TResponse>>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<TResponse>> PostAsync(TRequest requestObj)
|
public virtual async Task<ApiResult<TResponse>> PostAsync(TRequest requestObj)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<TResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Post,
|
Method = HttpMethod.Post,
|
||||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<TResponse>(response);
|
return await HandleErrorAsync<TResponse>(response);
|
||||||
|
@ -72,16 +97,24 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj)
|
public virtual async Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<TResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Put,
|
Method = HttpMethod.Put,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<TResponse>(response);
|
return await HandleErrorAsync<TResponse>(response);
|
||||||
|
@ -91,22 +124,31 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<object>> DeleteAsync(TId id)
|
public virtual async Task<ApiResult> DeleteAsync(TId id)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Delete,
|
Method = HttpMethod.Delete,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<object>(response);
|
return await HandleErrorAsync(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApiResult<object>.Success(null, response.StatusCode);
|
return ApiResult.Success(response.StatusCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,22 +4,34 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public class AuthApiRepository : BaseApiRepository, IAuthApiRepository
|
public class AuthApiRepository : BaseApiRepository, IAuthApiRepository
|
||||||
{
|
{
|
||||||
|
public AuthApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "auth";
|
protected override string ApiRoute => "auth";
|
||||||
|
|
||||||
public virtual async Task<ApiResult<TokenResponse>> PostTokenAsync(TokenRequest requestObj)
|
public virtual async Task<ApiResult<TokenResponse>> PostTokenAsync(TokenRequest requestObj)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<TokenResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Post,
|
Method = HttpMethod.Post,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<TokenResponse>(response);
|
return await HandleErrorAsync<TokenResponse>(response);
|
||||||
|
@ -29,16 +41,24 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<TokenResponse>> PostTokenTwoFactorAsync(TokenTwoFactorRequest requestObj)
|
public virtual async Task<ApiResult<TokenResponse>> PostTokenTwoFactorAsync(TokenTwoFactorRequest requestObj)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<TokenResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Post,
|
Method = HttpMethod.Post,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/token/two-factor")),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token/two-factor")),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<TokenResponse>(response);
|
return await HandleErrorAsync<TokenResponse>(response);
|
||||||
|
@ -49,4 +69,5 @@ namespace Bit.App.Repositories
|
||||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,34 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using ModernHttpClient;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public abstract class BaseApiRepository
|
public abstract class BaseApiRepository
|
||||||
{
|
{
|
||||||
public BaseApiRepository()
|
public BaseApiRepository(IConnectivity connectivity)
|
||||||
{
|
{
|
||||||
Client = new HttpClient(new NativeMessageHandler());
|
Connectivity = connectivity;
|
||||||
Client.BaseAddress = new Uri("https://api.bitwarden.com");
|
|
||||||
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual HttpClient Client { get; private set; }
|
protected IConnectivity Connectivity { get; private set; }
|
||||||
protected abstract string ApiRoute { get; }
|
protected abstract string ApiRoute { get; }
|
||||||
|
|
||||||
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
protected ApiResult HandledNotConnected()
|
||||||
|
{
|
||||||
|
return ApiResult.Failed(System.Net.HttpStatusCode.RequestTimeout, new ApiError { Message = "Not connected to the internet." });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ApiResult<T> HandledNotConnected<T>()
|
||||||
|
{
|
||||||
|
return ApiResult<T>.Failed(System.Net.HttpStatusCode.RequestTimeout, new ApiError { Message = "Not connected to the internet." });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -34,7 +41,7 @@ namespace Bit.App.Repositories
|
||||||
return ApiResult<T>.Failed(response.StatusCode, new ApiError { Message = "An unknown error has occured." });
|
return ApiResult<T>.Failed(response.StatusCode, new ApiError { Message = "An unknown error has occured." });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResult> HandleErrorAsync(HttpResponseMessage response)
|
protected async Task<ApiResult> HandleErrorAsync(HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,22 +5,34 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public class CipherApiRepository : BaseApiRepository, ICipherApiRepository
|
public class CipherApiRepository : BaseApiRepository, ICipherApiRepository
|
||||||
{
|
{
|
||||||
|
public CipherApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "ciphers";
|
protected override string ApiRoute => "ciphers";
|
||||||
|
|
||||||
public virtual async Task<ApiResult<CipherResponse>> GetByIdAsync(string id)
|
public virtual async Task<ApiResult<CipherResponse>> GetByIdAsync(string id)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<CipherResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<CipherResponse>(response);
|
return await HandleErrorAsync<CipherResponse>(response);
|
||||||
|
@ -30,16 +42,24 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<CipherResponse>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<CipherResponse>(responseContent);
|
||||||
return ApiResult<CipherResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<CipherResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<ListResponse<CipherResponse>>> GetAsync()
|
public virtual async Task<ApiResult<ListResponse<CipherResponse>>> GetAsync()
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<ListResponse<CipherResponse>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<ListResponse<CipherResponse>>(response);
|
return await HandleErrorAsync<ListResponse<CipherResponse>>(response);
|
||||||
|
@ -49,16 +69,24 @@ namespace Bit.App.Repositories
|
||||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<CipherResponse>>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<ListResponse<CipherResponse>>(responseContent);
|
||||||
return ApiResult<ListResponse<CipherResponse>>.Success(responseObj, response.StatusCode);
|
return ApiResult<ListResponse<CipherResponse>>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<CipherHistoryResponse>> GetByRevisionDateWithHistoryAsync(DateTime since)
|
public virtual async Task<ApiResult<CipherHistoryResponse>> GetByRevisionDateWithHistoryAsync(DateTime since)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<CipherHistoryResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/history", "?since=", since)),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/history", "?since=", since)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<CipherHistoryResponse>(response);
|
return await HandleErrorAsync<CipherHistoryResponse>(response);
|
||||||
|
@ -69,4 +97,5 @@ namespace Bit.App.Repositories
|
||||||
return ApiResult<CipherHistoryResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<CipherHistoryResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,22 +4,34 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public class DeviceApiRepository : ApiRepository<DeviceRequest, DeviceResponse, string>, IDeviceApiRepository
|
public class DeviceApiRepository : ApiRepository<DeviceRequest, DeviceResponse, string>, IDeviceApiRepository
|
||||||
{
|
{
|
||||||
|
public DeviceApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "devices";
|
protected override string ApiRoute => "devices";
|
||||||
|
|
||||||
public virtual async Task<ApiResult<DeviceResponse>> PutTokenAsync(string identifier, DeviceTokenRequest request)
|
public virtual async Task<ApiResult<DeviceResponse>> PutTokenAsync(string identifier, DeviceTokenRequest request)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<DeviceResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage(request)
|
var requestMessage = new TokenHttpRequestMessage(request)
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Put,
|
Method = HttpMethod.Put,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/identifier/", identifier, "/token")),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/identifier/", identifier, "/token")),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<DeviceResponse>(response);
|
return await HandleErrorAsync<DeviceResponse>(response);
|
||||||
|
@ -30,4 +42,5 @@ namespace Bit.App.Repositories
|
||||||
return ApiResult<DeviceResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<DeviceResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,22 +5,34 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public class FolderApiRepository : ApiRepository<FolderRequest, FolderResponse, string>, IFolderApiRepository
|
public class FolderApiRepository : ApiRepository<FolderRequest, FolderResponse, string>, IFolderApiRepository
|
||||||
{
|
{
|
||||||
|
public FolderApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "folders";
|
protected override string ApiRoute => "folders";
|
||||||
|
|
||||||
public virtual async Task<ApiResult<ListResponse<FolderResponse>>> GetByRevisionDateAsync(DateTime since)
|
public virtual async Task<ApiResult<ListResponse<FolderResponse>>> GetByRevisionDateAsync(DateTime since)
|
||||||
|
{
|
||||||
|
if(!Connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
return HandledNotConnected<ListResponse<FolderResponse>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var client = new ApiHttpClient())
|
||||||
{
|
{
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await Client.SendAsync(requestMessage);
|
var response = await client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return await HandleErrorAsync<ListResponse<FolderResponse>>(response);
|
return await HandleErrorAsync<ListResponse<FolderResponse>>(response);
|
||||||
|
@ -31,4 +43,5 @@ namespace Bit.App.Repositories
|
||||||
return ApiResult<ListResponse<FolderResponse>>.Success(responseObj, response.StatusCode);
|
return ApiResult<ListResponse<FolderResponse>>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,16 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public class SiteApiRepository : ApiRepository<SiteRequest, SiteResponse, string>, ISiteApiRepository
|
public class SiteApiRepository : ApiRepository<SiteRequest, SiteResponse, string>, ISiteApiRepository
|
||||||
{
|
{
|
||||||
|
public SiteApiRepository(IConnectivity connectivity)
|
||||||
|
: base(connectivity)
|
||||||
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "sites";
|
protected override string ApiRoute => "sites";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/App/Utilities/ApiHttpClient.cs
Normal file
17
src/App/Utilities/ApiHttpClient.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using ModernHttpClient;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Bit.App
|
||||||
|
{
|
||||||
|
public class ApiHttpClient : HttpClient
|
||||||
|
{
|
||||||
|
public ApiHttpClient()
|
||||||
|
: base(new NativeMessageHandler())
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri("https://api.bitwarden.com");
|
||||||
|
DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ using Bit.App;
|
||||||
using Bit.iOS.Core.Services;
|
using Bit.iOS.Core.Services;
|
||||||
using PushNotification.Plugin;
|
using PushNotification.Plugin;
|
||||||
using Plugin.DeviceInfo;
|
using Plugin.DeviceInfo;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
|
||||||
namespace Bit.iOS
|
namespace Bit.iOS
|
||||||
{
|
{
|
||||||
|
@ -43,6 +44,8 @@ namespace Bit.iOS
|
||||||
|
|
||||||
LoadApplication(new App.App(
|
LoadApplication(new App.App(
|
||||||
Resolver.Resolve<IAuthService>(),
|
Resolver.Resolve<IAuthService>(),
|
||||||
|
Resolver.Resolve<IConnectivity>(),
|
||||||
|
Resolver.Resolve<IUserDialogs>(),
|
||||||
Resolver.Resolve<IDatabaseService>(),
|
Resolver.Resolve<IDatabaseService>(),
|
||||||
Resolver.Resolve<ISyncService>(),
|
Resolver.Resolve<ISyncService>(),
|
||||||
Resolver.Resolve<IFingerprint>(),
|
Resolver.Resolve<IFingerprint>(),
|
||||||
|
|
Loading…
Reference in a new issue