Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hint for no goal when filtering and ptr on empty list #506

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

krugerk
Copy link
Contributor

@krugerk krugerk commented Oct 28, 2024

uses the common technique of setting the backgroundView of the CollectionView when no items would be displayed

fixes #226
fixes #604

new notice screen:
Simulator Screenshot - iPhone Xs - no beeminder goals notice

and now with pull-to-refresh:
Simulator Screenshot - iPhone Xs - no beeminder goals notice - pull to refresh

and the new hint:
Simulator Screenshot - iPhone Xs - beeminder goals but none showing due to filter

@krugerk krugerk force-pushed the bugfix/226-no-pull-to-refresh-on-empty-gallery branch from 3da3a0d to 6781c47 Compare October 29, 2024 09:19
@theospears theospears self-assigned this Nov 6, 2024
@@ -431,9 +414,19 @@ class GalleryViewController: UIViewController, UICollectionViewDelegateFlowLayou
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
switch (filteredGoals.isEmpty, goals.isEmpty) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

numberOfSections seems like it should be a pure function which just returns a number and doesn't have side effects like updating the background. Maybe updateGoals() is a better place for this to live?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure I understand. With this change the background is set according to the number of sections and is being set in the numberOfSections. So yeah, that method has the side effect of setting the background.
As is, updateGoals() does not seem to be an ideal spot for the change either.
I made a change; take a look

@theospears theospears assigned krugerk and unassigned theospears Nov 10, 2024
@krugerk krugerk force-pushed the bugfix/226-no-pull-to-refresh-on-empty-gallery branch 2 times, most recently from ddf0553 to 5a582e2 Compare November 15, 2024 22:38
@krugerk krugerk force-pushed the bugfix/226-no-pull-to-refresh-on-empty-gallery branch from 5a582e2 to d99fc1d Compare November 27, 2024 10:04
}
let searchItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(self.searchButtonPressed))
self.navigationItem.leftBarButtonItem = searchItem
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(self.searchButtonPressed))
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ServiceLocator.versionManager.lastChckedUpdateState() == .UpdateRequired ? 0 : self.filteredGoals.count
Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • include 'update required' as one of the reasons for an empty list (show need upgrade in the background view)

Copy link
Collaborator

@theospears theospears left a comment

Choose a reason for hiding this comment

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

I agree using BackgroundView on CollectionView is a reasonable way to handle this.

This PR will conflict with #542. Given you opened it first I don't want to put the work on fixing all the merge conflicts on you, so added some feedback about what updates are necessary for this to be merged. If you're happy to follow up on them in the next week I'll hold off on #542 and fix it up to be compatible after this is merged.

}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ServiceLocator.versionManager.lastChckedUpdateState() == .UpdateRequired ? 0 : self.filteredGoals.count
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
[filteredGoals.isEmpty, goals.isEmpty].contains(true) ? 0 : 1
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
[filteredGoals.isEmpty, goals.isEmpty].contains(true) ? 0 : 1
filteredGoals.isEmpty ? 0 : 1

If goals is empty then filtered goals will always be, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, if goals is empty, then any subset of it would also be empty, including the one known as filteredGoals.

I see what you mean: we are always using the combination of the filter applied to the goals and thus the set in filteredGoals. When the searchBar.text the filtered is considered off and all goals are in filteredGoals.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps these names are unclear. Something like allGoals and visibleGoals might have been a better choice?

var goals : [Goal] = []
var filteredGoals : [Goal] = []
var goals : [Goal] = [] {
didSet {
Copy link
Collaborator

Choose a reason for hiding this comment

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

[Do] Move this logic (and filteredGoals.didSet) to didUpdateGoals which contains all the other logic/view invalidation which is run when the set of goals update.

var view: UIView? {
switch (filteredGoals.isEmpty, goals.isEmpty) {
case (true, false):
return self.makeViewForEmptyCollection(when: .noGoalsMatchingFilter)
Copy link
Collaborator

Choose a reason for hiding this comment

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

[Do] Remove the enum and the multiple views, just pass in a string here.

I've marked this as a Do, but I'm open to being convinced otherwise. At the moment I don't see the benefit to justify the additional complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently collectionView?.backgroundView is being set to a UIView which is just a container, containing a BSLabel with the reason no goals are shown, and, below it, another UIView acting as a spacer.

The intent was to show the text/label "above the fold" for better visibility and to not have it sit in the middle, which would be covered by the MBProgressHUD activity indicator.

Your proposal is just to set the backgroundView to the label directly?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm happy either to set it to the view, or the label directly. I just don't think we get much from having the NoGoalReason enum - makeViewForEmptyCollection could just take the string to show.

@krugerk
Copy link
Contributor Author

krugerk commented Dec 29, 2024

I agree using BackgroundView on CollectionView is a reasonable way to handle this.

This PR will conflict with #542. Given you opened it first I don't want to put the work on fixing all the merge conflicts on you, so added some feedback about what updates are necessary for this to be merged. If you're happy to follow up on them in the next week I'll hold off on #542 and fix it up to be compatible after this is merged.

Thanks for the consideration. (some amount of) Updating the MR so that it is mergable with its target is to be expected. And I would update it accordingly.

@krugerk krugerk force-pushed the bugfix/226-no-pull-to-refresh-on-empty-gallery branch from bfee8d4 to 04a0479 Compare December 30, 2024 00:57
@krugerk krugerk requested a review from a team as a code owner December 30, 2024 00:57
@krugerk krugerk requested review from theospears and removed request for a team December 30, 2024 00:57

cell.goal = goal

return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: 320, height: section == 0 && self.goals.count > 0 ? 5 : 0)
return CGSize(width: 320, height: section == 0 && self.allGoals.count > 0 ? 5 : 0)
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let row = (indexPath as NSIndexPath).row
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
let row = (indexPath as NSIndexPath).row
let row = indexPath.row

}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let row = (indexPath as NSIndexPath).row
if row < self.filteredGoals.count { self.openGoal(self.filteredGoals[row]) }
if row < self.visibleGoals.count { self.openGoal(self.visibleGoals[row]) }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
if row < self.visibleGoals.count { self.openGoal(self.visibleGoals[row]) }
if row < self.visibleGoals.count {
self.openGoal(self.visibleGoals[row])
}

@krugerk krugerk force-pushed the bugfix/226-no-pull-to-refresh-on-empty-gallery branch from 9aabc04 to 3f5dad5 Compare December 30, 2024 11:04
Comment on lines 453 to 455
matchingGoal = self.allGoals.filter({ (goal) -> Bool in
return goal.slug == slug
}).last
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
matchingGoal = self.allGoals.filter({ (goal) -> Bool in
return goal.slug == slug
}).last
matchingGoal = self.allGoals.last(where: { $0.slug == slug })

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unrelated to this PR though

 @objc func openGoalFromNotification(_ notification: Notification) {
        var goalFromIdentifier: Goal? {
            guard
                let identifier = notification.userInfo?["identifier"] as? String,
                let url = URL(string: identifier),
                let objectID = viewContext.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: url)
            else { return nil }
                return viewContext.object(with: objectID) as? Goal
            }
        
        var goalFromSlug: Goal? {
            guard
                let slug = notification.userInfo?["slug"] as? String
            else { return nil }
            return self.allGoals.last(where: { $0.slug == slug })
        }
        
        if let matchingGoal = goalFromIdentifier ?? goalFromSlug {
            self.navigationController?.popToRootViewController(animated: false)
            self.openGoal(matchingGoal)
        }
    }

Comment on lines 480 to 485
case (true, false):
return self.makeViewForEmptyCollection(when: .noGoalsMatchingFilter)
case (true, true):
return self.makeViewForEmptyCollection(when: .noActiveGoals)
default:
return nil
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
case (true, false):
return self.makeViewForEmptyCollection(when: .noGoalsMatchingFilter)
case (true, true):
return self.makeViewForEmptyCollection(when: .noActiveGoals)
default:
return nil
case (true, false):
self.makeViewForEmptyCollection(when: .noGoalsMatchingFilter)
case (true, true):
self.makeViewForEmptyCollection(when: .noActiveGoals)
default:
nil

@@ -429,20 +416,20 @@ class GalleryViewController: UIViewController, UICollectionViewDelegateFlowLayou
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:GoalCollectionViewCell = self.collectionView!.dequeueReusableCell(withReuseIdentifier: self.cellReuseIdentifier, for: indexPath) as! GoalCollectionViewCell

let goal:Goal = self.filteredGoals[(indexPath as NSIndexPath).row]
let goal:Goal = self.visibleGoals[(indexPath as NSIndexPath).row]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
let goal:Goal = self.visibleGoals[(indexPath as NSIndexPath).row]
let goal:Goal = self.visibleGoals[indexPath.row]

@@ -429,20 +416,20 @@ class GalleryViewController: UIViewController, UICollectionViewDelegateFlowLayou
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:GoalCollectionViewCell = self.collectionView!.dequeueReusableCell(withReuseIdentifier: self.cellReuseIdentifier, for: indexPath) as! GoalCollectionViewCell
Copy link
Contributor Author

Choose a reason for hiding this comment

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

why self.collectionView with ! and not merely the collectionView passed into this method?

Comment on lines 44 to 45
var allGoals : [Goal] = []
var visibleGoals : [Goal] = []
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
var allGoals : [Goal] = []
var visibleGoals : [Goal] = []
var allGoals = [Goal]()
var visibleGoals = [Goal]()

var deadbeatView = UIView()
var outofdateView = UIView()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
var deadbeatView = UIView()
var outofdateView = UIView()
let deadbeatView = UIView()
let outOfDateView = UIView()

uses the common technique of setting the backgroundView of the CollectionView
when no items would be displayed

fixes beeminder#226
now it is in a small container and the visible text can be placed elsewhere easily
@krugerk krugerk force-pushed the bugfix/226-no-pull-to-refresh-on-empty-gallery branch from af1943c to c86c79e Compare January 12, 2025 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

gallery list is merely empty when no goals match filter No pull-to-refresh on an empty gallery
2 participants