Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

New Tab Page & Favicons Refactor #2490

Merged
merged 64 commits into from
Jun 8, 2020
Merged

Conversation

kylehickinson
Copy link
Collaborator

@kylehickinson kylehickinson commented Apr 28, 2020

Summary of Changes

Blanket Refactor Issues

This pull request fixes #2578
This pull request fixes #2579

NTP Issues

This pull request fixes #2380
This pull request fixes #2071
This pull request fixes #2036
This pull request fixes #2351
This pull request fixes #2059
This pull request fixes #2516

Keyboard Issues

Note that the "Auto-Open Keyboard" preference has been removed

This pull request fixes #2078
This pull request fixes #2073
This pull request fixes #2321 (because the pref no longer exists)

Favicon Issues

This pull request fixes #2051
This pull request fixes #1162
This pull request fixes #933
This pull request fixes #528
This pull request fixes #2362
This pull request fixes #2485
This pull request fixes #2099
This pull request fixes #1865
This pull request fixes #1030
This pull request fixes #2364

Submitter Checklist:

  • Unit Tests are updated to cover new or changed functionality
  • User-facing strings use NSLocalizableString()

Test Plan:

  • Test New Tab Page related functions:

    • Verify stats appear & function
    • Verify favorites appear and are left-aligned even with less than 4 items
    • Verify show more only appears when there's more than the visible number of favorites on NTP (between 4-6 depending on iPhone vs iPad portrait & landscape)
    • Verify iPhone/iPad landscape vs portrait
    • Verify background images
    • Verify background images source button
    • Verify SI's & SI button
    • Verify CHP's & QR code button
    • Verify private mode callouts
    • Verify themes
    • Verify no-image-bg light theme shows dark-blue bg now and no gradient
  • Test all places favicons are seen: Favorites, Bookmarks, Add Bookmark, History, Search, Back/Forward list, Tab Tray, Rewards Panel, Rewards Tipping/Auto-Contribute/Pending Contributions list, etc.

    • Verify custom icons are shown for super-referrers
    • Verify bundled icons are shown until you visit the page (therefore parsing and downloading the websites up-to-date favicon)
    • Verify websites that only have small favicons display monograms on the favorites overlay & NTP. (i.e. https://eqbank.ca) but display the icon in other places
    • Verify websites that don't have any valid favicon display monograms (e.g. https://kylehickinson.com)
  • Test new favorites overlay basic functionality (tap, edit, reorder, scroll, etc.)

  • Test upgrading from older versions that already have favicons downloaded

Screenshots:

Screenshots

Simulator Screen Shot - iPhone 11 Pro - 2020-05-25 at 13 41 06

Simulator Screen Shot - iPhone 11 Pro - 2020-05-25 at 13 41 35

Simulator Screen Shot - iPhone 11 Pro - 2020-05-25 at 13 44 15

Simulator Screen Shot - iPhone 11 Pro - 2020-05-25 at 13 45 17

Reviewer Checklist:

  • Issues include necessary QA labels:
    • QA/(Yes|No)
    • release-notes/(include|exclude)
    • bug / enhancement
  • Necessary security reviews have taken place.
  • Adequate unit test coverage exists to prevent regressions.
  • Adequate test plan exists for QA to validate (if applicable).
  • Issue is assigned to a milestone (should happen at merge time).

Copy link
Contributor

@iccub iccub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments and questions just by looking at the code, haven't run it yet.

There will be some more involved after custom homepage code is added, one view to add and some logic.
In general the refactor looks good, there's only one hacky solution of aligning the image credits and other 1 item sections I guess

Will do some functional review later, these are just some initial comments from me

@@ -0,0 +1,30 @@
// This Source Code Form is subject to the terms of the Mozilla Public
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update license for all newly added files.
#2441

@@ -98,8 +98,6 @@ extension Preferences {
static let backgroundImages = Option<Bool>(key: "newtabpage.background-images", default: true)
/// Whether sponsored images are included into the background image rotation
static let backgroundSponsoredImages = Option<Bool>(key: "newtabpage.background-sponsored-images", default: true)
/// Whether the iOS keyboard auto-opens on a NTP or not
static let autoOpenKeyboard = Option<Bool>(key: "newtabpage.auto-open-keyboard", default: false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we getting rid of this setting option?

Copy link
Collaborator Author

@kylehickinson kylehickinson Apr 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, partly because of Brave Today, party because tapping on URL bar will now display an entirely separate VC from NTP with just favs (no more stats, etc.)

@@ -3352,6 +3344,27 @@ extension BrowserViewController: ToolbarUrlActionsDelegate {
}
}

extension BrowserViewController: NewTabPageDelegate {
func navigateToInput(_ input: String, inNewTab: Bool, switchingToPrivateMode: Bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for, looks like it focuses on url bar with some url/text typed in, is this some new behavior or we use it somewhere already?
Hmm or is this what happens when you tap on favorites, or on bg image's credits

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the base of it from FavoritesDelegate:

protocol FavoritesDelegate: AnyObject {
    func didSelect(input: String)
    ...

Not sure why it passed in String (maybe for bookmarklets?) but I just kept it that way just in case. Its called based on a fav being clicked, or context menu actioned it to open in a new tab/new private tab

@@ -31,6 +31,8 @@ class FavoriteCell: UICollectionViewCell {
var imageInsets: UIEdgeInsets = UIEdgeInsets.zero
var cellInsets: UIEdgeInsets = UIEdgeInsets.zero

var longPressed: ((FavoriteCell) -> Void)?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to something like longPressHandler or didLongPress

// some padding between the title and the image.
let scale = 1.0 / UIScreen.main.scale
return CGSize(width: (scale * (cellWidth / scale)).rounded(.down),
height: 1000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this hardcoded height, just to tell the item to take as much space as needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct!

cell.longPressed = { [weak self] cell in
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

let edit = UIAlertAction(title: Strings.editBookmark, style: .default) { (action) in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove brackets here and in action below

@available(iOS 13.0, *)
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
guard let favourite = frc.fetchedObjects?[indexPath.item] else { return nil }
return UIContextMenuConfiguration(identifier: indexPath as NSCopying, previewProvider: nil) { (elemenst) -> UIMenu? in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in elemenst and remove brackets

/// The section is given half the available space
///
/// Layout is decided by device type (iPad vs iPhone)
case halfWidth
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we need this half width for?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for iPhone/iPad landscape, where the NTP is half the width of the screen and aligned to the left or right depending on the device (iPad = left, iPhone = right) but Brave Today will not have this same logic (it will just be centered regardless)


private let notifications: NewTabPageNotifications

private let sponsorButton = SpringButton()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sponsor button should have its own collectionview section, no? Otherwise when BraveToday is added this will be still attached to bottom of the screen

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, the sponsored image is not supposed to move, which is why I did this. It also doesn't fit the design either. On landscape iPhone its placed off on the left side next to the other elements :(

Tests were invalid since these controllers were split
if let domain = domain, let url = domain.url?.asURL, !url.absoluteString.isEmpty {
// Use the base domain's first character, but if that isn't valid
// use the favorites title as the monogram instead
monogramFallbackLabel.text = url.baseDomain?.first?.uppercased() ??
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things here:

  1. We use this logic in two places, how about adding a helper method in URL extension to get first letter of the url? This way we could also add some basic unit tests, for example check if www part is stripped

  2. What if all these three methods fail, we show no letter right? I think it would be better to add a fallback letter just in case could be W for website

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

baseDomain gets rid of any www, and only seems to fail for direct IPs (192.168.1.1 for example) which won't include www anyways and url.host should theoretically never be nil in our cases unless someone edited the URL and just got rid of the entire host? I'm not sure what the best course of action is really if they all somehow fail. Maybe just the first character in the absoluteString? 😂

///
/// If the app does not contain a custom icon for the site provided `nil`
/// will be returned
var customIcon: FaviconAttributes? {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make all these custom, bundled, downloaded icon getters private so we never directly access them by accident.
I assume we should always call load in order to retrieve a favicon

Copy link
Collaborator Author

@kylehickinson kylehickinson May 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were actually private before, I made them public internal so I could unit test them :)

}

/// Begin the search for a favicon for the site.
func load(_ completion: @escaping (URL, FaviconAttributes) -> Void) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a documentation comment that completion returns on main thread?

delegate?.tappedQRCodeButton(url: url)
}

private func handleBookmarkAction(bookmark: Bookmark, action: BookmarksAction) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost the same as implementation in BVC, maybe centralize this logic somewhere? At least reuse the code for popup in edit action

@kylehickinson kylehickinson requested a review from iccub May 26, 2020 19:43
Copy link
Contributor

@iccub iccub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job, clean refactor and very much needed

return
}

self.downloadIcon(url: faviconURL, addingToDatabase: true) { [weak self] image in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for isPrivate before adding to database?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already checked on completion on line 220: https://github.com/brave/brave-ios/pull/2490/files/6740bd8a934071e866f7db5d53b1d809c9da925c#diff-d47742238791692d201e5deaa57d0377R220

if addingToDatabase && !PrivateBrowsingManager.shared.isPrivateBrowsing {
  FaviconMO.add(favicon, forSiteUrl: self.url)
}

Fix issue where unsized icon would be used instead of sized ones
@brave brave deleted a comment from kylehickinson Jun 5, 2020
@kylehickinson kylehickinson merged commit f2f97e5 into development Jun 8, 2020
@kylehickinson kylehickinson deleted the new-tab-page-refactor branch June 8, 2020 15:03
@kylehickinson
Copy link
Collaborator Author

CI passed, but for some reason was still showing pending

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.