| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" | 5 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/hash.h" | 12 #include "base/hash.h" |
| 13 #include "base/i18n/string_compare.h" | 13 #include "base/i18n/string_compare.h" |
| 14 #include "base/mac/bind_objc_block.h" | 14 #include "base/mac/bind_objc_block.h" |
| 15 #include "base/mac/scoped_nsautorelease_pool.h" | |
| 16 #include "base/mac/scoped_nsobject.h" | |
| 17 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 18 #include "base/metrics/user_metrics_action.h" | 16 #include "base/metrics/user_metrics_action.h" |
| 19 #include "base/strings/sys_string_conversions.h" | 17 #include "base/strings/sys_string_conversions.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 21 #include "components/bookmarks/browser/bookmark_model.h" | 19 #include "components/bookmarks/browser/bookmark_model.h" |
| 22 #include "components/query_parser/query_parser.h" | 20 #include "components/query_parser/query_parser.h" |
| 23 #include "components/strings/grit/components_strings.h" | 21 #include "components/strings/grit/components_strings.h" |
| 24 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h" | 22 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h" |
| 25 #include "ios/chrome/browser/experimental_flags.h" | 23 #include "ios/chrome/browser/experimental_flags.h" |
| 26 #import "ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.h" | 24 #import "ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.h" |
| 27 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h" | 25 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h" |
| 28 #import "ios/chrome/browser/ui/bookmarks/bookmark_position_cache.h" | 26 #import "ios/chrome/browser/ui/bookmarks/bookmark_position_cache.h" |
| 29 #include "ios/chrome/browser/ui/bookmarks/undo_manager_wrapper.h" | 27 #include "ios/chrome/browser/ui/bookmarks/undo_manager_wrapper.h" |
| 30 #include "ios/chrome/browser/ui/ui_util.h" | 28 #include "ios/chrome/browser/ui/ui_util.h" |
| 31 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 29 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 32 #include "ios/chrome/grit/ios_strings.h" | 30 #include "ios/chrome/grit/ios_strings.h" |
| 33 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/Mat
erialSnackbar.h" | 31 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/Mat
erialSnackbar.h" |
| 34 #include "third_party/skia/include/core/SkColor.h" | 32 #include "third_party/skia/include/core/SkColor.h" |
| 35 #include "ui/base/l10n/l10n_util.h" | 33 #include "ui/base/l10n/l10n_util.h" |
| 36 #include "ui/base/l10n/l10n_util_mac.h" | 34 #include "ui/base/l10n/l10n_util_mac.h" |
| 37 #include "ui/base/models/tree_node_iterator.h" | 35 #include "ui/base/models/tree_node_iterator.h" |
| 38 | 36 |
| 37 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 38 #error "This file requires ARC support." |
| 39 #endif |
| 40 |
| 39 using bookmarks::BookmarkNode; | 41 using bookmarks::BookmarkNode; |
| 40 | 42 |
| 41 namespace bookmark_utils_ios { | 43 namespace bookmark_utils_ios { |
| 42 | 44 |
| 43 namespace { | 45 namespace { |
| 44 | 46 |
| 45 const BookmarkNode* FindFolderById(bookmarks::BookmarkModel* model, | 47 const BookmarkNode* FindFolderById(bookmarks::BookmarkModel* model, |
| 46 int64_t id) { | 48 int64_t id) { |
| 47 ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node()); | 49 ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node()); |
| 48 while (iterator.has_next()) { | 50 while (iterator.has_next()) { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 return CGRectGetWidth(statusBarWindowRect); | 182 return CGRectGetWidth(statusBarWindowRect); |
| 181 } | 183 } |
| 182 } | 184 } |
| 183 | 185 |
| 184 BOOL bookmarkMenuIsInSlideInPanel() { | 186 BOOL bookmarkMenuIsInSlideInPanel() { |
| 185 return !IsIPadIdiom() || IsCompactTablet(); | 187 return !IsIPadIdiom() || IsCompactTablet(); |
| 186 } | 188 } |
| 187 | 189 |
| 188 UIView* dropShadowWithWidth(CGFloat width) { | 190 UIView* dropShadowWithWidth(CGFloat width) { |
| 189 UIImage* shadowImage = [UIImage imageNamed:@"bookmark_bar_shadow"]; | 191 UIImage* shadowImage = [UIImage imageNamed:@"bookmark_bar_shadow"]; |
| 190 UIImageView* shadow = | 192 UIImageView* shadow = [[UIImageView alloc] initWithImage:shadowImage]; |
| 191 [[[UIImageView alloc] initWithImage:shadowImage] autorelease]; | |
| 192 CGRect shadowFrame = CGRectMake(0, 0, width, 4); | 193 CGRect shadowFrame = CGRectMake(0, 0, width, 4); |
| 193 shadow.frame = shadowFrame; | 194 shadow.frame = shadowFrame; |
| 194 shadow.autoresizingMask = | 195 shadow.autoresizingMask = |
| 195 UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; | 196 UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; |
| 196 return shadow; | 197 return shadow; |
| 197 } | 198 } |
| 198 | 199 |
| 199 #pragma mark - Updating Bookmarks | 200 #pragma mark - Updating Bookmarks |
| 200 | 201 |
| 201 // Deletes all subnodes of |node|, including |node|, that are in |bookmarks|. | 202 // Deletes all subnodes of |node|, including |node|, that are in |bookmarks|. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 218 DCHECK(!node || node->is_url()); | 219 DCHECK(!node || node->is_url()); |
| 219 base::string16 titleString = base::SysNSStringToUTF16(title); | 220 base::string16 titleString = base::SysNSStringToUTF16(title); |
| 220 | 221 |
| 221 // If the bookmark has no changes supporting Undo, just bail out. | 222 // If the bookmark has no changes supporting Undo, just bail out. |
| 222 if (node && node->GetTitle() == titleString && node->url() == url && | 223 if (node && node->GetTitle() == titleString && node->url() == url && |
| 223 node->parent() == folder) { | 224 node->parent() == folder) { |
| 224 return; | 225 return; |
| 225 } | 226 } |
| 226 | 227 |
| 227 // Secondly, create an Undo group for all undoable actions. | 228 // Secondly, create an Undo group for all undoable actions. |
| 228 base::scoped_nsobject<UndoManagerWrapper> wrapper( | 229 UndoManagerWrapper* wrapper = |
| 229 [[UndoManagerWrapper alloc] initWithBrowserState:browser_state]); | 230 [[UndoManagerWrapper alloc] initWithBrowserState:browser_state]; |
| 230 | 231 |
| 231 // Create or update the bookmark. | 232 // Create or update the bookmark. |
| 232 [wrapper startGroupingActions]; | 233 [wrapper startGroupingActions]; |
| 233 | 234 |
| 234 // Save the bookmark information. | 235 // Save the bookmark information. |
| 235 if (!node) { // Create a new bookmark. | 236 if (!node) { // Create a new bookmark. |
| 236 bookmark_model->client()->RecordAction( | 237 bookmark_model->client()->RecordAction( |
| 237 base::UserMetricsAction("BookmarkAdded")); | 238 base::UserMetricsAction("BookmarkAdded")); |
| 238 node = | 239 node = |
| 239 bookmark_model->AddURL(folder, folder->child_count(), titleString, url); | 240 bookmark_model->AddURL(folder, folder->child_count(), titleString, url); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 253 [wrapper resetUndoManagerChanged]; | 254 [wrapper resetUndoManagerChanged]; |
| 254 | 255 |
| 255 NSString* text = | 256 NSString* text = |
| 256 l10n_util::GetNSString((node) ? IDS_IOS_BOOKMARK_NEW_BOOKMARK_UPDATED | 257 l10n_util::GetNSString((node) ? IDS_IOS_BOOKMARK_NEW_BOOKMARK_UPDATED |
| 257 : IDS_IOS_BOOKMARK_NEW_BOOKMARK_CREATED); | 258 : IDS_IOS_BOOKMARK_NEW_BOOKMARK_CREATED); |
| 258 PresentUndoToastWithWrapper(wrapper, text); | 259 PresentUndoToastWithWrapper(wrapper, text); |
| 259 } | 260 } |
| 260 | 261 |
| 261 void PresentUndoToastWithWrapper(UndoManagerWrapper* wrapper, NSString* text) { | 262 void PresentUndoToastWithWrapper(UndoManagerWrapper* wrapper, NSString* text) { |
| 262 // Create the block that will be executed if the user taps the undo button. | 263 // Create the block that will be executed if the user taps the undo button. |
| 263 MDCSnackbarMessageAction* action = | 264 MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init]; |
| 264 [[[MDCSnackbarMessageAction alloc] init] autorelease]; | |
| 265 action.handler = ^{ | 265 action.handler = ^{ |
| 266 if (![wrapper hasUndoManagerChanged]) | 266 if (![wrapper hasUndoManagerChanged]) |
| 267 [wrapper undo]; | 267 [wrapper undo]; |
| 268 }; | 268 }; |
| 269 | 269 |
| 270 action.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_UNDO_BUTTON_TITLE); | 270 action.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_UNDO_BUTTON_TITLE); |
| 271 action.accessibilityIdentifier = @"Undo"; | 271 action.accessibilityIdentifier = @"Undo"; |
| 272 action.accessibilityLabel = | 272 action.accessibilityLabel = |
| 273 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_UNDO_BUTTON_TITLE); | 273 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_UNDO_BUTTON_TITLE); |
| 274 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess); | 274 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 295 if (bookmarks.find(node) != bookmarks.end()) | 295 if (bookmarks.find(node) != bookmarks.end()) |
| 296 model->Remove(node); | 296 model->Remove(node); |
| 297 } | 297 } |
| 298 | 298 |
| 299 void DeleteBookmarksWithUndoToast(const std::set<const BookmarkNode*>& nodes, | 299 void DeleteBookmarksWithUndoToast(const std::set<const BookmarkNode*>& nodes, |
| 300 bookmarks::BookmarkModel* model, | 300 bookmarks::BookmarkModel* model, |
| 301 ios::ChromeBrowserState* browser_state) { | 301 ios::ChromeBrowserState* browser_state) { |
| 302 size_t nodeCount = nodes.size(); | 302 size_t nodeCount = nodes.size(); |
| 303 DCHECK_GT(nodeCount, 0u); | 303 DCHECK_GT(nodeCount, 0u); |
| 304 | 304 |
| 305 base::scoped_nsobject<UndoManagerWrapper> wrapper( | 305 UndoManagerWrapper* wrapper = |
| 306 [[UndoManagerWrapper alloc] initWithBrowserState:browser_state]); | 306 [[UndoManagerWrapper alloc] initWithBrowserState:browser_state]; |
| 307 | 307 |
| 308 // Delete the selected bookmarks. | 308 // Delete the selected bookmarks. |
| 309 [wrapper startGroupingActions]; | 309 [wrapper startGroupingActions]; |
| 310 bookmark_utils_ios::DeleteBookmarks(nodes, model); | 310 bookmark_utils_ios::DeleteBookmarks(nodes, model); |
| 311 [wrapper stopGroupingActions]; | 311 [wrapper stopGroupingActions]; |
| 312 [wrapper resetUndoManagerChanged]; | 312 [wrapper resetUndoManagerChanged]; |
| 313 | 313 |
| 314 NSString* text = nil; | 314 NSString* text = nil; |
| 315 | 315 |
| 316 if (nodeCount == 1) { | 316 if (nodeCount == 1) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 347 return didPerformMove; | 347 return didPerformMove; |
| 348 } | 348 } |
| 349 | 349 |
| 350 void MoveBookmarksWithUndoToast(const std::set<const BookmarkNode*>& nodes, | 350 void MoveBookmarksWithUndoToast(const std::set<const BookmarkNode*>& nodes, |
| 351 bookmarks::BookmarkModel* model, | 351 bookmarks::BookmarkModel* model, |
| 352 const BookmarkNode* folder, | 352 const BookmarkNode* folder, |
| 353 ios::ChromeBrowserState* browser_state) { | 353 ios::ChromeBrowserState* browser_state) { |
| 354 size_t nodeCount = nodes.size(); | 354 size_t nodeCount = nodes.size(); |
| 355 DCHECK_GT(nodeCount, 0u); | 355 DCHECK_GT(nodeCount, 0u); |
| 356 | 356 |
| 357 base::scoped_nsobject<UndoManagerWrapper> wrapper( | 357 UndoManagerWrapper* wrapper = |
| 358 [[UndoManagerWrapper alloc] initWithBrowserState:browser_state]); | 358 [[UndoManagerWrapper alloc] initWithBrowserState:browser_state]; |
| 359 | 359 |
| 360 // Move the selected bookmarks. | 360 // Move the selected bookmarks. |
| 361 [wrapper startGroupingActions]; | 361 [wrapper startGroupingActions]; |
| 362 bool didPerformMove = bookmark_utils_ios::MoveBookmarks(nodes, model, folder); | 362 bool didPerformMove = bookmark_utils_ios::MoveBookmarks(nodes, model, folder); |
| 363 [wrapper stopGroupingActions]; | 363 [wrapper stopGroupingActions]; |
| 364 [wrapper resetUndoManagerChanged]; | 364 [wrapper resetUndoManagerChanged]; |
| 365 | 365 |
| 366 if (!didPerformMove) | 366 if (!didPerformMove) |
| 367 return; // Don't present a snackbar when no real move as happened. | 367 return; // Don't present a snackbar when no real move as happened. |
| 368 | 368 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 397 NodesSection::NodesSection() {} | 397 NodesSection::NodesSection() {} |
| 398 | 398 |
| 399 NodesSection::~NodesSection() {} | 399 NodesSection::~NodesSection() {} |
| 400 | 400 |
| 401 void segregateNodes( | 401 void segregateNodes( |
| 402 const NodeVector& vector, | 402 const NodeVector& vector, |
| 403 std::vector<std::unique_ptr<NodesSection>>& nodesSectionVector) { | 403 std::vector<std::unique_ptr<NodesSection>>& nodesSectionVector) { |
| 404 nodesSectionVector.clear(); | 404 nodesSectionVector.clear(); |
| 405 | 405 |
| 406 // Make a localized date formatter. | 406 // Make a localized date formatter. |
| 407 base::scoped_nsobject<NSDateFormatter> formatter( | 407 NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; |
| 408 [[NSDateFormatter alloc] init]); | |
| 409 [formatter setDateFormat:@"MMMM yyyy"]; | 408 [formatter setDateFormat:@"MMMM yyyy"]; |
| 410 // Segregate nodes by creation date. | 409 // Segregate nodes by creation date. |
| 411 // Nodes that were created in the same month are grouped together. | 410 // Nodes that were created in the same month are grouped together. |
| 412 for (auto* node : vector) { | 411 for (auto* node : vector) { |
| 413 base::mac::ScopedNSAutoreleasePool pool; | 412 @autoreleasepool { |
| 414 base::Time dateAdded = node->date_added(); | 413 base::Time dateAdded = node->date_added(); |
| 415 base::TimeDelta delta = dateAdded - base::Time::UnixEpoch(); | 414 base::TimeDelta delta = dateAdded - base::Time::UnixEpoch(); |
| 416 base::scoped_nsobject<NSDate> date( | 415 NSDate* date = |
| 417 [[NSDate alloc] initWithTimeIntervalSince1970:delta.InSeconds()]); | 416 [[NSDate alloc] initWithTimeIntervalSince1970:delta.InSeconds()]; |
| 418 NSString* dateString = [formatter stringFromDate:date]; | 417 NSString* dateString = [formatter stringFromDate:date]; |
| 419 const std::string timeRepresentation = base::SysNSStringToUTF8(dateString); | 418 const std::string timeRepresentation = |
| 419 base::SysNSStringToUTF8(dateString); |
| 420 | 420 |
| 421 BOOL found = NO; | 421 BOOL found = NO; |
| 422 for (const auto& nodesSection : nodesSectionVector) { | 422 for (const auto& nodesSection : nodesSectionVector) { |
| 423 if (nodesSection->timeRepresentation == timeRepresentation) { | 423 if (nodesSection->timeRepresentation == timeRepresentation) { |
| 424 nodesSection->vector.push_back(node); | 424 nodesSection->vector.push_back(node); |
| 425 found = YES; | 425 found = YES; |
| 426 break; | 426 break; |
| 427 } |
| 427 } | 428 } |
| 429 |
| 430 if (found) |
| 431 continue; |
| 432 |
| 433 // No NodesSection found. |
| 434 auto nodesSection = base::MakeUnique<NodesSection>(); |
| 435 nodesSection->time = dateAdded; |
| 436 nodesSection->timeRepresentation = timeRepresentation; |
| 437 nodesSection->vector.push_back(node); |
| 438 nodesSectionVector.push_back(std::move(nodesSection)); |
| 428 } | 439 } |
| 429 | |
| 430 if (found) | |
| 431 continue; | |
| 432 | |
| 433 // No NodesSection found. | |
| 434 auto nodesSection = base::MakeUnique<NodesSection>(); | |
| 435 nodesSection->time = dateAdded; | |
| 436 nodesSection->timeRepresentation = timeRepresentation; | |
| 437 nodesSection->vector.push_back(node); | |
| 438 nodesSectionVector.push_back(std::move(nodesSection)); | |
| 439 } | 440 } |
| 440 | 441 |
| 441 // Sort the NodesSections. | 442 // Sort the NodesSections. |
| 442 std::sort(nodesSectionVector.begin(), nodesSectionVector.end(), | 443 std::sort(nodesSectionVector.begin(), nodesSectionVector.end(), |
| 443 [](const std::unique_ptr<NodesSection>& n1, | 444 [](const std::unique_ptr<NodesSection>& n1, |
| 444 const std::unique_ptr<NodesSection>& n2) { | 445 const std::unique_ptr<NodesSection>& n2) { |
| 445 return n1->time > n2->time; | 446 return n1->time > n2->time; |
| 446 }); | 447 }); |
| 447 | 448 |
| 448 // For each NodesSection, sort the nodes inside. | 449 // For each NodesSection, sort the nodes inside. |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 | 677 |
| 677 *position = cache.position; | 678 *position = cache.position; |
| 678 return YES; | 679 return YES; |
| 679 } | 680 } |
| 680 | 681 |
| 681 void ClearPositionCache() { | 682 void ClearPositionCache() { |
| 682 [[NSUserDefaults standardUserDefaults] removeObjectForKey:kPositionCacheKey]; | 683 [[NSUserDefaults standardUserDefaults] removeObjectForKey:kPositionCacheKey]; |
| 683 } | 684 } |
| 684 | 685 |
| 685 } // namespace bookmark_utils_ios | 686 } // namespace bookmark_utils_ios |
| OLD | NEW |