Skip to content

Instantly share code, notes, and snippets.

@sidepelican
Created July 30, 2019 15:08
Show Gist options
  • Save sidepelican/330ca3255cffcf13cd5352d5935040c7 to your computer and use it in GitHub Desktop.
Save sidepelican/330ca3255cffcf13cd5352d5935040c7 to your computer and use it in GitHub Desktop.
import Combine
import SwiftUI
struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
typealias Index = Base.Index
typealias Element = (index: Index, element: Base.Element)
let base: Base
var startIndex: Index { base.startIndex }
var endIndex: Index { base.endIndex }
func index(after i: Index) -> Index {
base.index(after: i)
}
func index(before i: Index) -> Index {
base.index(before: i)
}
func index(_ i: Index, offsetBy distance: Int) -> Index {
base.index(i, offsetBy: distance)
}
subscript(position: Index) -> Element {
(index: position, element: base[position])
}
}
extension RandomAccessCollection {
func indexed() -> IndexedCollection<Self> {
IndexedCollection(base: self)
}
}
struct Landmark: Identifiable {
var id: Int
var name: String
var isFavorite: Bool = false
}
let landmarkData = [
Landmark(id: 1, name: "A"),
Landmark(id: 2, name: "B"),
Landmark(id: 3, name: "C"),
Landmark(id: 4, name: "D"),
]
final class UserData: ObservableObject {
@Published var showFavoritesOnly = false
@Published var landmarks = landmarkData
}
struct LandmarkDetail: View {
@Binding var landmark: Landmark
var body: some View {
Toggle(landmark.name, isOn: $landmark.isFavorite)
}
}
struct LandmarkList: View {
@Binding var landmarks: [Landmark]
@Binding var showFavoritesOnly: Bool
var filteredLandmarks: Binding<[Landmark]> {
Binding<[Landmark]>(get: {
self.landmarks.filter { !(self.showFavoritesOnly && !$0.isFavorite) }
}, set: { newValue in
self.landmarks = newValue
})
}
func bindingLandmark(for landmarks: Binding<[Landmark]>, index: Int) -> Binding<Landmark> {
Binding(get: {
landmarks.value[index]
}, set: { newValue in
var tmp = landmarks.value
tmp[index] = newValue
landmarks.value = tmp
})
}
var body: some View {
List(filteredLandmarks.value.indexed(), id: \.1.id) { (index, landmark) in
NavigationLink(
landmark.name + (landmark.isFavorite ? "★" : ""),
destination: LandmarkDetail(landmark: self.bindingLandmark(for: self.filteredLandmarks, index: index))
)
}
}
}
struct ContentView: View {
@EnvironmentObject var userData: UserData
var body: some View {
NavigationView {
LandmarkList(landmarks: $userData.landmarks, showFavoritesOnly: $userData.showFavoritesOnly)
.navigationBarTitle("Landmarks")
.navigationBarItems(trailing: Toggle("showFavoritesOnly", isOn: $userData.showFavoritesOnly))
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment