Start 100DaysOfSwiftUI from 2020.Mar.18th.
Day 99: Project 19, part four
done with 3 hours
For 1st challenge,
in ResortView.swift
ZStack(alignment: .bottomTrailing) { // - new
Image(decorative: resort.id)
.resizable()
.scaledToFit()
Text(resort.imageCredit) // - new
.font(.footnote) // - new
} // - new
for 2nd challenge
for load
init() {
// load our saved data
if let data = UserDefaults.standard.data(forKey: saveKey), let decodedData = try? JSONDecoder().decode(Set.self, from: data) {
resorts = decodedData
} else {
self.resorts = []
}
}
for save
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
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
コード
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