[ios] Restore bookmarks

This commit is contained in:
VladiMihaylenko 2018-05-08 13:12:29 +03:00 committed by Aleksandr Zatsepin
parent 7d4d51ed1f
commit f0f3d0bd8b
13 changed files with 272 additions and 14 deletions

View file

@ -284,7 +284,8 @@ extension BMCViewController: BMCPermissionsCellDelegate {
})
case .backup:
viewModel.grant(permission: permission)
case .restore: assertionFailure()
case .restore:
viewModel.requestRestoring()
}
}
}

View file

@ -17,6 +17,7 @@ final class BMCDefaultViewModel: NSObject {
private(set) var isPendingPermission = false
private var isAuthenticated = false
private var filesPrepared = false;
private var onPreparedToShareCategory: BMCViewModel.onPreparedToShareHandler?
@ -38,7 +39,7 @@ final class BMCDefaultViewModel: NSObject {
isPendingPermission = false
permissions = [.backup]
} else {
isPendingPermission = true
isPendingPermission = false
permissions = [.restore(BM.lastSynchronizationDate())]
}
}
@ -222,9 +223,103 @@ extension BMCDefaultViewModel: BMCViewModel {
func areNotificationsEnabled() -> Bool {
return BM.areNotificationsEnabled()
}
func requestRestoring() {
BM.requestRestoring()
}
func applyRestoring() {
BM.applyRestoring()
}
func cancelRestoring() {
if filesPrepared {
return
}
BM.cancelRestoring()
}
}
extension BMCDefaultViewModel: MWMBookmarksObserver {
func onRestoringStarted() {
filesPrepared = false
MWMAlertViewController.activeAlert().presentSpinnerAlert(withTitle: L("bookmarks_restore_process"))
{ [weak self] in self?.cancelRestoring() }
}
func onRestoringFilesPrepared() {
filesPrepared = true
}
func onRestoringFinished(_ result: MWMSynchronizationResult) {
MWMAlertViewController.activeAlert().closeAlert() { [weak self] in
switch result {
case .networkError: fallthrough
case .authError:
MWMAlertViewController.activeAlert().presentDefaultAlert(withTitle: L("error_server_title"),
message: L("error_server_message"),
rightButtonTitle: L("try_again"),
leftButtonTitle: L("cancel")) {
[weak self] in
self?.requestRestoring()
}
case .diskError:
MWMAlertViewController.activeAlert().presentInternalErrorAlert()
case .userInterrupted: break
case .success:
guard let s = self else { return }
s.setCategories()
s.view.update(sections: [.categories])
}
}
}
func onRestoringRequest(_ result: MWMRestoringRequestResult, backupDate date: Date?) {
MWMAlertViewController.activeAlert().closeAlert() {
switch result {
case .noInternet: MWMAlertViewController.activeAlert().presentNoConnectionAlert()
case .backupExists:
guard let date = date else {
assertionFailure()
return
}
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
let message = String(coreFormat: L("bookmarks_message_backuped_user"),
arguments: [formatter.string(from: date)])
MWMAlertViewController.activeAlert().presentDefaultAlert(withTitle: L("bookmarks_restore_title"),
message: message,
rightButtonTitle: L("restore"),
leftButtonTitle: L("cancel"))
{ [weak self] in
MWMAlertViewController.activeAlert().presentSpinnerAlert(withTitle: L("bookmarks_restore_process")) {
[weak self] in
self?.cancelRestoring()
}
self?.applyRestoring()
}
case .noBackup:
MWMAlertViewController.activeAlert().presentDefaultAlert(withTitle: L("bookmarks_restore_empty_title"),
message: L("bookmarks_restore_empty_message"),
rightButtonTitle: L("ok"),
leftButtonTitle: nil,
rightButtonAction: nil)
case .notEnoughDiskSpace: MWMAlertViewController.activeAlert().presentNotEnoughSpaceAlert()
case .requestError: assertionFailure()
}
}
}
func onBookmarksLoadFinished() {
loadData()
convertAllKMLIfNeeded()

View file

@ -48,4 +48,8 @@ protocol BMCViewModel: AnyObject {
func setNotificationsEnabled(_ enabled: Bool)
func areNotificationsEnabled() -> Bool
func requestRestoring()
func applyRestoring()
func cancelRestoring()
}

View file

@ -30,7 +30,18 @@ final class BMCPermissionsCell: MWMTableViewCell {
case .backup:
label.text = L("bookmarks_message_authorized_user")
button.setTitle(L("bookmarks_backup").uppercased(), for: .normal)
case .restore: assertionFailure()
case let .restore(date):
if let date = date {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
label.text = String(coreFormat: L("bookmarks_message_backuped_user"),
arguments: [formatter.string(from: date)])
} else {
label.text = L("bookmarks_message_unbackuped_user")
}
button.setTitle(L("bookmarks_restore"), for: .normal)
}
}
}

View file

@ -54,6 +54,13 @@
- (void)presentSpinnerAlertWithTitle:(nonnull NSString *)title cancel:(nullable MWMVoidBlock)cancel;
- (void)presentBookmarkConversionErrorAlert;
- (void)presentDefaultAlertWithTitle:(nonnull NSString *)title
message:(nullable NSString *)message
rightButtonTitle:(nonnull NSString *)rightButtonTitle
leftButtonTitle:(nullable NSString *)leftButtonTitle
rightButtonAction:(nullable MWMVoidBlock)action;
- (void)closeAlert:(nullable MWMVoidBlock)completion;
- (nonnull instancetype)init __attribute__((unavailable("call -initWithViewController: instead!")));

View file

@ -248,6 +248,19 @@ static NSString * const kAlertControllerNibIdentifier = @"MWMAlertViewController
[self displayAlert:[MWMAlert bookmarkConversionErrorAlert]];
}
- (void)presentDefaultAlertWithTitle:(nonnull NSString *)title
message:(nullable NSString *)message
rightButtonTitle:(nonnull NSString *)rightButtonTitle
leftButtonTitle:(nullable NSString *)leftButtonTitle
rightButtonAction:(nullable MWMVoidBlock)action
{
[self displayAlert:[MWMAlert defaultAlertWithTitle:title
message:message
rightButtonTitle:rightButtonTitle
leftButtonTitle:leftButtonTitle
rightButtonAction:action]];
}
- (void)displayAlert:(MWMAlert *)alert
{
// TODO(igrechuhin): Remove this check on location manager refactoring.

View file

@ -43,6 +43,12 @@
+ (MWMAlert *)spinnerAlertWithTitle:(NSString *)title cancel:(MWMVoidBlock)cancel;
+ (MWMAlert *)bookmarkConversionErrorAlert;
+ (MWMAlert *)defaultAlertWithTitle:(NSString *)title
message:(NSString *)message
rightButtonTitle:(NSString *)rightButtonTitle
leftButtonTitle:(NSString *)leftButtonTitle
rightButtonAction:(MWMVoidBlock)action;
- (void)close:(MWMVoidBlock)completion;
- (void)setNeedsCloseAlertAfterEnterBackground;

View file

@ -185,6 +185,20 @@
return [MWMDefaultAlert bookmarkConversionErrorAlert];
}
+ (MWMAlert *)defaultAlertWithTitle:(NSString *)title
message:(NSString *)message
rightButtonTitle:(NSString *)rightButtonTitle
leftButtonTitle:(NSString *)leftButtonTitle
rightButtonAction:(MWMVoidBlock)action
{
return [MWMDefaultAlert defaultAlertWithTitle:title
message:message
rightButtonTitle:rightButtonTitle
leftButtonTitle:leftButtonTitle
rightButtonAction:action
statisticsEvent:nil];
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
// Should override this method if you want custom relayout after rotation.

View file

@ -40,4 +40,11 @@
+ (instancetype)convertBookmarksWithCount:(NSUInteger)count okBlock:(MWMVoidBlock)okBlock;
+ (instancetype)bookmarkConversionErrorAlert;
+ (instancetype)defaultAlertWithTitle:(nonnull NSString *)title
message:(nullable NSString *)message
rightButtonTitle:(nonnull NSString *)rightButtonTitle
leftButtonTitle:(nullable NSString *)leftButtonTitle
rightButtonAction:(nullable MWMVoidBlock)action
statisticsEvent:(nullable NSString *)statisticsEvent;
@end

View file

@ -40,6 +40,8 @@ static NSString * const kStatBooking = @"Booking.com";
static NSString * const kStatBookmarkCreated = @"Bookmark. Bookmark created";
static NSString * const kStatBookmarks = @"Bookmarks";
static NSString * const kStatBookmarksAuthRequestError = @"Bookmarks_SyncProposal_error";
static NSString * const kStatBookmarksRestoreProposalCancel = @"Bookmarks_RestoreProposal_cancel";
static NSString * const kStatBookmarksRestoreProposalClick = @"Bookmarks_RestoreProposal_click";
static NSString * const kStatBookmarksAuthRequestSuccess = @"Bookmarks_SyncProposal_enabled";
static NSString * const kStatBookmarksRestoreProposalError = @"Bookmarks_RestoreProposal_error";
static NSString * const kStatBookmarksRestoreProposalSuccess = @"Bookmarks_RestoreProposal_success";

View file

@ -40,6 +40,10 @@
+ (void)setNotificationsEnabled:(BOOL)enabled;
+ (BOOL)areNotificationsEnabled;
+ (void)requestRestoring;
+ (void)applyRestoring;
+ (void)cancelRestoring;
- (instancetype)init __attribute__((unavailable("call +manager instead")));
- (instancetype)copy __attribute__((unavailable("call +manager instead")));
- (instancetype)copyWithZone:(NSZone *)zone __attribute__((unavailable("call +manager instead")));

View file

@ -6,6 +6,8 @@
#include "coding/internal/file_data.hpp"
#include "base/stl_helpers.hpp"
#include <utility>
namespace
@ -132,7 +134,16 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result)
auto onSynchronizationStarted = [](Cloud::SynchronizationType type)
{
if (type == Cloud::SynchronizationType::Backup)
{
[Statistics logEvent:kStatBookmarksSyncStarted];
}
else
{
[[MWMBookmarksManager manager] loopObservers:^(Observer observer) {
if ([observer respondsToSelector:@selector(onRestoringStarted)])
[observer onRestoringStarted];
}];
}
};
auto onSynchronizationFinished = [](Cloud::SynchronizationType type, Cloud::SynchronizationResult result,
@ -143,21 +154,33 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result)
[Statistics logEvent:type == Cloud::SynchronizationType::Backup ? kStatBookmarksSyncSuccess :
kStatBookmarksRestoreProposalSuccess];
}
else
else if (auto const error = CloudErrorToString(result))
{
NSString * const errorType = CloudErrorToString(result);
if (errorType != nil)
{
[Statistics logEvent:type == Cloud::SynchronizationType::Backup ? kStatBookmarksSyncError :
kStatBookmarksRestoreProposalError
withParameters:@{kStatType: errorType, kStatError: @(errorStr.c_str())}];
}
[Statistics logEvent:type == Cloud::SynchronizationType::Backup ? kStatBookmarksSyncError :
kStatBookmarksRestoreProposalError
withParameters:@{kStatType: error, kStatError: @(errorStr.c_str())}];
}
if (type != Cloud::SynchronizationType::Restore)
return;
[[MWMBookmarksManager manager] loopObservers:^(Observer observer) {
if ([observer respondsToSelector:@selector(onRestoringFinished:)])
[observer onRestoringFinished:static_cast<MWMSynchronizationResult>(my::Key(result))];
}];
};
auto onRestoreRequested = [](Cloud::RestoringRequestResult result, uint64_t backupTimestampInMs)
{
if (result == Cloud::RestoringRequestResult::NoBackup)
auto const res = static_cast<MWMRestoringRequestResult>(my::Key(result));
NSDate * date = nil;
if (result == Cloud::RestoringRequestResult::BackupExists)
{
auto const interval = static_cast<NSTimeInterval>(backupTimestampInMs / 1000.);
date = [NSDate dateWithTimeIntervalSince1970:interval];
}
else if (result == Cloud::RestoringRequestResult::NoBackup)
{
[Statistics logEvent:kStatBookmarksRestoreProposalError
withParameters:@{kStatType: kStatNoBackup, kStatError: @("")}];
@ -167,11 +190,19 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result)
[Statistics logEvent:kStatBookmarksRestoreProposalError
withParameters:@{kStatType: kStatDisk, kStatError: @("Not enough disk space")}];
}
[[MWMBookmarksManager manager] loopObservers:^(Observer observer) {
if ([observer respondsToSelector:@selector(onRestoringRequest:backupDate:)])
[observer onRestoringRequest:res backupDate:date];
}];
};
auto onRestoredFilesPrepared = []()
auto onRestoredFilesPrepared = []
{
//TODO: On this callback we have to block cancel button in restore dialog if such button exists.
[[MWMBookmarksManager manager] loopObservers:^(Observer observer) {
if ([observer respondsToSelector:@selector(onRestoringFilesPrepared)])
[observer onRestoringFilesPrepared];
}];
};
bm.SetCloudHandlers(std::move(onSynchronizationStarted), std::move(onSynchronizationFinished),
@ -333,6 +364,47 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result)
GetFramework().GetBookmarkManager().SetCloudEnabled(enabled);
}
+ (void)requestRestoring
{
auto const status = Platform::ConnectionStatus();
auto statusStr = [](Platform::EConnectionType type) -> NSString * {
switch (type)
{
case Platform::EConnectionType::CONNECTION_NONE:
return kStatOffline;
case Platform::EConnectionType::CONNECTION_WWAN:
return kStatMobile;
case Platform::EConnectionType::CONNECTION_WIFI:
return kStatWifi;
}
} (status);
[Statistics logEvent:kStatBookmarksRestoreProposalClick
withParameters:@{kStatNetwork : statusStr}];
if (status == Platform::EConnectionType::CONNECTION_NONE)
{
[self.manager loopObservers:^(Observer observer) {
if ([observer respondsToSelector:@selector(onRestoringRequest:backupDate:)])
[observer onRestoringRequest:MWMRestoringRequestResultNoInternet backupDate:nil];
}];
return;
}
GetFramework().GetBookmarkManager().RequestCloudRestoring();
}
+ (void)applyRestoring
{
GetFramework().GetBookmarkManager().ApplyCloudRestoring();
}
+ (void)cancelRestoring
{
[Statistics logEvent:kStatBookmarksRestoreProposalCancel];
GetFramework().GetBookmarkManager().CancelCloudRestoring();
}
- (void)loopObservers:(TLoopBlock)block
{
for (Observer observer in self.observers)

View file

@ -1,10 +1,32 @@
#import "MWMTypes.h"
typedef NS_ENUM(NSUInteger, MWMRestoringRequestResult)
{
MWMRestoringRequestResultBackupExists,
MWMRestoringRequestResultNoBackup,
MWMRestoringRequestResultNotEnoughDiskSpace,
MWMRestoringRequestResultNoInternet,
MWMRestoringRequestResultRequestError
};
typedef NS_ENUM(NSUInteger, MWMSynchronizationResult)
{
MWMSynchronizationResultSuccess,
MWMSynchronizationResultAuthError,
MWMSynchronizationResultNetworkError,
MWMSynchronizationResultDiskError,
MWMSynchronizationResultUserInterrupted
};
@protocol MWMBookmarksObserver<NSObject>
- (void)onConversionFinish:(BOOL)success;
@optional
- (void)onRestoringRequest:(MWMRestoringRequestResult)result backupDate:(NSDate * _Nullable)date;
- (void)onRestoringFinished:(MWMSynchronizationResult)result;
- (void)onRestoringStarted;
- (void)onRestoringFilesPrepared;
- (void)onBookmarksLoadFinished;
- (void)onBookmarksFileLoadSuccess;
- (void)onBookmarksCategoryDeleted:(MWMMarkGroupID)groupId;