Start 100DaysOfSwiftUI from 2020.Mar.18th.
Day 99: Project 19, part four
done with 3 hours
For 1st challenge,
in ResortView.swift
1 2 3 4 5 6 7 8 9 |
ZStack(alignment: .bottomTrailing) { // <- new Image(decorative: resort.id) .resizable() .scaledToFit() Text(resort.imageCredit) // <- new .font(.footnote) // <- new } // <- new |
for 2nd challenge
for load
1 2 3 4 5 6 7 8 9 10 |
init() { // load our saved data if let data = UserDefaults.standard.data(forKey: saveKey), let decodedData = try? JSONDecoder().decode(Set<String>.self, from: data) { resorts = decodedData } else { self.resorts = [] } } |
for save
1 2 3 4 5 6 7 8 9 |
func save() { // write out our data let data = try? JSONEncoder().encode(resorts) if let encodedData = data { UserDefaults.standard.set(encodedData, forKey: saveKey) } } |
for 3rd challenge:
On top of 3rd challenge, I added how many resorts are there for each condition. Ex: how many resorts are there for size small.
create ResortList class
ResortList.swft
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
class ResortList: ObservableObject { var resorts:[Resort] @Published var sortName:String = "name" @Published var countryFileter: String = "" @Published var sizeFilter: Int = 0 @Published var priceFilter: Int = 0 init() { resorts = [] } init(fromBundle name:String) { resorts = Bundle.main.decode("resorts.json") } func sortedList(sortType:String) -> [Resort] { switch sortName { case "name": return resorts.sorted(by: {$0.name < $1.name}) case "country": return resorts.sorted(by: {$0.country < $1.country}) default: return resorts } } func filterWithCondition( resorts: [Resort]) -> [Resort] { return resorts.filter({ self.countryFileter == "" || self.countryFileter == $0.country}).filter({self.sizeFilter==0 || self.sizeFilter == $0.size}).filter({self.priceFilter==0 || self.priceFilter == $0.price} ) } func processedList() -> [Resort] { return filterWithCondition(resorts: sortedList(sortType: sortName)) } var countries:[String] { return Array(Set(resorts.map({$0.country}))).sorted() } var prices:[Int] { return [1,2,3] } var sizes:[Int] { return [1,2,3] } func sizeStringWithNum(size:Int) -> String { switch size { case 1: return "Small"+"(\(resorts.filter({$0.size == size}).count))" case 2: return "Average"+"(\(resorts.filter({$0.size == size}).count))" default: return "Large"+"(\(resorts.filter({$0.size == size}).count))" } } func priceStringWithNum(price:Int) -> String { String(repeating: "$", count: price)+"(\(resorts.filter({$0.price == price}).count))" } } |
Add code to ContentView
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
struct ContentView: View { @ObservedObject var favorites = Favorites() @ObservedObject var resorts = ResortList(fromBundle: "resorts.json") @State private var isShowingSortFilter = false var body: some View { NavigationView { List(resorts.processedList()) { resort in NavigationLink(destination: ResortView(resort: resort)) { Image(resort.country) .resizable() .scaledToFill() .frame(width: 40, height: 25) .clipShape( RoundedRectangle(cornerRadius: 5) ) .overlay( RoundedRectangle(cornerRadius: 5) .stroke(Color.black, lineWidth: 1) ) VStack(alignment: .leading) { Text(resort.name) .font(.headline) Text("\(resort.runs) runs") .foregroundColor(.secondary) }.layoutPriority(1) if self.favorites.contains(resort) { Spacer() Image(systemName: "heart.fill") .accessibility(label: Text("This is a favorite resort")) .foregroundColor(.red) } } } .navigationBarTitle("Resorts") .navigationBarItems(trailing: Button("sort/filter"){ self.isShowingSortFilter.toggle() }) WelcomeView() } .environmentObject(favorites) .sheet(isPresented: $isShowingSortFilter) { VStack { Text("Sort") .font(.headline) Picker(selection: self.$resorts.sortName, label: Text("Sort")) { Text("name").tag("name") Text("country").tag("country") } .font(.footnote) .pickerStyle(SegmentedPickerStyle()) Text("Filter") .font(.headline) Text("Country") .font(.subheadline) Picker(selection: self.$resorts.countryFileter, label: Text("country"), content: { Text("-").tag("") ForEach(self.resorts.countries, id: \.self) { name in Text(name) } }) .font(.footnote) .pickerStyle(SegmentedPickerStyle()) Text("Size") .font(.subheadline) Picker(selection: self.$resorts.sizeFilter, label: Text("size"), content: { Text("-").tag(0) ForEach(self.resorts.sizes, id: \.self) { size in Text(self.resorts.sizeStringWithNum(size: size)) .tag(size) } }) .font(.footnote) .pickerStyle(SegmentedPickerStyle()) Text("Price") .font(.subheadline) Picker(selection: self.$resorts.priceFilter, label: Text("price"), content: { Text("-").tag(0) ForEach(self.resorts.prices, id: \.self) { price in Text(self.resorts.priceStringWithNum(price: price)) .tag(price) } }) .font(.footnote) .pickerStyle(SegmentedPickerStyle()) Button("done"){ self.isShowingSortFilter.toggle() } } } } } |
Sponsor Link