Skip to content

Commit

Permalink
117
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Sep 14, 2020
1 parent 42fb6dd commit 16c7486
Show file tree
Hide file tree
Showing 338 changed files with 40,003 additions and 0 deletions.
483 changes: 483 additions & 0 deletions 0116-redacted-swiftui-pt2/Articles/Articles.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
13 changes: 13 additions & 0 deletions 0116-redacted-swiftui-pt2/Articles/Shared/ActivityIndicator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import SwiftUI

struct ActivityIndicator: UIViewRepresentable {
init() {}

func makeUIView(context: Context) -> UIActivityIndicatorView {
let view = UIActivityIndicatorView(style: .large)
view.startAnimating()
return view
}

func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {}
}
10 changes: 10 additions & 0 deletions 0116-redacted-swiftui-pt2/Articles/Shared/ArticlesApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import SwiftUI

@main
struct ArticlesApp: App {
var body: some Scene {
WindowGroup {
VanillaArticlesView()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
179 changes: 179 additions & 0 deletions 0116-redacted-swiftui-pt2/Articles/Shared/Composable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import ComposableArchitecture
import SwiftUI

struct ArticlesState: Equatable {
var articles: [Article] = []
var isLoading = false
var readingArticle: Article?
}

enum ArticlesAction {
case article(index: Int, action: ArticleAction)
case articlesResponse([Article]?)
case articleTapped(Article)
case dismissArticle
case onAppear
}

enum ArticleAction {
case favoriteTapped
case hideTapped
case readLaterTapped
}

let articlesReducer = Reducer<ArticlesState, ArticlesAction, Void> { state, action, environment in
switch action {
case let .article(index: index, action: .favoriteTapped):
state.articles[index].isFavorite.toggle()
return .none

case let .article(index: index, action: .hideTapped):
state.articles[index].isHidden.toggle()
return .none

case let .article(index: index, action: .readLaterTapped):
state.articles[index].willReadLater.toggle()
return .none

case let .articlesResponse(articles):
state.isLoading = false
state.articles = articles ?? []
return .none

case let .articleTapped(article):
state.readingArticle = article
return .none

case .dismissArticle:
state.readingArticle = nil
return .none

case .onAppear:
state.isLoading = true
return Effect(value: .articlesResponse(liveArticles))
.delay(for: 4, scheduler: DispatchQueue.main)
.eraseToEffect()
}
}

struct ComposableArticlesView: View {
let store: Store<ArticlesState, ArticlesAction>

var body: some View {
WithViewStore(self.store) { viewStore in
NavigationView {
List {
if viewStore.isLoading {
ActivityIndicator()
.padding()
.frame(maxWidth: .infinity)
}

ArticlesListView(store: self.store)
}
.sheet(
item: viewStore.binding(get: \.readingArticle, send: .dismissArticle)
) { article in
NavigationView {
ArticleDetailView(article: article)
.navigationTitle(article.title)
}
}
.navigationTitle("Articles")
}
.onAppear { viewStore.send(.onAppear) }
}
}
}

struct ArticlesListView: View {
let store: Store<ArticlesState, ArticlesAction>

var body: some View {
WithViewStore(self.store) { viewStore in
ForEachStore(
self.store.scope(state: \.articles, action: ArticlesAction.article)
) { articleStore in
WithViewStore(articleStore) { articleViewStore in
Button(action: { viewStore.send(.articleTapped(articleViewStore.state)) }) {
ArticleRowView(store: articleStore)
}
.buttonStyle(PlainButtonStyle())
}
}
}
}
}

private struct ArticleRowView: View {
let store: Store<Article, ArticleAction>

var body: some View {
WithViewStore(self.store) { viewStore in
HStack(alignment: .top) {
Image("")
.frame(width: 80, height: 80)
.background(Color(white: 0.9))
.padding([.trailing])

VStack(alignment: .leading) {
Text(viewStore.title)
.font(.title)

Text(articleDateFormatter.string(from: viewStore.date))
.bold()

Text(viewStore.blurb)
.padding(.top, 6)

HStack {
Spacer()

Button(action: { viewStore.send(.favoriteTapped) }) {
Image(systemName: "star.fill")
}
.buttonStyle(PlainButtonStyle())
.foregroundColor(viewStore.isFavorite ? .red : .blue)
.padding()

Button(action: { viewStore.send(.readLaterTapped) }) {
Image(systemName: "book.fill")
}
.buttonStyle(PlainButtonStyle())
.foregroundColor(viewStore.willReadLater ? .yellow : .blue)
.padding()

Button(action: { viewStore.send(.hideTapped) }) {
Image(systemName: "eye.slash.fill")
}
.buttonStyle(PlainButtonStyle())
.foregroundColor(.blue)
.padding()
}
}
}
.padding([.top, .bottom])
.buttonStyle(PlainButtonStyle())
}
}
}

private struct ArticleDetailView: View {
let article: Article

var body: some View {
Text(self.article.blurb)
}
}

struct Composable_Previews: PreviewProvider {
static var previews: some View {
ComposableArticlesView(
store: Store(
initialState: ArticlesState(),
reducer: articlesReducer,
environment: ()
)
)
}
}
Loading

0 comments on commit 16c7486

Please sign in to comment.