WIP: [ios] Undo for the bookmark and tracks deletion #8263

Closed
kirylkaveryn wants to merge 5 commits from ios/undo-for-the-bookmark-deletion into master
18 changed files with 424 additions and 62 deletions

View file

@ -143,6 +143,12 @@ NS_SWIFT_NAME(BookmarksManager)
- (void)moveTrack:(MWMTrackID)trackId
toGroupId:(MWMMarkGroupID)groupId;
- (void)recoverBookmark:(MWMMarkID)bookmarkId;
- (void)recoverTrack:(MWMTrackID)trackId;
- (void)removeBookmarkFromRecentlyDeleted:(MWMMarkID)bookmarkId;
- (void)removeTrackFromRecentlyDeleted:(MWMTrackID)trackId;
- (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

@ -191,6 +191,13 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
self.bm.SetAsyncLoadingCallbacks(std::move(bookmarkCallbacks));
}
- (void)notifyObserversOnCategoryUpdated:(MWMMarkGroupID)groupId {
[self loopObservers:^(id<MWMBookmarksObserver> observer) {
if ([observer respondsToSelector:@selector(onBookmarksCategoryUpdated:)])
[observer onBookmarksCategoryUpdated:groupId];
}];
}
#pragma mark - Bookmarks loading
- (BOOL)areBookmarksLoaded
@ -489,15 +496,17 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
- (void)deleteBookmark:(MWMMarkID)bookmarkId
{
auto const groupId = self.bm.GetBookmark(bookmarkId)->GetGroupId();
self.bm.GetEditSession().DeleteBookmark(bookmarkId);
[self loopObservers:^(id<MWMBookmarksObserver> observer) {
if ([observer respondsToSelector:@selector(onBookmarkDeleted:)])
[observer onBookmarkDeleted:bookmarkId];
}];
if (self.bm.HasBmCategory(groupId))
[self notifyObserversOnCategoryUpdated:groupId];
}
- (void)deleteTrack:(MWMTrackID)trackId {
auto const groupId = self.bm.GetTrack(trackId)->GetGroupId();
self.bm.GetEditSession().DeleteTrack(trackId);
if (self.bm.HasBmCategory(groupId))
[self notifyObserversOnCategoryUpdated:groupId];
}
- (MWMBookmark *)bookmarkWithId:(MWMMarkID)bookmarkId {
@ -698,6 +707,10 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
bookmark->SetDescription(description.UTF8String);
if (title.UTF8String != bookmark->GetPreferredName())
bookmark->SetCustomName(title.UTF8String);
[self notifyObserversOnCategoryUpdated:groupId];
if (currentGroupId != groupId)
[self notifyObserversOnCategoryUpdated:currentGroupId];
}
- (void)updateBookmark:(MWMMarkID)bookmarkId setColor:(MWMBookmarkColor)color {
@ -711,6 +724,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
self.bm.SetLastEditedBmColor(kmlColor);
bookmark->SetColor(kmlColor);
[self notifyObserversOnCategoryUpdated:bookmark->GetGroupId()];
}
- (void)moveBookmark:(MWMMarkID)bookmarkId toGroupId:(MWMMarkGroupID)groupId {
@ -720,6 +735,32 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
auto editSession = self.bm.GetEditSession();
editSession.MoveBookmark(bookmarkId, currentGroupId, groupId);
}
[self notifyObserversOnCategoryUpdated:groupId];
if (currentGroupId != groupId)
[self notifyObserversOnCategoryUpdated:currentGroupId];
}
- (void)recoverBookmark:(MWMMarkID)bookmarkId {
Bookmark * bookmark = self.bm.GetEditSession().RecoverRecentlyDeletedBookmark(bookmarkId);
if (bookmark)
[self notifyObserversOnCategoryUpdated:bookmark->GetGroupId()];
}
- (void)removeBookmarkFromRecentlyDeleted:(MWMMarkID)bookmarkId
{
self.bm.RemoveBookmarkFromRecentlyDeleted(bookmarkId);
}
- (void)recoverTrack:(MWMTrackID)trackId {
Track * track = self.bm.GetEditSession().RecoverRecentlyDeletedTrack(trackId);
if (track)
[self notifyObserversOnCategoryUpdated:track->GetGroupId()];
}
- (void)removeTrackFromRecentlyDeleted:(MWMTrackID)trackId
{
self.bm.RemoveTrackFromRecentlyDeleted(trackId);
}
- (void)updateTrack:(MWMTrackID)trackId
@ -742,6 +783,10 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
track->SetColor(newColor);
track->SetName(title.UTF8String);
[self notifyObserversOnCategoryUpdated:groupId];
if (currentGroupId != groupId)
[self notifyObserversOnCategoryUpdated:currentGroupId];
}
- (void)updateTrack:(MWMTrackID)trackId setColor:(UIColor *)color {
@ -755,6 +800,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
if (newColor != currentColor)
track->SetColor(newColor);
[self notifyObserversOnCategoryUpdated:track->GetGroupId()];
}
- (void)moveTrack:(MWMTrackID)trackId toGroupId:(MWMMarkGroupID)groupId {
@ -764,6 +811,10 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
auto editSession = self.bm.GetEditSession();
editSession.MoveTrack(trackId, currentGroupId, groupId);
}
[self notifyObserversOnCategoryUpdated:groupId];
if (currentGroupId != groupId)
[self notifyObserversOnCategoryUpdated:currentGroupId];
}
- (void)setCategory:(MWMMarkGroupID)groupId authorType:(MWMBookmarkGroupAuthorType)author

View file

@ -9,6 +9,7 @@ NS_SWIFT_NAME(BookmarksObserver)
- (void)onBookmarksLoadFinished;
- (void)onBookmarksFileLoadSuccess;
- (void)onBookmarksFileLoadError;
- (void)onBookmarksCategoryUpdated:(MWMMarkGroupID)groupId;
- (void)onBookmarksCategoryDeleted:(MWMMarkGroupID)groupId;
- (void)onBookmarkDeleted:(MWMMarkID)bookmarkId;

View file

@ -121,14 +121,32 @@ extension BookmarksListInteractor: IBookmarksListInteractor {
return BookmarksListSortingType(bookmarksManager.lastSortingType(markGroupId))
}
func deleteBookmark(_ bookmarkId: MWMMarkID) {
func deleteBookmark(_ bookmarkId: MWMMarkID, completion: (Bookmark) -> Void) {
completion(bookmarksManager.bookmark(withId: bookmarkId))
bookmarksManager.deleteBookmark(bookmarkId)
}
func deleteTrack(_ trackId: MWMTrackID) {
func deleteTrack(_ trackId: MWMTrackID, completion: (Track) -> Void) {
completion(bookmarksManager.track(withId: trackId))
bookmarksManager.deleteTrack(trackId)
}
func recoverBookmark(_ bookmarkId: MWMMarkID) {
bookmarksManager.recoverBookmark(bookmarkId)
}
func recoverTrack(_ trackId: MWMTrackID) {
bookmarksManager.recoverTrack(trackId)
}
func removeBookmarkFromRecentlyDeleted(_ bookmarkId: MWMMarkID) {
bookmarksManager.removeBookmark(fromRecentlyDeleted: bookmarkId)
}
func removeTrackFromRecentlyDeleted(_ trackId: MWMTrackID) {
bookmarksManager.removeTrack(fromRecentlyDeleted: trackId)
}
func moveBookmark(_ bookmarkId: MWMMarkID, toGroupId groupId: MWMMarkGroupID) {
bookmarksManager.moveBookmark(bookmarkId, toGroupId: groupId)
}
@ -183,4 +201,9 @@ extension BookmarksListInteractor: BookmarksObserver {
func onBookmarksCategoryDeleted(_ groupId: MWMMarkGroupID) {
reloadCategory()
}
func onBookmarksCategoryUpdated(_ groupId: MWMMarkGroupID) {
guard groupId == markGroupId else { return }
reloadCategory()
}
}

View file

@ -110,8 +110,12 @@ protocol IBookmarksListInteractor {
completion: @escaping ([BookmarksSection]) -> Void)
func resetSort()
func lastSortingType() -> BookmarksListSortingType?
func deleteBookmark(_ bookmarkId: MWMMarkID)
func deleteTrack(_ trackId: MWMTrackID)
func deleteBookmark(_ bookmarkId: MWMMarkID, completion: (Bookmark) -> Void)
func deleteTrack(_ trackId: MWMTrackID, completion: (Track) -> Void)
func recoverBookmark(_ bookmarkId: MWMMarkID)
func recoverTrack(_ trackId: MWMTrackID)
func removeBookmarkFromRecentlyDeleted(_ bookmarkId: MWMMarkID)
func removeTrackFromRecentlyDeleted(_ trackId: MWMTrackID)
func moveBookmark(_ bookmarkId: MWMMarkID, toGroupId: MWMMarkGroupID)
func moveTrack(_ trackId: MWMTrackID, toGroupId: MWMMarkGroupID)
func updateBookmark(_ bookmarkId: MWMMarkID, setGroupId groupId: MWMMarkGroupID, title: String, color: BookmarkColor, description: String)

View file

@ -273,11 +273,29 @@ extension BookmarksListPresenter: IBookmarksListPresenter {
switch section {
case let bookmarksSection as IBookmarksSectionViewModel:
guard let bookmark = bookmarksSection.bookmarks[index] as? BookmarkViewModel else { fatalError() }
interactor.deleteBookmark(bookmark.bookmarkId)
interactor.deleteBookmark(bookmark.bookmarkId) { bookmark in
// TODO: localize texts
Toast.undoToast(deletedObject: bookmark.bookmarkName,
undoAction: { [weak self, interactor] in
interactor.recoverBookmark(bookmark.bookmarkId)
self?.reload()
}, onHideCompletion: { [interactor] in
interactor.removeBookmarkFromRecentlyDeleted(bookmark.bookmarkId)
}).show()
}
reload()
case let tracksSection as ITracksSectionViewModel:
guard let track = tracksSection.tracks[index] as? TrackViewModel else { fatalError() }
interactor.deleteTrack(track.trackId)
interactor.deleteTrack(track.trackId) { track in
// TODO: localize texts
Toast.undoToast(deletedObject: track.trackName,
undoAction: { [weak self, interactor] in
interactor.recoverTrack(track.trackId)
self?.reload()
}, onHideCompletion: { [interactor] in
interactor.removeTrackFromRecentlyDeleted(track.trackId)
}).show()
}
reload()
default:
fatalError("Cannot delete item: unsupported section type: \(section.self)")

View file

@ -185,6 +185,10 @@ extension BMCViewController: BMCView {
}
}
}
func isVisible() -> Bool {
isViewLoaded && view.window != nil
}
}
extension BMCViewController: UITableViewDataSource {

View file

@ -3,6 +3,7 @@ protocol BMCView: AnyObject {
func delete(at indexPaths: [IndexPath])
func insert(at indexPaths: [IndexPath])
func conversionFinished(success: Bool)
func isVisible() -> Bool
}
final class BMCDefaultViewModel: NSObject {
@ -169,10 +170,12 @@ extension BMCDefaultViewModel: BookmarksObserver {
}
func onBookmarksCategoryDeleted(_ groupId: MWMMarkGroupID) {
guard let view, view.isVisible() else { return }
reloadData()
}
func onBookmarkDeleted(_: MWMMarkID) {
func onBookmarksCategoryUpdated(_ groupId: MWMMarkGroupID) {
guard let view, view.isVisible() else { return }
reloadData()
}
}

View file

@ -1,62 +1,53 @@
@objc(MWMToast)
final class Toast: NSObject {
class Toast: NSObject {
@objc(MWMToastAlignment)
enum Alignment: Int {
case bottom
case top
}
private var blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
private var timer: Timer?
private static let duration: TimeInterval = 3.0
private static var toasts: [Toast] = []
@objc static func toast(withText text: String) -> Toast {
let toast = Toast(text)
toasts.append(toast)
return toast
private let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
private var timer: Timer?
var contentView: UIView { blurView.contentView }
var onHideCompletion: (() -> Void)?
override init() {
super.init()
setupBlurView()
Self.toasts.append(self)
}
@objc static func hideAll() {
toasts.forEach { $0.hide() }
}
private init(_ text: String) {
private func setupBlurView() {
blurView.layer.setCorner(radius: 8)
blurView.clipsToBounds = true
blurView.alpha = 0
let label = UILabel()
label.text = text
label.textAlignment = .center
label.numberOfLines = 0
label.font = .regular14()
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(label)
blurView.isUserInteractionEnabled = false
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor, constant: 8),
label.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor, constant: -8),
label.topAnchor.constraint(equalTo: blurView.contentView.topAnchor, constant: 8),
label.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor, constant: -8)
])
}
deinit {
timer?.invalidate()
}
}
// MARK: - Public methods
extension Toast {
@objc static func hideAll() {
toasts.forEach { $0.hide() }
}
@objc func show() {
show(in: UIApplication.shared.keyWindow, alignment: .bottom)
Self.hideAll()
show(in: UIApplication.shared.keyWindow, alignment: .bottom, duration: Toast.duration)
}
@objc func show(withAlignment alignment: Alignment, pinToSafeArea: Bool = true) {
show(in: UIApplication.shared.keyWindow, alignment: alignment, pinToSafeArea: pinToSafeArea)
@objc func show(withAlignment alignment: Alignment, pinToSafeArea: Bool = true, duration: TimeInterval = Toast.duration) {
show(in: UIApplication.shared.keyWindow, alignment: alignment, pinToSafeArea: pinToSafeArea, duration: duration)
}
@objc func show(in view: UIView?, alignment: Alignment, pinToSafeArea: Bool = true) {
@objc func show(in view: UIView?, alignment: Alignment, pinToSafeArea: Bool = true, duration: TimeInterval = Toast.duration) {
guard let view = view else { return }
blurView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(blurView)
@ -85,7 +76,7 @@ final class Toast: NSObject {
self.blurView.alpha = 1
}
timer = Timer.scheduledTimer(timeInterval: 3,
timer = Timer.scheduledTimer(timeInterval: duration,
target: self,
selector: #selector(hide),
userInfo: nil,
@ -96,9 +87,124 @@ final class Toast: NSObject {
timer?.invalidate()
if self.blurView.superview != nil {
UIView.animate(withDuration: kDefaultAnimationDuration,
animations: { self.blurView.alpha = 0 }) { [self] _ in
animations: { self.blurView.alpha = 0 },
completion: { [self] _ in
self.onHideCompletion?()
self.blurView.removeFromSuperview()
Self.toasts.removeAll(where: { $0 === self }) }
Self.toasts.removeAll(where: { $0 === self })
})
}
}
}
extension Toast {
@objc static func toast(withText text: String) -> Toast {
toast(withText: text, onHideCompletion: nil)
}
@objc static func toast(withText text: String, onHideCompletion: (() -> Void)? = nil) -> Toast {
DefaultToast(text, onHideCompletion: onHideCompletion)
}
@objc static func undoToast(withText text: String, undoAction: @escaping () -> Void, onHideCompletion: (() -> Void)?) -> Toast {
UndoToast(text, undoAction: undoAction, onHideCompletion: onHideCompletion)
}
@objc static func undoToast(deletedObject: String, undoAction: @escaping () -> Void, onHideCompletion: (() -> Void)? = nil) -> Toast {
// TODO: localize text
undoToast(withText: "The \(deletedObject) was deleted", undoAction: undoAction, onHideCompletion: onHideCompletion)
}
}
private final class DefaultToast: Toast {
private let messageLabel = UILabel()
fileprivate convenience init(_ text: String, onHideCompletion: (() -> Void)?) {
self.init()
self.onHideCompletion = onHideCompletion
setupMessageLabel(text)
layoutViews()
}
private func setupMessageLabel(_ text: String) {
messageLabel.text = text
messageLabel.textAlignment = .center
messageLabel.numberOfLines = 0
messageLabel.font = .regular14()
messageLabel.textColor = .white
messageLabel.isUserInteractionEnabled = false
}
private func layoutViews() {
contentView.addSubview(messageLabel)
messageLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
messageLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8),
messageLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8),
messageLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
messageLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)
])
}
}
private final class UndoToast: Toast {
private let messageLabel = UILabel()
private let undoButton = UIButton()
private var undoAction: (() -> Void)?
fileprivate convenience init(_ text: String, undoAction: @escaping () -> Void, onHideCompletion: (() -> Void)?) {
self.init()
self.undoAction = undoAction
self.onHideCompletion = onHideCompletion
setupMessageLabel(text)
setupUndoButton()
layoutViews()
}
private func setupMessageLabel(_ text: String) {
messageLabel.text = text
messageLabel.textAlignment = .center
messageLabel.numberOfLines = 0
messageLabel.font = .regular14()
messageLabel.textColor = .white
messageLabel.isUserInteractionEnabled = false
}
private func setupUndoButton() {
undoButton.setTitle(L("undo"), for: .normal)
undoButton.setTitleColor(.white, for: .normal)
undoButton.setTitleColor(.lightGray, for: .highlighted)
undoButton.titleLabel?.font = .bold17()
undoButton.backgroundColor = .clear
undoButton.addTarget(self, action: #selector(undoButtonDidTap), for: .touchUpInside)
}
@objc private func undoButtonDidTap() {
undoAction?()
hide()
}
private func layoutViews() {
contentView.addSubview(messageLabel)
contentView.addSubview(undoButton)
messageLabel.translatesAutoresizingMaskIntoConstraints = false
undoButton.translatesAutoresizingMaskIntoConstraints = false
messageLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
NSLayoutConstraint.activate([
contentView.heightAnchor.constraint(greaterThanOrEqualToConstant: 40),
messageLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 12),
messageLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
messageLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
undoButton.leadingAnchor.constraint(equalTo: messageLabel.trailingAnchor, constant: 20),
undoButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -25),
undoButton.centerYAnchor.constraint(equalTo: messageLabel.centerYAnchor),
undoButton.heightAnchor.constraint(equalToConstant: 30),
])
}
}

View file

@ -234,7 +234,14 @@ extension EditBookmarkViewController: MWMNoteCellDelegate {
extension EditBookmarkViewController: MWMButtonCellDelegate {
func cellDidPressButton(_ cell: UITableViewCell) {
BookmarksManager.shared().deleteBookmark(bookmarkId)
let bookmarkManager = BookmarksManager.shared()
bookmarkManager.deleteBookmark(bookmarkId)
Toast.undoToast(deletedObject: bookmarkTitle ?? L("bookmark"),
undoAction: { [bookmarkId] in
bookmarkManager.recoverBookmark(bookmarkId)
}, onHideCompletion: { [bookmarkId] in
bookmarkManager.removeBookmark(fromRecentlyDeleted: bookmarkId)
}).show()
if let placePageData = placePageData {
FrameworkHelper.updateAfterDeleteBookmark()
placePageData.updateBookmarkStatus()

View file

@ -186,7 +186,15 @@ extension EditTrackViewController: BookmarkTitleCellDelegate {
extension EditTrackViewController: MWMButtonCellDelegate {
func cellDidPressButton(_ cell: UITableViewCell) {
bookmarksManager.deleteTrack(trackId)
let bookmarkManager = BookmarksManager.shared()
bookmarkManager.deleteTrack(trackId)
Toast.undoToast(withText: trackTitle ?? L("track_title"),
undoAction: { [trackId] in
bookmarkManager.recoverTrack(trackId)
}, onHideCompletion: { [trackId] in
bookmarkManager.removeTrack(fromRecentlyDeleted: trackId)
}).show()
// TODO: When the PlacePage screen will be implemented it should be reloaded here (see EditBookmarkViewController).
goBack()
}
}

View file

@ -64,6 +64,13 @@ class ActionBarViewController: UIViewController {
configureButtons()
}
func setBookmarkSelected(_ isSelected: Bool) {
guard let bookmarkButton = stackView.arrangedSubviews.first(where: { ($0 as? ActionBarButton)?.type == .bookmark }) as? ActionBarButton else {
return
}
bookmarkButton.setBookmarkSelected(isSelected)
}
override func viewDidLoad() {
super.viewDidLoad()

View file

@ -47,6 +47,8 @@ NS_SWIFT_NAME(ActionBarButton)
isSelected:(BOOL)isSelected
isEnabled:(BOOL)isEnabled;
- (void)setBookmarkSelected:(BOOL)isSelected;
@end
NS_ASSUME_NONNULL_END

View file

@ -155,8 +155,6 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) {
}
- (IBAction)tap {
if (self.type == MWMActionBarButtonTypeBookmark)
[self setBookmarkSelected:!self.button.isSelected];
if (self.type == MWMActionBarButtonTypeRouteTo)
[self disableRouteToButtonHighlight];
@ -164,7 +162,10 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) {
}
- (void)setBookmarkSelected:(BOOL)isSelected {
if (isSelected)
if (self.type != MWMActionBarButtonTypeBookmark)
return;
if (!self.button.isSelected && isSelected)
[self.button.imageView startAnimating];
self.button.selected = isSelected;

View file

@ -187,6 +187,7 @@ extension PlacePageCommonLayout {
bookmarkViewController.bookmarkData = bookmarkData
isBookmark = true
}
actionBarViewController.setBookmarkSelected(isBookmark)
if let title = placePageData.previewData.title, let headerViewController = headerViewControllers.compactMap({ $0 as? PlacePageHeaderViewController }).first {
let secondaryTitle = placePageData.previewData.secondaryTitle
headerViewController.setTitle(title, secondaryTitle: secondaryTitle)
@ -195,6 +196,7 @@ extension PlacePageCommonLayout {
self.presenter?.layoutIfNeeded()
UIView.animate(withDuration: kDefaultAnimationDuration) { [unowned self] in
self.bookmarkViewController.view.isHidden = !isBookmark
self.actionBar?.placePageData = self.placePageData
self.presenter?.layoutIfNeeded()
}
}

View file

@ -187,11 +187,32 @@ using namespace storage;
- (void)removeBookmark:(PlacePageData *)data
{
auto &f = GetFramework();
f.GetBookmarkManager().GetEditSession().DeleteBookmark(data.bookmarkData.bookmarkId);
PlacePageBookmarkData * bookmarkData = data.bookmarkData;
NSString * bookmarkTitle = data.previewData.title;
[MWMBookmarksManager.sharedManager deleteBookmark:bookmarkData.bookmarkId];
[[MWMToast
undoToastWithDeletedObject:bookmarkTitle
undoAction:^{
[MWMBookmarksManager.sharedManager recoverBookmark:bookmarkData.bookmarkId];
// Skip updating PP if it's closed.
if (![self isPPShown])
return;
auto & f = GetFramework();
auto & info = f.GetCurrentPlacePageInfo();
auto buildInfo = info.GetBuildInfo();
buildInfo.m_match = place_page::BuildInfo::Match::Everything;
buildInfo.m_userMarkId = bookmarkData.bookmarkId;
f.UpdatePlacePageInfoForCurrentSelection(buildInfo);
[data updateBookmarkStatus];
}
onHideCompletion:^{
[MWMBookmarksManager.sharedManager removeBookmarkFromRecentlyDeleted:bookmarkData.bookmarkId];
}] show];
[MWMFrameworkHelper updateAfterDeleteBookmark];
[data updateBookmarkStatus];
}

View file

@ -372,15 +372,53 @@ void BookmarkManager::DeleteBookmark(kml::MarkId bmId)
ASSERT(IsBookmark(bmId), ());
auto const it = m_bookmarks.find(bmId);
CHECK(it != m_bookmarks.end(), ());
auto const groupId = it->second->GetGroupId();
auto const bookmark = it->second.get();
auto const groupId = bookmark->GetGroupId();
if (groupId != kml::kInvalidMarkGroupId)
{
AddBookmarkToRecentlyDeleted(std::move(it->second));
DetachUserMark(bmId, groupId);
}
m_changesTracker.OnDeleteMark(bmId);
m_bookmarks.erase(it);
}
void BookmarkManager::AddBookmarkToRecentlyDeleted(std::unique_ptr<Bookmark> && bookmark)
{
m_recentlyDeletedBookmarks.emplace(bookmark.get()->GetId(), std::move(bookmark));
}
void BookmarkManager::RemoveBookmarkFromRecentlyDeleted(kml::MarkId bookmarkId)
{
m_recentlyDeletedBookmarks.erase(bookmarkId);
}
Bookmark * BookmarkManager::RecoverRecentlyDeletedBookmark(kml::MarkId bookmarkId)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
auto it = m_recentlyDeletedBookmarks.find(bookmarkId);
if (it == m_recentlyDeletedBookmarks.end())
return nullptr;
auto const recentlyDeletedBookmark = it->second.get();
auto data = recentlyDeletedBookmark->GetData();
auto groupId = recentlyDeletedBookmark->GetGroupId();
if (!HasBmCategory(groupId))
groupId = LastEditedBMCategory();
auto bookmark = CreateBookmark(std::move(data));
bookmark->Attach(groupId);
auto * group = GetBmCategory(groupId);
group->AttachUserMark(bookmark->GetId());
m_changesTracker.OnAttachBookmark(bookmark->GetId(), groupId);
group->SetIsVisible(true);
RemoveBookmarkFromRecentlyDeleted(bookmarkId);
return bookmark;
}
void BookmarkManager::DetachUserMark(kml::MarkId bmId, kml::MarkGroupId catId)
{
GetGroup(catId)->DetachUserMark(bmId);
@ -456,11 +494,48 @@ void BookmarkManager::DeleteTrack(kml::TrackId trackId)
auto it = m_tracks.find(trackId);
auto const groupId = it->second->GetGroupId();
if (groupId != kml::kInvalidMarkGroupId)
{
AddTrackToRecentlyDeleted(std::move(it->second));
GetBmCategory(groupId)->DetachTrack(trackId);
}
m_changesTracker.OnDeleteLine(trackId);
m_tracks.erase(it);
}
Track * BookmarkManager::RecoverRecentlyDeletedTrack(kml::TrackId trackId)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
auto it = m_recentlyDeletedTracks.find(trackId);
if (it == m_recentlyDeletedTracks.end())
return nullptr;
auto recentlyDeletedTrack = it->second.get();
auto data = recentlyDeletedTrack->GetData();
auto groupId = recentlyDeletedTrack->GetGroupId();
if (!HasBmCategory(groupId))
groupId = LastEditedBMCategory();
auto track = CreateTrack(std::move(data));
track->Attach(groupId);
auto * group = GetBmCategory(groupId);
group->AttachTrack(trackId);
RemoveTrackFromRecentlyDeleted(trackId);
return track;
}
void BookmarkManager::AddTrackToRecentlyDeleted(std::unique_ptr<Track> && track)
{
m_recentlyDeletedTracks.emplace(track.get()->GetId(), std::move(track));
}
void BookmarkManager::RemoveTrackFromRecentlyDeleted(kml::TrackId trackId)
{
m_recentlyDeletedTracks.erase(trackId);
}
void BookmarkManager::GetDirtyGroups(kml::GroupIdSet & dirtyGroups) const
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
@ -3446,11 +3521,21 @@ Bookmark * BookmarkManager::EditSession::CreateBookmark(kml::BookmarkData && bmD
return m_bmManager.CreateBookmark(std::move(bmData), groupId);
}
Bookmark * BookmarkManager::EditSession::RecoverRecentlyDeletedBookmark(kml::MarkId bookmarkId)
{
return m_bmManager.RecoverRecentlyDeletedBookmark(bookmarkId);
}
Track * BookmarkManager::EditSession::CreateTrack(kml::TrackData && trackData)
{
return m_bmManager.CreateTrack(std::move(trackData));
}
Track * BookmarkManager::EditSession::RecoverRecentlyDeletedTrack(kml::TrackId trackId)
{
return m_bmManager.RecoverRecentlyDeletedTrack(trackId);
}
Bookmark * BookmarkManager::EditSession::GetBookmarkForEdit(kml::MarkId bmId)
{
return m_bmManager.GetBookmarkForEdit(bmId);

View file

@ -165,6 +165,9 @@ public:
void NotifyChanges();
Bookmark * RecoverRecentlyDeletedBookmark(kml::MarkId bookmarkId);
Track * RecoverRecentlyDeletedTrack(kml::TrackId trackId);
private:
BookmarkManager & m_bmManager;
};
@ -421,6 +424,9 @@ public:
bool IsCompilation(kml::MarkGroupId id) const;
kml::CompilationType GetCompilationType(kml::MarkGroupId id) const;
void RemoveBookmarkFromRecentlyDeleted(kml::MarkId bookmarkId);
void RemoveTrackFromRecentlyDeleted(kml::TrackId trackId);
private:
class MarksChangesTracker : public df::UserMarksProvider
{
@ -560,14 +566,19 @@ private:
void DetachUserMark(kml::MarkId bmId, kml::MarkGroupId catId);
void DeleteCompilations(kml::GroupIdCollection const & compilations);
Track * CreateTrack(kml::TrackData && trackData);
void AddBookmarkToRecentlyDeleted(std::unique_ptr<Bookmark> && bookmark);
Bookmark * RecoverRecentlyDeletedBookmark(kml::MarkId bookmarkId);
Track * CreateTrack(kml::TrackData && trackData);
Track * GetTrackForEdit(kml::TrackId trackId);
void AttachTrack(kml::TrackId trackId, kml::MarkGroupId groupId);
void DetachTrack(kml::TrackId trackId, kml::MarkGroupId groupId);
void DeleteTrack(kml::TrackId trackId);
void MoveTrack(kml::TrackId trackID, kml::MarkGroupId curGroupID, kml::MarkGroupId newGroupID);
void AddTrackToRecentlyDeleted(std::unique_ptr<Track> && track);
Track * RecoverRecentlyDeletedTrack(kml::TrackId trackId);
void ClearGroup(kml::MarkGroupId groupId);
void SetIsVisible(kml::MarkGroupId groupId, bool visible);
@ -751,7 +762,9 @@ private:
MarksCollection m_userMarks;
BookmarksCollection m_bookmarks;
BookmarksCollection m_recentlyDeletedBookmarks;
TracksCollection m_tracks;
TracksCollection m_recentlyDeletedTracks;
StaticMarkPoint * m_selectionMark = nullptr;
MyPositionMarkPoint * m_myPositionMark = nullptr;