Skip to content

Commit

Permalink
Stops can be added to a Favorite View
Browse files Browse the repository at this point in the history
  • Loading branch information
thealpa committed Apr 12, 2022
1 parent feba9cb commit 8d0c084
Show file tree
Hide file tree
Showing 12 changed files with 386 additions and 27 deletions.
18 changes: 16 additions & 2 deletions CVAG.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand All @@ -39,13 +42,16 @@
3D53805727DA7D41005860CE /* Departures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Departures.swift; sourceTree = "<group>"; };
3D53805927DA9A6A005860CE /* DeparturesLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeparturesLoader.swift; sourceTree = "<group>"; };
3D59B66927DE73BE00BA0DFA /* DepartureCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureCellView.swift; sourceTree = "<group>"; };
3D5CA9C52804720800DE6E60 /* FavoriteAddButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteAddButtonView.swift; sourceTree = "<group>"; };
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 = "<group>"; };
3D635F4927D81789008906D3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
3D635F4B27D8178A008906D3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
3D635F4E27D8178A008906D3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
3D732E8627EBF7BA003E8110 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
3DCEB98C27ED4118003FC99C /* StopAnnotationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StopAnnotationView.swift; sourceTree = "<group>"; };
3DD72ACB2801BC8000044491 /* Favorites.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Favorites.swift; sourceTree = "<group>"; };
3DD72AD628032A8F00044491 /* FavoriteButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButtonView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -69,6 +75,8 @@
3DCEB98C27ED4118003FC99C /* StopAnnotationView.swift */,
3D59B66927DE73BE00BA0DFA /* DepartureCellView.swift */,
3D4012F427E931DE00649196 /* FavoritesDrawerView.swift */,
3DD72AD628032A8F00044491 /* FavoriteButtonView.swift */,
3D5CA9C52804720800DE6E60 /* FavoriteAddButtonView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand All @@ -79,6 +87,7 @@
3D53804827D93B2E005860CE /* Stop.swift */,
3D53805727DA7D41005860CE /* Departures.swift */,
3D53805327DA3760005860CE /* Drawer.swift */,
3DD72ACB2801BC8000044491 /* Favorites.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions CVAG/CVAG.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
6 changes: 4 additions & 2 deletions CVAG/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
8 changes: 7 additions & 1 deletion CVAG/Models/Drawer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
29 changes: 29 additions & 0 deletions CVAG/Models/Favorites.swift
Original file line number Diff line number Diff line change
@@ -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)
]
}
22 changes: 22 additions & 0 deletions CVAG/Models/Stop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
7 changes: 7 additions & 0 deletions CVAG/Stores/DeparturesLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand Down
60 changes: 39 additions & 21 deletions CVAG/Views/DrawerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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))
Expand All @@ -120,38 +123,40 @@ 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))
.padding(.top, 100)
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)
Expand All @@ -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!])
}
}
65 changes: 65 additions & 0 deletions CVAG/Views/FavoriteAddButtonView.swift
Original file line number Diff line number Diff line change
@@ -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))
}
}
Loading

0 comments on commit 8d0c084

Please sign in to comment.