diff --git a/CVAG.xcodeproj/project.pbxproj b/CVAG.xcodeproj/project.pbxproj index eea6bf2..8221dae 100644 --- a/CVAG.xcodeproj/project.pbxproj +++ b/CVAG.xcodeproj/project.pbxproj @@ -18,12 +18,15 @@ 3D53805827DA7D41005860CE /* Departures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D53805727DA7D41005860CE /* Departures.swift */; }; 3D53805A27DA9A6A005860CE /* DeparturesLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D53805927DA9A6A005860CE /* DeparturesLoader.swift */; }; 3D59B66A27DE73BE00BA0DFA /* DepartureCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D59B66927DE73BE00BA0DFA /* DepartureCellView.swift */; }; + 3D5CA9C62804720800DE6E60 /* FavoriteAddButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D5CA9C52804720800DE6E60 /* FavoriteAddButtonView.swift */; }; 3D635F4827D81789008906D3 /* CVAGApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D635F4727D81789008906D3 /* CVAGApp.swift */; }; 3D635F4A27D81789008906D3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D635F4927D81789008906D3 /* ContentView.swift */; }; 3D635F4C27D8178A008906D3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D635F4B27D8178A008906D3 /* Assets.xcassets */; }; 3D635F4F27D8178A008906D3 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D635F4E27D8178A008906D3 /* Preview Assets.xcassets */; }; 3D732E8727EBF7BA003E8110 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3D732E8627EBF7BA003E8110 /* LaunchScreen.storyboard */; }; 3DCEB98D27ED4118003FC99C /* StopAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCEB98C27ED4118003FC99C /* StopAnnotationView.swift */; }; + 3DD72ACC2801BC8000044491 /* Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DD72ACB2801BC8000044491 /* Favorites.swift */; }; + 3DD72AD728032A8F00044491 /* FavoriteButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DD72AD628032A8F00044491 /* FavoriteButtonView.swift */; }; 3DDAF3C527FA3100006C8730 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 3DDAF3C427FA3100006C8730 /* Introspect */; }; /* End PBXBuildFile section */ @@ -39,6 +42,7 @@ 3D53805727DA7D41005860CE /* Departures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Departures.swift; sourceTree = ""; }; 3D53805927DA9A6A005860CE /* DeparturesLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeparturesLoader.swift; sourceTree = ""; }; 3D59B66927DE73BE00BA0DFA /* DepartureCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureCellView.swift; sourceTree = ""; }; + 3D5CA9C52804720800DE6E60 /* FavoriteAddButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteAddButtonView.swift; sourceTree = ""; }; 3D635F4427D81789008906D3 /* CVAG.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CVAG.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3D635F4727D81789008906D3 /* CVAGApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CVAGApp.swift; sourceTree = ""; }; 3D635F4927D81789008906D3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -46,6 +50,8 @@ 3D635F4E27D8178A008906D3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 3D732E8627EBF7BA003E8110 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 3DCEB98C27ED4118003FC99C /* StopAnnotationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StopAnnotationView.swift; sourceTree = ""; }; + 3DD72ACB2801BC8000044491 /* Favorites.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Favorites.swift; sourceTree = ""; }; + 3DD72AD628032A8F00044491 /* FavoriteButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButtonView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,6 +75,8 @@ 3DCEB98C27ED4118003FC99C /* StopAnnotationView.swift */, 3D59B66927DE73BE00BA0DFA /* DepartureCellView.swift */, 3D4012F427E931DE00649196 /* FavoritesDrawerView.swift */, + 3DD72AD628032A8F00044491 /* FavoriteButtonView.swift */, + 3D5CA9C52804720800DE6E60 /* FavoriteAddButtonView.swift */, ); path = Views; sourceTree = ""; @@ -79,6 +87,7 @@ 3D53804827D93B2E005860CE /* Stop.swift */, 3D53805727DA7D41005860CE /* Departures.swift */, 3D53805327DA3760005860CE /* Drawer.swift */, + 3DD72ACB2801BC8000044491 /* Favorites.swift */, ); path = Models; sourceTree = ""; @@ -227,12 +236,15 @@ 3D635F4A27D81789008906D3 /* ContentView.swift in Sources */, 3D53805A27DA9A6A005860CE /* DeparturesLoader.swift in Sources */, 3D635F4827D81789008906D3 /* CVAGApp.swift in Sources */, + 3DD72AD728032A8F00044491 /* FavoriteButtonView.swift in Sources */, + 3D5CA9C62804720800DE6E60 /* FavoriteAddButtonView.swift in Sources */, 3D53805827DA7D41005860CE /* Departures.swift in Sources */, 3DCEB98D27ED4118003FC99C /* StopAnnotationView.swift in Sources */, 3D4012F527E931DE00649196 /* FavoritesDrawerView.swift in Sources */, 3D53804927D93B2E005860CE /* Stop.swift in Sources */, 3D53805427DA3760005860CE /* Drawer.swift in Sources */, 3D59B66A27DE73BE00BA0DFA /* DepartureCellView.swift in Sources */, + 3DD72ACC2801BC8000044491 /* Favorites.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -360,8 +372,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = CVAG/CVAG.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 32; + CURRENT_PROJECT_VERSION = 35; DEVELOPMENT_ASSET_PATHS = "\"CVAG/Preview Content\""; DEVELOPMENT_TEAM = B7HSFEB698; ENABLE_PREVIEWS = YES; @@ -391,8 +404,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = CVAG/CVAG.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 32; + CURRENT_PROJECT_VERSION = 35; DEVELOPMENT_ASSET_PATHS = "\"CVAG/Preview Content\""; DEVELOPMENT_TEAM = B7HSFEB698; ENABLE_PREVIEWS = YES; diff --git a/CVAG/CVAG.entitlements b/CVAG/CVAG.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/CVAG/CVAG.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/CVAG/ContentView.swift b/CVAG/ContentView.swift index 25a56b1..de4f344 100644 --- a/CVAG/ContentView.swift +++ b/CVAG/ContentView.swift @@ -12,17 +12,19 @@ struct ContentView: View { // Start with a placeholder stop @State var selectedStop: Stop = noStop @State var setDrawerHeight: drawerType = .hidden + @State var showFavoritesView: Bool = true var body: some View { ZStack { MapView(selectedStop: $selectedStop, setDrawerHeight: $setDrawerHeight) - DrawerView(selectedStop: $selectedStop, setDrawerHeight: $setDrawerHeight, drawerHeights: [-100]) + DrawerView(selectedStop: $selectedStop, showFavoritesView: $showFavoritesView, setDrawerHeight: $setDrawerHeight, drawerHeights: [-100]) + FavoritesDrawerView(selectedStop: $selectedStop, setDrawerHeight: $setDrawerHeight, showFavoritesView: $showFavoritesView) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView(selectedStop: Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.1, longitude: 50.1)) + ContentView(selectedStop: Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.1, longitude: 50.1), showFavoritesView: true) } } diff --git a/CVAG/Models/Drawer.swift b/CVAG/Models/Drawer.swift index 7e80023..ad957df 100644 --- a/CVAG/Models/Drawer.swift +++ b/CVAG/Models/Drawer.swift @@ -8,7 +8,8 @@ import SwiftUI /// Default positions of drawer in __ascending__ order. -let drawerDefault: [CGFloat] = [50, 400, UIScreen.main.bounds.height - 150] +// +let drawerDefault: [CGFloat] = [(UIScreen.screenHeight * 0.15), (UIScreen.screenHeight * 0.60), (UIScreen.screenHeight * 0.90)] public enum drawerType { case hidden @@ -17,3 +18,8 @@ public enum drawerType { case medium case high } + +extension UIScreen{ + static let screenWidth = UIScreen.main.bounds.size.width + static let screenHeight = UIScreen.main.bounds.size.height +} diff --git a/CVAG/Models/Favorites.swift b/CVAG/Models/Favorites.swift new file mode 100644 index 0000000..10ed67c --- /dev/null +++ b/CVAG/Models/Favorites.swift @@ -0,0 +1,29 @@ +// +// Favorites.swift +// CVAG +// +// Created by Jan Hülsmann on 09.04.22. +// + +import SwiftUI + +class FavoritesModel: ObservableObject { + + // Load example data on first run + init() { + if !UserDefaults.standard.bool(forKey: "didLaunchBefore") { + UserDefaults.standard.set(true, forKey: "didLaunchBefore") + favorites = exampleFavorites + } + } + + @AppStorage("favoriteStops") var favorites = FavoriteStops() + + @Published var currentFavorite: Stop? + + private var exampleFavorites: [Stop] = [ + Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.8327427033286, longitude: 12.9213850148795), + Stop(id: 216, name: "TU Campus", latitude: 50.8134653801663, longitude: 12.931050887338), + Stop(id: 59, name: "Hauptbahnhof", latitude: 50.8400951572571, longitude: 12.929685448106) + ] +} diff --git a/CVAG/Models/Stop.swift b/CVAG/Models/Stop.swift index 37de5b0..9869490 100644 --- a/CVAG/Models/Stop.swift +++ b/CVAG/Models/Stop.swift @@ -20,3 +20,25 @@ struct Stop: Identifiable, Codable, Equatable { } let noStop: Stop = Stop(id: 0, name: "", latitude: 0.0, longitude: 0.0) + +typealias FavoriteStops = [Stop] + +extension FavoriteStops: RawRepresentable { + public init?(rawValue: String) { + guard let data = rawValue.data(using: .utf8), + let result = try? JSONDecoder().decode(FavoriteStops.self, from: data) + else { + return nil + } + self = result + } + + public var rawValue: String { + guard let data = try? JSONEncoder().encode(self), + let result = String(data: data, encoding: .utf8) + else { + return "[]" + } + return result + } +} diff --git a/CVAG/Stores/DeparturesLoader.swift b/CVAG/Stores/DeparturesLoader.swift index c368af1..4fcc984 100644 --- a/CVAG/Stores/DeparturesLoader.swift +++ b/CVAG/Stores/DeparturesLoader.swift @@ -10,6 +10,7 @@ import Foundation class DeparturesLoader: ObservableObject { @Published var departures = [Departure]() @Published var loadingError: Bool = false + @Published var noDepartures: Bool = false func loadData(id: Int16) { // Skip if using placeholder id @@ -29,6 +30,12 @@ class DeparturesLoader: ObservableObject { DispatchQueue.main.async { self.loadingError = false self.departures = decodedData.stops + + if self.departures.isEmpty { + self.noDepartures = true + } else { + self.noDepartures = false + } } } else { print("No data") diff --git a/CVAG/Views/DrawerView.swift b/CVAG/Views/DrawerView.swift index ef9cbd6..ddd782f 100644 --- a/CVAG/Views/DrawerView.swift +++ b/CVAG/Views/DrawerView.swift @@ -13,10 +13,12 @@ struct DrawerView: View { @Binding var selectedStop: Stop @StateObject var departuresList = DeparturesLoader() + @Binding var showFavoritesView: Bool @Binding var setDrawerHeight: drawerType @State var drawerHeights: [CGFloat] @State var currentDrawerHeight: CGFloat = drawerDefault[1] @State private var showError = false + @State private var noDepartures = false /// Update timer let timer = Timer.publish(every: 30, tolerance: 5, on: .main, in: .common).autoconnect() @@ -101,6 +103,7 @@ struct DrawerView: View { Button { setDrawerHeight = .hidden selectedStop = noStop + showFavoritesView = true } label: { Image(systemName: "xmark") .font(.system(size: 12, weight: .bold, design: .rounded)) @@ -120,7 +123,7 @@ struct DrawerView: View { Text("Keine Verbindung zur CVAG") .font(.footnote) .padding() - } else if departuresList.departures.count == 0 { + } else if noDepartures { Image(systemName: "moon.zzz.fill") .font(.system(size: 48)) .foregroundColor(Color(.systemGray)) @@ -128,30 +131,32 @@ struct DrawerView: View { Text("Aktuell keine Abfahrten") .font(.footnote) .padding() - } - - ScrollView { - ForEach(departuresList.departures) { departure in - DepartureCellView(departure: departure) - Divider() - .padding(.horizontal, 20) - .padding(.bottom, 10) - } - }.onChange(of: selectedStop) { newStop in - departuresList.loadData(id: selectedStop.id) - }.onReceive(timer) { time in - - // Only reload data if drawer is visible - if currentDrawerHeight > 0 { - departuresList.loadData(id: selectedStop.id) + } else { + ScrollView { + ForEach(departuresList.departures) { departure in + DepartureCellView(departure: departure) + Divider() + .padding(.horizontal, 20) + .padding(.bottom, 10) + } + }.onReceive(timer) { time in + + // Only reload data if drawer is visible + if currentDrawerHeight > 0 { + departuresList.loadData(id: selectedStop.id) + } + }.introspectScrollView { scrollView in + scrollView.alwaysBounceVertical = false } - }.introspectScrollView { scrollView in - scrollView.alwaysBounceVertical = false } - .frame(maxHeight: UIScreen.main.bounds.height - 200) Spacer() } + + FavoriteAddButtonView(stop: selectedStop) + .shadow(radius: 5) + .padding(.top, drawerDefault[2] - 200) + } }.impact(.medium) .dislodge(.light) @@ -170,11 +175,24 @@ struct DrawerView: View { showError = false } } + .onChange(of: departuresList.noDepartures) { newValue in + if newValue == true { + noDepartures = true + } else { + noDepartures = false + } + } + .onChange(of: selectedStop) { newStop in + departuresList.loadData(id: selectedStop.id) + if newStop != noStop { + showFavoritesView = false + } + }.ignoresSafeArea(.all) } } struct DrawerView_Previews: PreviewProvider { static var previews: some View { - DrawerView(selectedStop: .constant(Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.1, longitude: 50.1)), setDrawerHeight: .constant(.variable), drawerHeights: [drawerDefault.last!]) + DrawerView(selectedStop: .constant(Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.1, longitude: 50.1)), showFavoritesView: .constant(false), setDrawerHeight: .constant(.variable), drawerHeights: [drawerDefault.last!]) } } diff --git a/CVAG/Views/FavoriteAddButtonView.swift b/CVAG/Views/FavoriteAddButtonView.swift new file mode 100644 index 0000000..a976883 --- /dev/null +++ b/CVAG/Views/FavoriteAddButtonView.swift @@ -0,0 +1,65 @@ +// +// FavoriteAddButtonView.swift +// CVAG +// +// Created by Jan Hülsmann on 11.04.22. +// + +import SwiftUI + +struct FavoriteAddButtonView: View { + + var stop: Stop + var impactGenerator: UIImpactFeedbackGenerator = UIImpactFeedbackGenerator(style: .medium) + @State var isFavorite: Bool = false + @StateObject var favoritesData = FavoritesModel() + + var body: some View { + + Button { + DispatchQueue.main.async { + impactGenerator.impactOccurred() + } + if !favoritesData.favorites.contains(stop) { + favoritesData.favorites.append(stop) + isFavorite = true + } else if let index = favoritesData.favorites.firstIndex(of: stop) { + favoritesData.favorites.remove(at: index) + isFavorite = false + } + } label: { + HStack { + if isFavorite == false { + Image(systemName: "plus") + .font(.system(size: 16, weight: .medium, design: .rounded)) + Text("Zu Favoriten hinzufügen") + .font(.system(size: 16, weight: .medium, design: .rounded)) + } else { + Image(systemName: "xmark") + .font(.system(size: 16, weight: .medium, design: .rounded)) + Text("Von Favoriten entfernen") + .font(.system(size: 16, weight: .medium, design: .rounded)) + } + + }.padding(.horizontal, 20) + .padding(.vertical, 5) + } + .foregroundColor(Color(.systemBackground)) + .padding() + .background(Color(.label)) + .clipShape(Capsule()) + .onChange(of: stop) { newStop in + if favoritesData.favorites.contains(newStop) { + isFavorite = true + } else { + isFavorite = false + } + } + } +} + +struct FavoriteAddButtonView_Previews: PreviewProvider { + static var previews: some View { + FavoriteAddButtonView(stop: Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.1, longitude: 50.1)) + } +} diff --git a/CVAG/Views/FavoriteButtonView.swift b/CVAG/Views/FavoriteButtonView.swift new file mode 100644 index 0000000..e11cdca --- /dev/null +++ b/CVAG/Views/FavoriteButtonView.swift @@ -0,0 +1,46 @@ +// +// FavoriteButtonView.swift +// CVAG +// +// Created by Jan Hülsmann on 10.04.22. +// + +import SwiftUI +import AVKit + +struct FavoriteButtonView: View { + var stop: Stop + + var body: some View { + VStack { + HStack { + Image(systemName: "mappin.and.ellipse") + .font(Font.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.horizontal, 15) + .padding(.top, 15) + + Spacer() + } + + Spacer() + + HStack { + Text(stop.name) + .font(Font.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.horizontal, 15) + .padding(.bottom, 15) + + Spacer() + } + } + .frame(width: (UIScreen.screenWidth - 60) / 2, height: 120) + .background(Color(.secondarySystemBackground)) + .cornerRadius(15) + } +} + +struct FavoriteButtonView_Previews: PreviewProvider { + static var previews: some View { + FavoriteButtonView(stop: Stop(id: 131, name: "Zentralhaltestelle", latitude: 50.1, longitude: 50.1)) + } +} diff --git a/CVAG/Views/FavoritesDrawerView.swift b/CVAG/Views/FavoritesDrawerView.swift new file mode 100644 index 0000000..4a10e69 --- /dev/null +++ b/CVAG/Views/FavoritesDrawerView.swift @@ -0,0 +1,144 @@ +// +// FavoritesDrawerView.swift +// CVAG +// +// Created by Jan Hülsmann on 21.03.22. +// + +import SwiftUI +import Drawer +import Introspect + +struct FavoritesDrawerView: View { + + @Binding var selectedStop: Stop + @Binding var setDrawerHeight: drawerType + + @StateObject var favoritesData = FavoritesModel() + @Binding var showFavoritesView: Bool + @State var restingHeight: [CGFloat] = drawerDefault + @State var currentDrawerHeight: CGFloat = drawerDefault[1] + + //Workaround + @State var showGrid: Bool = true + + let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2) + + var body: some View { + Drawer(){ + ZStack { + + RoundedRectangle(cornerRadius: 50.0) + .foregroundColor(Color(.systemBackground)) + .shadow(radius: 25) + + VStack { + Spacer().frame(height: 8.0) + + RoundedRectangle(cornerRadius: 3.0) + .foregroundColor(Color(.systemGray5)) + .frame(width: 35.0, height: 6.0) + + HStack { + Text("Favoriten") + .frame(maxWidth: .infinity, alignment: .leading) + .font(.system(size: 32, weight: .semibold, design: .default)) + + Spacer() + + ZStack { + Circle() + .frame(width: 25, height: 25) + .foregroundColor(Color(.secondarySystemBackground)) + Button { + showFavoritesView = false + } label: { + Image(systemName: "xmark") + .font(.system(size: 12, weight: .bold, design: .rounded)) + .foregroundColor(Color(.secondaryLabel)) + } + } + }.padding(.horizontal, 20) + .padding(.top, 15) + .padding(.bottom, 20) + + if showFavoritesView { + LazyVGrid(columns: columns, spacing: 20) { + ForEach(favoritesData.favorites) { favoriteStop in + + FavoriteButtonView(stop: favoriteStop) + .contentShape(.dragPreview, RoundedRectangle(cornerRadius: 15)) + .opacity(favoritesData.currentFavorite?.id == favoriteStop.id ? 0.01 : 1) + .onDrag({ + return NSItemProvider(object: String(favoriteStop.id) as NSString) + }) + .onDrop(of: ["favorite"], delegate: DropViewDelegate(stop: favoriteStop, favoritesData: favoritesData)) + .onTapGesture { + selectedStop = favoriteStop + setDrawerHeight = .medium + showFavoritesView = false + } + } + }.padding(.horizontal, 15) + } + + Spacer() + } + } + }.impact(.medium) + .dislodge(.light) + .spring(0) + .rest(at: $restingHeight) + .onRest { restingHeight in + currentDrawerHeight = restingHeight + } + .onChange(of: showFavoritesView) { showView in + if showView == false { + restingHeight = [-100] + } else if showView == true { + restingHeight = drawerDefault + } + }.ignoresSafeArea(.all) + } +} + +struct DropViewDelegate: DropDelegate { + var stop: Stop + var favoritesData: FavoritesModel + + func performDrop(info: DropInfo) -> Bool { + favoritesData.currentFavorite = nil + return true + } + + func dropEntered(info: DropInfo) { + + if favoritesData.currentFavorite == nil { + favoritesData.currentFavorite = stop + } + + let fromIndex = favoritesData.favorites.firstIndex { (stop) -> Bool in + return stop.id == favoritesData.currentFavorite?.id + } ?? 0 + + let toIndex = favoritesData.favorites.firstIndex { (stop) -> Bool in + return stop.id == self.stop.id + } ?? 0 + + if fromIndex != toIndex { + let fromStop = favoritesData.favorites[fromIndex] + favoritesData.favorites[fromIndex] = favoritesData.favorites[toIndex] + favoritesData.favorites[toIndex] = fromStop + } + } + + func dropUpdated(info: DropInfo) -> DropProposal? { + return DropProposal(operation: .move) + } +} + +struct FavoritesDrawerView_Previews: PreviewProvider { + static var previews: some View { + FavoritesDrawerView(selectedStop: .constant(noStop), setDrawerHeight: .constant(.variable), showFavoritesView: .constant(true), restingHeight: [500] ) + } +} diff --git a/CVAG/Views/StopAnnotationView.swift b/CVAG/Views/StopAnnotationView.swift index 319a9a8..03be57f 100644 --- a/CVAG/Views/StopAnnotationView.swift +++ b/CVAG/Views/StopAnnotationView.swift @@ -36,11 +36,12 @@ struct StopAnnotationView: View { .onTapGesture { setDrawerHeight = .medium selectedStop = stop - showSelected.toggle() } .onChange(of: selectedStop) { newStop in if stop.id != newStop.id { showSelected = false + } else { + showSelected.toggle() } } }