Skip to content

Commit

Permalink
Merge pull request #49 from OneBusAway/presentation-manager
Browse files Browse the repository at this point in the history
Presentation manager
  • Loading branch information
aaronbrethorst authored Aug 11, 2024
2 parents 05a0fd1 + 369358a commit c952a9c
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 70 deletions.
32 changes: 32 additions & 0 deletions OTPKit/Controls/SearchView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// SearchView.swift
// OTPKit
//
// Created by Aaron Brethorst on 8/11/24.
//

import SwiftUI

/// A reusable Search control suitable for displaying in the header of a view.
struct SearchView: View {
var placeholder: String
@Binding var searchText: String
@FocusState var isSearchFocused: Bool

var body: some View {
HStack {
Image(systemName: "magnifyingglass")
TextField(placeholder, text: $searchText)
.autocorrectionDisabled()
.focused($isSearchFocused)
}
.padding(.vertical, 8)
.padding(.horizontal, 12)
.background(Color.gray.opacity(0.2))
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}

// #Preview {
// SearchView()
// }
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@ public struct AddFavoriteLocationsSheet: View {
}
}

private func searchView() -> some View {
HStack {
Image(systemName: "magnifyingglass")
TextField("Search for a place", text: $search)
.autocorrectionDisabled()
.focused($isSearchFocused)
}
.padding(.vertical, 8)
.padding(.horizontal, 12)
.background(Color.gray.opacity(0.2))
.clipShape(RoundedRectangle(cornerRadius: 12))
.padding(.horizontal, 16)
}

private func currentUserSection() -> some View {
if search.isEmpty, let userLocation = locationManagerService.currentLocation {
AnyView(
Expand Down Expand Up @@ -108,7 +94,8 @@ public struct AddFavoriteLocationsSheet: View {
dismiss()
}
.padding()
searchView()
SearchView(placeholder: "Search for a place", searchText: $search, isSearchFocused: _isSearchFocused)
.padding(.horizontal, 16)
List {
currentUserSection()
searchedResultsSection()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// FavoriteLocationsSheet.swift
// MoreFavoriteLocationsSheet.swift
// OTPKitDemo
//
// Created by Hilmy Veradin on 03/07/24.
Expand All @@ -8,7 +8,7 @@
import SwiftUI

/// Show all the lists of favorite locations
public struct FavoriteLocationsSheet: View {
public struct MoreFavoriteLocationsSheet: View {
@Environment(\.dismiss) private var dismiss

@EnvironmentObject private var sheetEnvironment: OriginDestinationSheetEnvironment
Expand Down Expand Up @@ -44,5 +44,5 @@ public struct FavoriteLocationsSheet: View {
}

#Preview {
FavoriteLocationsSheet()
MoreFavoriteLocationsSheet()
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// RecentLocationsSheet.swift
// MoreRecentLocationsSheet.swift
// OTPKitDemo
//
// Created by Hilmy Veradin on 03/07/24.
Expand All @@ -8,7 +8,7 @@
import SwiftUI

/// Show all the lists of all recent locations
public struct RecentLocationsSheet: View {
public struct MoreRecentLocationsSheet: View {
@Environment(\.dismiss) var dismiss

@EnvironmentObject private var sheetEnvironment: OriginDestinationSheetEnvironment
Expand All @@ -34,5 +34,5 @@ public struct RecentLocationsSheet: View {
}

#Preview {
RecentLocationsSheet()
MoreRecentLocationsSheet()
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ public struct OriginDestinationSheetView: View {
@State private var search: String = ""

// Sheet States
@State private var isAddSavedLocationsSheetOpen = false
@State private var isFavoriteLocationSheetOpen = false
@State private var isRecentLocationSheetOpen = false
@State private var isFavoriteLocationDetailSheetOpen = false
private enum Modals: Identifiable {
case addFavoriteSheet
case moreFavoritesSheet
case favoriteDetailsSheet
case moreRecentsSheet

var id: Self { self }
}

@StateObject private var presentationManager = PresentationManager<Modals>()

@State private var isShowFavoriteConfirmationDialog = false

// Alert States
Expand All @@ -32,23 +39,10 @@ public struct OriginDestinationSheetView: View {
// Public initializer
public init() {}

private func searchView() -> some View {
HStack {
Image(systemName: "magnifyingglass")
TextField("Search for a place", text: $search)
.autocorrectionDisabled()
.focused($isSearchFocused)
}
.padding(.vertical, 8)
.padding(.horizontal, 12)
.background(Color.gray.opacity(0.2))
.clipShape(RoundedRectangle(cornerRadius: 12))
}

private func favoriteSectionConfirmationDialog() -> some View {
Group {
Button(action: {
isFavoriteLocationDetailSheetOpen.toggle()
presentationManager.present(.favoriteDetailsSheet)
}, label: {
Text("Show Details")
})
Expand Down Expand Up @@ -88,30 +82,15 @@ public struct OriginDestinationSheetView: View {
})

FavoriteView(title: "Add", imageName: "plus", tapAction: {
isAddSavedLocationsSheetOpen.toggle()
presentationManager.present(.addFavoriteSheet)
})
}
}
}, header: {
SectionHeaderView(text: "Favorites") {
isFavoriteLocationSheetOpen.toggle()
presentationManager.present(.moreFavoritesSheet)
}
})
.sheet(isPresented: $isAddSavedLocationsSheetOpen, content: {
AddFavoriteLocationsSheet()
.environmentObject(sheetEnvironment)
})
.sheet(isPresented: $isFavoriteLocationSheetOpen, content: {
FavoriteLocationsSheet()
.environmentObject(sheetEnvironment)
})
.sheet(isPresented: $isFavoriteLocationDetailSheetOpen, content: {
FavoriteLocationDetailSheet()
.environmentObject(sheetEnvironment)
})
.confirmationDialog("", isPresented: $isShowFavoriteConfirmationDialog, actions: {
favoriteSectionConfirmationDialog()
})
}

private func recentsSection() -> some View {
Expand All @@ -137,13 +116,9 @@ public struct OriginDestinationSheetView: View {
})
}, header: {
SectionHeaderView(text: "Recents") {
isRecentLocationSheetOpen.toggle()
presentationManager.present(.moreRecentsSheet)
}
})
.sheet(isPresented: $isRecentLocationSheetOpen, content: {
RecentLocationsSheet()
.environmentObject(sheetEnvironment)
})
)
}

Expand Down Expand Up @@ -219,7 +194,7 @@ public struct OriginDestinationSheetView: View {
}
.padding()

searchView()
SearchView(placeholder: "Search for a place", searchText: $search, isSearchFocused: _isSearchFocused)
.padding(.horizontal, 16)

List {
Expand All @@ -239,15 +214,34 @@ public struct OriginDestinationSheetView: View {

Spacer()
}
.alert(isPresented: $isShowErrorAlert) {
Alert(title: Text(errorTitle),
message: Text(errorMessage),
dismissButton: .cancel(Text("Ok")))
}
.onAppear {
sheetEnvironment.refreshFavoriteLocations()
sheetEnvironment.refreshRecentLocations()
}
.sheet(item: $presentationManager.activePresentation) { presentation in
switch presentation {
case .addFavoriteSheet:
AddFavoriteLocationsSheet()
.environmentObject(sheetEnvironment)
case .moreFavoritesSheet:
MoreFavoriteLocationsSheet()
.environmentObject(sheetEnvironment)
case .favoriteDetailsSheet:
FavoriteLocationDetailSheet()
.environmentObject(sheetEnvironment)
case .moreRecentsSheet:
MoreRecentLocationsSheet()
.environmentObject(sheetEnvironment)
}
}
.alert(isPresented: $isShowErrorAlert) {
Alert(title: Text(errorTitle),
message: Text(errorMessage),
dismissButton: .cancel(Text("OK")))
}
.confirmationDialog("", isPresented: $isShowFavoriteConfirmationDialog, actions: {
favoriteSectionConfirmationDialog()
})
}
}

Expand Down
25 changes: 25 additions & 0 deletions OTPKit/Miscellaneous/PresentationManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// PresentationManager.swift
// OTPKit
//
// Created by Aaron Brethorst on 8/11/24.
//

import SwiftUI

/// Manages the presentation state of dependent modal sheets.
///
/// In other words, instead of having to maintain several independent boolean values for determining which
/// sheet is currently visible, you can use `PresentationManager` to DRY up and orchestrate your
/// modal sheet state.
class PresentationManager<PresentationType: Identifiable>: ObservableObject {
@Published var activePresentation: PresentationType?

func present(_ presentationType: PresentationType) {
activePresentation = presentationType
}

func dismiss() {
activePresentation = nil
}
}
5 changes: 2 additions & 3 deletions OTPKitDemo/MapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public struct MapView: View {
.sheet(isPresented: isPlanResponsePresented, content: {
TripPlannerSheetView()
.presentationDetents([.medium, .large])
.interactiveDismissDisabled()
.interactiveDismissDisabled()
})
.sheet(isPresented: isStepsViewPresented, onDismiss: {
locationManagerService.resetTripPlanner()
Expand All @@ -87,8 +87,7 @@ public struct MapView: View {
} else if locationManagerService.isMapMarkingMode {
MapMarkingView()
} else if locationManagerService.selectedItinerary != nil,
locationManagerService.isStepsViewPresented == false
{
locationManagerService.isStepsViewPresented == false {
VStack {
Spacer()
TripPlannerView()
Expand Down

0 comments on commit c952a9c

Please sign in to comment.