Skip to content

Commit

Permalink
#1899 (dashboard)
Browse files Browse the repository at this point in the history
- The folder and feed names and icons are now populated when first showing the Dashboard, before loading the stories.
- The Dashboard is automatically refreshed every five minutes, while it is displayed.
- Tapping a Dashboard list header goes to that folder or feed.
- (Tapping a story isn’t implemented yet.)
  • Loading branch information
Dejal committed Jan 24, 2025
1 parent b693dd4 commit a383b7b
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 24 deletions.
16 changes: 13 additions & 3 deletions clients/ios/Classes/DashList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import Foundation
var feeds = [Feed]()
var stories = [Story]()

var isLoaded: Bool {
return folder != nil
var hasStories: Bool {
return !stories.isEmpty
}

var isFolder: Bool {
Expand Down Expand Up @@ -62,14 +62,24 @@ import Foundation
self.order = order
self.feedId = feedId
self.folderId = folderId

load()
}

func load() {
if isFolder {
folder = Folder(id: folderId)
} else if let feedId {
feeds = [Feed(id: feedId)]
}
}
}

extension DashList: @preconcurrency CustomStringConvertible {
var description: String {
let base = "DashList index: \(index), side: \(side), order: \(order)"

if isLoaded {
if hasStories {
if isFolder {
return "\(base), folder: `\(folder?.name ?? "none")` (\(folderId)) contains \(feeds.count) feeds with \(stories.count) stories"
} else {
Expand Down
4 changes: 2 additions & 2 deletions clients/ios/Classes/FeedDetailDashListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct DashListHeaderView: View {
.frame(height: 50)
.clipShape(RoundedRectangle(cornerRadius: 10))
.onTapGesture {
// interaction.hid(story: story)
interaction.tapped(dash: dash)
}
}
}
Expand All @@ -72,7 +72,7 @@ struct DashListStoriesView: View {

var body: some View {
VStack(alignment: .center) {
if dash.isLoaded {
if dash.hasStories {
ForEach(dash.stories) { story in
CardView(feedDetailInteraction: interaction, cache: cache, story: story)
}
Expand Down
1 change: 1 addition & 0 deletions clients/ios/Classes/FeedDetailGridView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import SwiftUI
var isMarkReadOnScroll: Bool { get }

func pullToRefresh()
func tapped(dash: DashList)
func visible(story: Story)
func tapped(story: Story)
func reading(story: Story)
Expand Down
4 changes: 4 additions & 0 deletions clients/ios/Classes/FeedDetailObjCViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,10 @@ - (void)fetchRiverPage:(int)page withCallback:(void(^)(void))callback {
#pragma mark Processing Stories

- (void)finishedLoadingFeed:(NSDictionary *)results feedPage:(NSInteger)feedPage feedId:(NSString *)sentFeedId {
if (self.dashboardIndex >= 0 && !self.isDashboard) {
return;
}

appDelegate.hasLoadedFeedDetail = YES;
self.isOnline = YES;
self.isShowingFetching = NO;
Expand Down
21 changes: 21 additions & 0 deletions clients/ios/Classes/FeedDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,14 @@ extension FeedDetailViewController: FeedDetailInteraction {
instafetchFeed()
}

func tapped(dash: DashList) {
if dash.isFolder {
appDelegate.feedsViewController.selectFolder(dash.folderId)
} else if let feedId = dash.feedId {
appDelegate.feedsViewController.selectFeed(feedId, inFolder: dash.folderId)
}
}

func visible(story: Story) {
print("🐓 Visible: \(story.debugTitle)")

Expand Down Expand Up @@ -365,6 +373,11 @@ extension FeedDetailViewController: FeedDetailInteraction {

print("🪿 Tapped \(story.debugTitle)")

if isDashboard {
tappedDashboard(story: story)
return
}

let indexPath = IndexPath(row: story.index, section: 0)

suppressMarkAsRead = true
Expand All @@ -376,6 +389,14 @@ extension FeedDetailViewController: FeedDetailInteraction {
}
}

func tappedDashboard(story: Story) {
// guard let feedId = story.feed?.id else {
// return
// }

//TODO: 🚧
}

func reading(story: Story) {
print("🪿 Reading \(story.debugTitle)")
}
Expand Down
8 changes: 6 additions & 2 deletions clients/ios/Classes/FeedsObjCViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ UIGestureRecognizerDelegate, UISearchBarDelegate> {
- (void)selectNextFolder:(id)sender;
- (void)selectPreviousFolder:(id)sender;

- (void)selectWidgetStories;

- (void)selectFolder:(NSString *)folder;
- (void)selectFeed:(NSString *)feedId inFolder:(NSString *)folder;


- (void)markFeedRead:(NSString *)feedId cutoffDays:(NSInteger)days;
- (void)markFeedsRead:(NSArray *)feedIds cutoffDays:(NSInteger)days;
- (void)markEverythingReadWithDays:(NSInteger)days;
Expand All @@ -136,8 +142,6 @@ UIGestureRecognizerDelegate, UISearchBarDelegate> {
- (void)fadeFeed:(NSString *)feedId;
- (IBAction)tapAddSite:(id)sender;

- (void)selectWidgetStories;

- (void)reloadFeedTitlesTable;
- (void)resetToolbar;
- (void)layoutHeaderCounts:(UIInterfaceOrientation)orientation;
Expand Down
74 changes: 62 additions & 12 deletions clients/ios/Classes/FeedsObjCViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -2147,12 +2147,7 @@ - (void)selectNextFolder:(id)sender {
} while (!foundNext && section != stopAtSection);

[self didSelectSectionHeaderWithTag:section];

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:section];

if ([self.feedTitlesTable numberOfRowsInSection:section] > 0) {
[self.feedTitlesTable scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
[self scrollToSection:section];
}

- (void)selectPreviousFolder:(id)sender {
Expand All @@ -2165,12 +2160,7 @@ - (void)selectPreviousFolder:(id)sender {
}

[self didSelectSectionHeaderWithTag:section];

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:section];

if ([self.feedTitlesTable numberOfRowsInSection:section] > 0) {
[self.feedTitlesTable scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
[self scrollToSection:section];
}

- (void)selectDashboard:(id)sender {
Expand All @@ -2189,6 +2179,43 @@ - (void)selectWidgetStories {
}
}

- (void)selectFolder:(NSString *)folder {
NSInteger tag = [appDelegate.dictFoldersArray indexOfObject:folder];

if (tag != NSNotFound) {
[self didSelectSectionHeaderWithTag:tag];
[self scrollToSection:tag];
}
}

- (void)selectFeed:(NSString *)feedId inFolder:(NSString *)folder {
NSInteger section = [appDelegate.dictFoldersArray indexOfObject:folder];
NSArray *feedsInFolder = [appDelegate.dictFolders objectForKey:folder];

if (section != NSNotFound) {
for (NSInteger row = 0; row < feedsInFolder.count; row++) {
id thisFeedId = [feedsInFolder objectAtIndex:row];
NSString *thisFeedIdStr = [NSString stringWithFormat:@"%@", thisFeedId];

if ([thisFeedIdStr isEqualToString:feedId]) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];

[self expandFolderIfNecessary:folder];
[feedTitlesTable selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
[self tableView:feedTitlesTable didSelectRowAtIndexPath:indexPath];
}
}
}
}

- (void)scrollToSection:(NSInteger)section {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:section];

if ([self.feedTitlesTable numberOfRowsInSection:section] > 0) {
[self.feedTitlesTable scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}

#pragma mark - MCSwipeTableViewCellDelegate

// When the user starts swiping the cell this method is called
Expand Down Expand Up @@ -2406,6 +2433,29 @@ - (void)didCollapseFolder:(UIButton *)button {

}

- (void)expandFolderIfNecessary:(NSString *)folderName {
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];

NSString *collapseKey = [NSString stringWithFormat:@"folderCollapsed:%@", folderName];
bool isFolderCollapsed = [userPreferences boolForKey:collapseKey];

if (isFolderCollapsed) {
// Expand folder
[userPreferences setBool:NO forKey:collapseKey];
[userPreferences synchronize];
appDelegate.collapsedFolders = nil;

[self resetRowHeights];

NSInteger tag = [appDelegate.dictFoldersArray indexOfObject:folderName];

[self.feedTitlesTable beginUpdates];
[self.feedTitlesTable reloadSections:[NSIndexSet indexSetWithIndex:tag]
withRowAnimation:UITableViewRowAnimationFade];
[self.feedTitlesTable endUpdates];
}
}

- (BOOL)isFeedVisible:(id)feedId {
if (![feedId isKindOfClass:[NSString class]]) {
feedId = [NSString stringWithFormat:@"%@",feedId];
Expand Down
29 changes: 24 additions & 5 deletions clients/ios/Classes/FeedsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,20 @@ class FeedsViewController: FeedsObjCViewController {
return parentTitles
}

var dashboardTimer: Timer?

@objc func clearDashboard() {
appDelegate.feedDetailViewController.dashboardIndex = -1
appDelegate.detailViewController.storyTitlesInDashboard = false

dashboardTimer?.invalidate()
dashboardTimer = nil
}

@objc func reloadDashboard() {
appDelegate.feedDetailViewController.dashboardIndex = -1

immediatelyLoadNextDash(prepare: false)
}

@objc func loadDashboard() {
Expand All @@ -116,7 +127,13 @@ class FeedsViewController: FeedsObjCViewController {
} else if appDelegate.feedDetailViewController.dashboardIndex >= 0 {
deferredLoadNextDash()
} else {
immediatelyLoadNextDash()
let frequency: TimeInterval = 5 * 60

dashboardTimer?.invalidate()
dashboardTimer = Timer.scheduledTimer(timeInterval: frequency, target: self, selector: #selector(reloadDashboard), userInfo: nil, repeats: true
)

immediatelyLoadNextDash(prepare: true)
}
}

Expand All @@ -126,26 +143,28 @@ class FeedsViewController: FeedsObjCViewController {
dashWorkItem?.cancel()

let workItem = DispatchWorkItem { [weak self] in
guard let self else {
guard let self, isDashboard else {
return
}

immediatelyLoadNextDash()
immediatelyLoadNextDash(prepare: true)
}

dashWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5), execute: workItem)
}

private func immediatelyLoadNextDash() {
private func immediatelyLoadNextDash(prepare: Bool) {
appDelegate.feedDetailViewController.storyCache.reloadDashboard(for: appDelegate.feedDetailViewController.dashboardIndex)

appDelegate.feedDetailViewController.dashboardIndex += 1

let index = appDelegate.feedDetailViewController.dashboardIndex

if index == 0 {
appDelegate.feedDetailViewController.storyCache.prepareDashboard()
if prepare {
appDelegate.feedDetailViewController.storyCache.prepareDashboard()
}
} else if index >= appDelegate.dashboardArray.count {
// Done.

Expand Down

0 comments on commit a383b7b

Please sign in to comment.