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

snj-4-feed-categories #31

Merged
merged 11 commits into from
Dec 14, 2021
70 changes: 34 additions & 36 deletions SwiftNews/SwiftNews.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
5C46051D27358027009199E4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5C46051C27358027009199E4 /* Preview Assets.xcassets */; };
5C46052727358027009199E4 /* SwiftNewsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C46052627358027009199E4 /* SwiftNewsTests.swift */; };
5C4605492735807D009199E4 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 5C4605482735807D009199E4 /* ComposableArchitecture */; };
5C46054C27358197009199E4 /* RSSListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C46054B27358197009199E4 /* RSSListView.swift */; };
5C46054E273581A0009199E4 /* RSSListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C46054D273581A0009199E4 /* RSSListState.swift */; };
5C460550273581A9009199E4 /* RSSFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C46054F273581A9009199E4 /* RSSFeedView.swift */; };
5C460552273581AF009199E4 /* RSSFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C460551273581AF009199E4 /* RSSFeed.swift */; };
5C460554273581B5009199E4 /* RSSArticleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C460553273581B5009199E4 /* RSSArticleView.swift */; };
Expand All @@ -32,11 +30,12 @@
899DBF8527385DBD00F41A40 /* RSSFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C460551273581AF009199E4 /* RSSFeed.swift */; };
899DBF8627385DBF00F41A40 /* RSSArticleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C460553273581B5009199E4 /* RSSArticleView.swift */; };
899DBF8727385DC100F41A40 /* RSSArticle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C460555273581BA009199E4 /* RSSArticle.swift */; };
899DBF8827385DC300F41A40 /* RSSListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C46054B27358197009199E4 /* RSSListView.swift */; };
899DBF8927385DC600F41A40 /* RSSListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C46054D273581A0009199E4 /* RSSListState.swift */; };
B2063F68273712EB005EA377 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = B2063F67273712EB005EA377 /* SwiftSoup */; };
B24D640B27359ED20030C454 /* FeedBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24D640A27359ED20030C454 /* FeedBuilder.swift */; };
B24D640D2735A31B0030C454 /* FeedErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24D640C2735A31B0030C454 /* FeedErrorHandler.swift */; };
B2732A14274DD2C8008FD7D0 /* CategoriesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D461B427389BC900B6A614 /* CategoriesView.swift */; };
B2D461B327389AA800B6A614 /* RSSCategoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D461B227389AA800B6A614 /* RSSCategoryView.swift */; };
B2D461B527389BC900B6A614 /* CategoriesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D461B427389BC900B6A614 /* CategoriesView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -77,8 +76,6 @@
5C46051C27358027009199E4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
5C46052227358027009199E4 /* SwiftNewsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftNewsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5C46052627358027009199E4 /* SwiftNewsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftNewsTests.swift; sourceTree = "<group>"; };
5C46054B27358197009199E4 /* RSSListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSSListView.swift; sourceTree = "<group>"; };
5C46054D273581A0009199E4 /* RSSListState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSSListState.swift; sourceTree = "<group>"; };
5C46054F273581A9009199E4 /* RSSFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSSFeedView.swift; sourceTree = "<group>"; };
5C460551273581AF009199E4 /* RSSFeed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSSFeed.swift; sourceTree = "<group>"; };
5C460553273581B5009199E4 /* RSSArticleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSSArticleView.swift; sourceTree = "<group>"; };
Expand All @@ -90,6 +87,8 @@
899DBF7327385DA000F41A40 /* SwiftNewsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftNewsWidget.swift; sourceTree = "<group>"; };
B24D640A27359ED20030C454 /* FeedBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedBuilder.swift; sourceTree = "<group>"; };
B24D640C2735A31B0030C454 /* FeedErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedErrorHandler.swift; sourceTree = "<group>"; };
B2D461B227389AA800B6A614 /* RSSCategoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSCategoryView.swift; sourceTree = "<group>"; };
B2D461B427389BC900B6A614 /* CategoriesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoriesView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -149,11 +148,11 @@
5C46051427358025009199E4 /* SwiftNews */ = {
isa = PBXGroup;
children = (
B2D461AF27389A6F00B6A614 /* RSSCategories */,
5C4605602735938A009199E4 /* SwiftNewsApp.swift */,
B24D640627359CC60030C454 /* Services */,
5C460557273581C2009199E4 /* RSSFeed */,
5C460558273581CC009199E4 /* RSSArticle */,
5C460559273581D6009199E4 /* RSSList */,
5C46051927358027009199E4 /* Assets.xcassets */,
5C46051B27358027009199E4 /* Preview Content */,
);
Expand Down Expand Up @@ -194,15 +193,6 @@
path = RSSArticle;
sourceTree = "<group>";
};
5C460559273581D6009199E4 /* RSSList */ = {
isa = PBXGroup;
children = (
5C46055D273581F0009199E4 /* Views */,
5C46055E273581FA009199E4 /* Data */,
);
path = RSSList;
sourceTree = "<group>";
};
5C46055A273581DC009199E4 /* Data */ = {
isa = PBXGroup;
children = (
Expand All @@ -215,6 +205,7 @@
isa = PBXGroup;
children = (
5C46054F273581A9009199E4 /* RSSFeedView.swift */,
B2D461B427389BC900B6A614 /* CategoriesView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand All @@ -227,22 +218,6 @@
path = Views;
sourceTree = "<group>";
};
5C46055D273581F0009199E4 /* Views */ = {
isa = PBXGroup;
children = (
5C46054B27358197009199E4 /* RSSListView.swift */,
);
path = Views;
sourceTree = "<group>";
};
5C46055E273581FA009199E4 /* Data */ = {
isa = PBXGroup;
children = (
5C46054D273581A0009199E4 /* RSSListState.swift */,
);
path = Data;
sourceTree = "<group>";
};
5C46055F273581FF009199E4 /* Data */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -278,6 +253,30 @@
path = Services;
sourceTree = "<group>";
};
B2D461AF27389A6F00B6A614 /* RSSCategories */ = {
isa = PBXGroup;
children = (
B2D461B127389A9500B6A614 /* Views */,
B2D461B027389A8100B6A614 /* Data */,
);
path = RSSCategories;
sourceTree = "<group>";
};
B2D461B027389A8100B6A614 /* Data */ = {
isa = PBXGroup;
children = (
B2D461B227389AA800B6A614 /* RSSCategoryView.swift */,
);
path = Data;
sourceTree = "<group>";
};
B2D461B127389A9500B6A614 /* Views */ = {
isa = PBXGroup;
children = (
);
path = Views;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -428,10 +427,10 @@
files = (
5C460554273581B5009199E4 /* RSSArticleView.swift in Sources */,
B24D640D2735A31B0030C454 /* FeedErrorHandler.swift in Sources */,
5C46054E273581A0009199E4 /* RSSListState.swift in Sources */,
B2D461B527389BC900B6A614 /* CategoriesView.swift in Sources */,
5C4605612735938A009199E4 /* SwiftNewsApp.swift in Sources */,
5C460556273581BA009199E4 /* RSSArticle.swift in Sources */,
5C46054C27358197009199E4 /* RSSListView.swift in Sources */,
B2D461B327389AA800B6A614 /* RSSCategoryView.swift in Sources */,
B24D640B27359ED20030C454 /* FeedBuilder.swift in Sources */,
5C460552273581AF009199E4 /* RSSFeed.swift in Sources */,
5C460550273581A9009199E4 /* RSSFeedView.swift in Sources */,
Expand All @@ -450,14 +449,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B2732A14274DD2C8008FD7D0 /* CategoriesView.swift in Sources */,
899DBF8627385DBF00F41A40 /* RSSArticleView.swift in Sources */,
899DBF7427385DA000F41A40 /* SwiftNewsWidget.swift in Sources */,
899DBF8327385DB800F41A40 /* FeedErrorHandler.swift in Sources */,
899DBF8827385DC300F41A40 /* RSSListView.swift in Sources */,
899DBF8727385DC100F41A40 /* RSSArticle.swift in Sources */,
899DBF8227385DB400F41A40 /* FeedBuilder.swift in Sources */,
899DBF8527385DBD00F41A40 /* RSSFeed.swift in Sources */,
899DBF8927385DC600F41A40 /* RSSListState.swift in Sources */,
899DBF8427385DBA00F41A40 /* RSSFeedView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
2 changes: 1 addition & 1 deletion SwiftNews/SwiftNews/RSSArticle/Views/RSSArticleView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct RSSArticleView: View {
Text(viewStore.pubDate)
.font(.caption)
.padding(.bottom, 5)
Link("Swift By Sundell", destination: URL(string: viewStore.link)!)
Link("View Web Version", destination: URL(string: viewStore.link)!)
.font(.caption)
.padding(.bottom, 5)
Text((try? viewStore.document?.text()) ?? viewStore.content)
Expand Down
23 changes: 23 additions & 0 deletions SwiftNews/SwiftNews/RSSCategories/Data/RSSCategoryView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// RSSCategoryView.swift
// SwiftNews
//
// Created by Rob Maltese on 11/7/21.
//

import Foundation
import ComposableArchitecture
import SwiftUI
Copy link
Collaborator

Choose a reason for hiding this comment

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

Old Stub


// MARK: - State



// MARK: - Actions


// MARK: -Environment


// MARK: - Reducer

36 changes: 33 additions & 3 deletions SwiftNews/SwiftNews/RSSFeed/Data/RSSFeed.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,23 @@ struct RSSFeed: Equatable, Identifiable {
var articles: IdentifiedArrayOf<RSSArticle> = []

var isFetchingData: Bool = false

// State for Category View.
var feed: FeedURL = .sundell
var availableFeeds: [FeedURL]
var categoryState: CategoryState {
get {
CategoryState(
feed: self.feed,
availableFeeds: self.availableFeeds
)
}

set {
self.feed = newValue.feed
self.availableFeeds = newValue.availableFeeds
}
}

var favoriteArticles: IdentifiedArrayOf<RSSArticle> = []
var nonFavoriteArticles: IdentifiedArrayOf<RSSArticle> = []
Expand All @@ -22,13 +38,16 @@ struct RSSFeed: Equatable, Identifiable {
// MARK: - Actions

enum RSSFeedAction: Equatable {

case didAppear
case updateFavoriteSections
case fetchArticles
case loaded(articles: Result<[RSSArticle], FeedError>)

case favoriteArticle(id: RSSArticle.ID, action: RSSArticleAction)
case nonFavoriteArticle(id: RSSArticle.ID, action: RSSArticleAction)

case category(CategoryActions)
}

// MARK: - Environment
Expand Down Expand Up @@ -95,6 +114,12 @@ let rssFeedReducer = Reducer<RSSFeed, RSSFeedAction, RSSFeedEnvironment>
}
),

categoryReducer
.pullback(state: \RSSFeed.categoryState,
action: /RSSFeedAction.category,
environment: {_ in ()}
),

rssArticleReducer
.forEach(
state: \RSSFeed.nonFavoriteArticles,
Expand Down Expand Up @@ -132,8 +157,8 @@ let rssFeedReducer = Reducer<RSSFeed, RSSFeedAction, RSSFeedEnvironment>

case .loaded(articles: .failure):
state.isFetchingData = false
// TODO: Handle failure
return .none
state.articles = []
return Effect(value: .updateFavoriteSections)

case let .loaded(articles: .success(articles)):
state.isFetchingData = false
Expand All @@ -152,12 +177,17 @@ let rssFeedReducer = Reducer<RSSFeed, RSSFeedAction, RSSFeedEnvironment>
}
.sorted { $0.isFavorite && !$1.isFavorite }
)
state.favoriteArticles = state.articles.filter(\.isFavorite)
state.nonFavoriteArticles = state.articles.filter { $0.isFavorite }

return Effect(value: .updateFavoriteSections)

case .nonFavoriteArticle, .favoriteArticle:
return .none

case .category :
state.isFirstLoad = true
return Effect(value: .didAppear)
}

}
)
65 changes: 65 additions & 0 deletions SwiftNews/SwiftNews/RSSFeed/Views/CategoriesView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// CategoryTemp.swift
// SwiftNews
//
// Created by Rob Maltese on 11/7/21.
//

import SwiftUI
import ComposableArchitecture

struct CategoryState: Equatable {
var feed: FeedURL
var availableFeeds: [FeedURL]
}

enum CategoryActions: Equatable {
case selectFeed(FeedURL)
}

let categoryReducer = Reducer<CategoryState, CategoryActions, Void > { state, action, _ in
switch action {
case .selectFeed(let feedURL) :
state.feed = feedURL
return .none
}
}

struct CategoriesView: View {
let store: Store<CategoryState, CategoryActions>

let rows = [
GridItem(.fixed(50)),
GridItem(.fixed(50))
]

var body: some View {
WithViewStore(store) { viewStore in
ScrollView(.horizontal) {
LazyHGrid(rows: rows, alignment: .center) {
ForEach(viewStore.availableFeeds, id: \.self) { item in
Button {
viewStore.send(.selectFeed(item))
} label: {
Text(item.description)
.frame(minWidth: 75, idealWidth: 150, maxWidth: 175, minHeight: 25, idealHeight: 50, maxHeight: 100, alignment: .center)
.background(viewStore.feed == item ? Color.blue : Color.clear)
.foregroundColor(viewStore.feed == item ? .white : .blue)
.cornerRadius(12)
.overlay(RoundedRectangle(cornerRadius: 12)
.stroke()
)
}
}
}
.padding(.leading, 5)
}
}
}
}

struct CategoryTemp_Previews: PreviewProvider {
static var previews: some View {
CategoriesView(store: .init(initialState: CategoryState.init(feed: .sundell, availableFeeds: FeedURL.allCases), reducer: categoryReducer, environment: ()))
}
}
Loading