-
Notifications
You must be signed in to change notification settings - Fork 299
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ed55f1b
commit 34fa5d5
Showing
3 changed files
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import Combine | ||
import SwiftUI | ||
|
||
class AppState: ObservableObject { | ||
@Published var count = 0 | ||
@Published var favoritePrimes: [Int] = [] | ||
@Published var loggedInUser: User? = nil | ||
@Published var activityFeed: [Activity] = [] | ||
|
||
struct Activity { | ||
let timestamp: Date | ||
let type: ActivityType | ||
|
||
enum ActivityType { | ||
case addedFavoritePrime(Int) | ||
case removedFavoritePrime(Int) | ||
} | ||
} | ||
|
||
struct User { | ||
let id: Int | ||
let name: String | ||
let bio: String | ||
} | ||
} | ||
|
||
struct FavoritePrimesState { | ||
var favoritePrimes: [Int] | ||
var activityFeed: [AppState.Activity] | ||
} | ||
|
||
extension AppState { | ||
var favoritePrimesState: FavoritePrimesState { | ||
get { | ||
FavoritePrimesState( | ||
favoritePrimes: self.favoritePrimes, | ||
activityFeed: self.activityFeed | ||
) | ||
} | ||
set { | ||
self.favoritePrimes = newValue.favoritePrimes | ||
self.activityFeed = newValue.activityFeed | ||
} | ||
} | ||
} | ||
|
||
struct PrimeAlert: Identifiable { | ||
let prime: Int | ||
var id: Int { self.prime } | ||
} | ||
|
||
struct CounterView: View { | ||
@ObservedObject var state: AppState | ||
@State var isPrimeModalShown = false | ||
@State var alertNthPrime: PrimeAlert? | ||
@State var isNthPrimeButtonDisabled = false | ||
|
||
var body: some View { | ||
VStack { | ||
HStack { | ||
Button("-") { self.state.count -= 1 } | ||
Text("\(self.state.count)") | ||
Button("+") { self.state.count += 1 } | ||
} | ||
Button("Is this prime?") { self.isPrimeModalShown = true } | ||
Button( | ||
"What is the \(ordinal(self.state.count)) prime?", | ||
action: self.nthPrimeButtonAction | ||
) | ||
.disabled(self.isNthPrimeButtonDisabled) | ||
} | ||
.font(.title) | ||
.navigationBarTitle("Counter demo") | ||
.sheet(isPresented: self.$isPrimeModalShown) { | ||
IsPrimeModalView(state: self.state) | ||
} | ||
.alert(item: self.$alertNthPrime) { alert in | ||
Alert( | ||
title: Text("The \(ordinal(self.state.count)) prime is \(alert.prime)"), | ||
dismissButton: .default(Text("Ok")) | ||
) | ||
} | ||
} | ||
|
||
func nthPrimeButtonAction() { | ||
self.isNthPrimeButtonDisabled = true | ||
nthPrime(self.state.count) { prime in | ||
self.alertNthPrime = prime.map(PrimeAlert.init(prime:)) | ||
self.isNthPrimeButtonDisabled = false | ||
} | ||
} | ||
} | ||
|
||
struct IsPrimeModalView: View { | ||
@ObservedObject var state: AppState | ||
|
||
var body: some View { | ||
VStack { | ||
if isPrime(self.state.count) { | ||
Text("\(self.state.count) is prime 🎉") | ||
if self.state.favoritePrimes.contains(self.state.count) { | ||
Button("Remove from favorite primes") { | ||
self.state.favoritePrimes.removeAll(where: { $0 == self.state.count }) | ||
self.state.activityFeed.append(.init(timestamp: Date(), type: .removedFavoritePrime(self.state.count))) | ||
} | ||
} else { | ||
Button("Save to favorite primes") { | ||
self.state.favoritePrimes.append(self.state.count) | ||
self.state.activityFeed.append(.init(timestamp: Date(), type: .addedFavoritePrime(self.state.count))) | ||
|
||
} | ||
} | ||
} else { | ||
Text("\(self.state.count) is not prime :(") | ||
} | ||
} | ||
} | ||
} | ||
|
||
struct FavoritePrimesView: View { | ||
@Binding var state: FavoritePrimesState | ||
|
||
var body: some View { | ||
List { | ||
ForEach(self.state.favoritePrimes, id: \.self) { prime in | ||
Text("\(prime)") | ||
} | ||
.onDelete { indexSet in | ||
for index in indexSet { | ||
let prime = self.state.favoritePrimes[index] | ||
self.state.favoritePrimes.remove(at: index) | ||
self.state.activityFeed.append(.init(timestamp: Date(), type: .removedFavoritePrime(prime))) | ||
} | ||
} | ||
} | ||
.navigationBarTitle(Text("Favorite Primes")) | ||
} | ||
} | ||
|
||
struct ContentView: View { | ||
@ObservedObject var state: AppState | ||
|
||
var body: some View { | ||
NavigationView { | ||
List { | ||
NavigationLink( | ||
"Counter demo", | ||
destination: CounterView(state: self.state) | ||
) | ||
NavigationLink( | ||
"Favorite primes", | ||
destination: FavoritePrimesView(state: self.$state.favoritePrimesState) | ||
) | ||
} | ||
.navigationBarTitle("State management") | ||
} | ||
} | ||
} | ||
|
||
import PlaygroundSupport | ||
PlaygroundPage.current.liveView = UIHostingController( | ||
rootView: ContentView(state: AppState()) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import Foundation | ||
|
||
private let wolframAlphaApiKey = "6H69Q3-828TKQJ4EP" | ||
|
||
private struct WolframAlphaResult: Decodable { | ||
let queryresult: QueryResult | ||
|
||
struct QueryResult: Decodable { | ||
let pods: [Pod] | ||
|
||
struct Pod: Decodable { | ||
let primary: Bool? | ||
let subpods: [SubPod] | ||
|
||
struct SubPod: Decodable { | ||
let plaintext: String | ||
} | ||
} | ||
} | ||
} | ||
|
||
private func wolframAlpha(query: String, callback: @escaping (WolframAlphaResult?) -> Void) -> Void { | ||
var components = URLComponents(string: "https://api.wolframalpha.com/v2/query")! | ||
components.queryItems = [ | ||
URLQueryItem(name: "input", value: query), | ||
URLQueryItem(name: "format", value: "plaintext"), | ||
URLQueryItem(name: "output", value: "JSON"), | ||
URLQueryItem(name: "appid", value: wolframAlphaApiKey), | ||
] | ||
|
||
URLSession.shared.dataTask(with: components.url(relativeTo: nil)!) { data, response, error in | ||
callback( | ||
data | ||
.flatMap { try? JSONDecoder().decode(WolframAlphaResult.self, from: $0) } | ||
) | ||
} | ||
.resume() | ||
} | ||
|
||
public func nthPrime(_ n: Int, callback: @escaping (Int?) -> Void) -> Void { | ||
wolframAlpha(query: "prime \(n)") { result in | ||
callback( | ||
result | ||
.flatMap { | ||
$0.queryresult | ||
.pods | ||
.first(where: { $0.primary == .some(true) })? | ||
.subpods | ||
.first? | ||
.plaintext | ||
} | ||
.flatMap(Int.init) | ||
) | ||
} | ||
} | ||
|
||
public func ordinal(_ n: Int) -> String { | ||
let formatter = NumberFormatter() | ||
formatter.numberStyle = .ordinal | ||
return formatter.string(for: n) ?? "" | ||
} | ||
|
||
public func isPrime (_ p: Int) -> Bool { | ||
if p <= 1 { return false } | ||
if p <= 3 { return true } | ||
for i in 2...Int(sqrtf(Float(p))) { | ||
if p % i == 0 { return false } | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<playground version='5.0' target-platform='ios'> | ||
<timeline fileName='timeline.xctimeline'/> | ||
</playground> |