@@ -5,6 +5,7 @@ struct SportsGroundsMapView: View {
55 @EnvironmentObject private var network : CheckNetworkService
66 @EnvironmentObject private var defaults : DefaultsService
77 @StateObject private var viewModel = SportsGroundsMapViewModel ( )
8+ @State private var presentation = Presentation . map
89 @State private var needUpdateRecent = false
910 @State private var showErrorAlert = false
1011 @State private var alertMessage = " "
@@ -14,39 +15,25 @@ struct SportsGroundsMapView: View {
1415
1516 var body : some View {
1617 NavigationView {
17- ZStack {
18- MapViewUI (
19- " SportsGroundsMapView " ,
20- viewModel. region,
21- viewModel. sportsGrounds,
22- $viewModel. needUpdateAnnotations,
23- $viewModel. needUpdateRegion,
24- $viewModel. ignoreUserLocation,
25- openDetailsClbk: openDetailsView
26- )
27- . opacity ( mapOpacity)
28- . animation ( . easeInOut, value: viewModel. isLoading)
29- ProgressView ( )
30- . opacity ( viewModel. isLoading ? 1 : 0 )
31- }
32- . overlay ( alignment: viewModel. isRegionSet ? . bottom : . center) {
33- NavigationLink ( isActive: $showDetailsView) {
34- SportsGroundDetailView (
35- for: viewModel. selectedGround,
36- onDeletion: updateDeleted
37- )
38- } label: { EmptyView ( ) }
39- locationSettingsReminder
18+ VStack {
19+ segmentedControl
20+ groundsContent
21+ . disabled ( viewModel. isLoading)
22+ . animation ( . easeInOut, value: viewModel. isLoading)
23+ . overlay {
24+ ProgressView ( )
25+ . opacity ( viewModel. isLoading ? 1 : 0 )
26+ }
4027 }
4128 . onChange ( of: viewModel. errorMessage, perform: setupErrorAlert)
42- . onChange ( of: defaults. mainUserCountryID , perform: updateFilterCountry )
29+ . onChange ( of: defaults. mainUserInfo , perform: updateFilterForUser )
4330 . alert ( alertMessage, isPresented: $showErrorAlert) {
4431 Button ( " Ok " , action: closeAlert)
4532 }
4633 . task { await askForGrounds ( ) }
4734 . onAppear {
4835 viewModel. onAppearAction ( )
49- updateFilterCountry ( countryID : defaults. mainUserCountryID )
36+ updateFilterForUser ( info : defaults. mainUserInfo )
5037 }
5138 . onDisappear { viewModel. onDisappearAction ( ) }
5239 . toolbar {
@@ -61,14 +48,20 @@ struct SportsGroundsMapView: View {
6148 rightBarButton
6249 }
6350 }
64- . navigationTitle ( " Площадки " )
65- . navigationBarTitleDisplayMode ( needToHideMap ? . large : . inline )
51+ . navigationTitle ( " Площадки ( \( viewModel . sportsGrounds . count ) ) " )
52+ . navigationBarTitleDisplayMode ( navigationTitleDisplayMode )
6653 }
6754 . navigationViewStyle ( . stack)
6855 }
6956}
7057
7158private extension SportsGroundsMapView {
59+ /// Вариант отображения площадок на экране
60+ enum Presentation : String , CaseIterable , Equatable {
61+ case map = " Карта "
62+ case list = " Список "
63+ }
64+
7265 var filterButton : some View {
7366 Button {
7467 showFilters. toggle ( )
@@ -86,19 +79,70 @@ private extension SportsGroundsMapView {
8679 }
8780 }
8881
82+ var segmentedControl : some View {
83+ Picker ( " Способ отображения " , selection: $presentation) {
84+ ForEach ( Presentation . allCases, id: \. self) {
85+ Text ( $0. rawValue)
86+ . accessibilityIdentifier ( $0. rawValue)
87+ }
88+ }
89+ . pickerStyle ( . segmented)
90+ . padding ( . horizontal)
91+ }
92+
93+ @ViewBuilder
94+ var groundsContent : some View {
95+ switch presentation {
96+ case . list:
97+ List ( viewModel. sportsGrounds) { ground in
98+ NavigationLink {
99+ SportsGroundDetailView (
100+ for: ground,
101+ onDeletion: updateDeleted
102+ )
103+ } label: {
104+ SportsGroundViewCell ( model: ground)
105+ }
106+ . accessibilityIdentifier ( " SportsGroundViewCell " )
107+ }
108+ . opacity ( viewModel. isLoading ? 0.5 : 1 )
109+ case . map:
110+ MapViewUI (
111+ " SportsGroundsMapView " ,
112+ viewModel. region,
113+ viewModel. ignoreUserLocation,
114+ viewModel. sportsGrounds,
115+ $viewModel. needUpdateAnnotations,
116+ $viewModel. needUpdateRegion,
117+ openDetailsClbk: openDetailsView
118+ )
119+ . opacity ( mapOpacity)
120+ . overlay ( alignment: viewModel. isRegionSet ? . bottom : . center) {
121+ NavigationLink ( isActive: $showDetailsView) {
122+ SportsGroundDetailView (
123+ for: viewModel. selectedGround,
124+ onDeletion: updateDeleted
125+ )
126+ } label: { EmptyView ( ) }
127+ locationSettingsReminder
128+ }
129+ }
130+ }
131+
132+ var navigationTitleDisplayMode : NavigationBarItem . TitleDisplayMode {
133+ switch presentation {
134+ case . list: return . inline
135+ case . map: return needToHideMap ? . large : . inline
136+ }
137+ }
138+
89139 var needToHideMap : Bool {
90140 !viewModel. isRegionSet && viewModel. ignoreUserLocation
91141 }
92142
93143 var mapOpacity : Double {
94- if needToHideMap {
95- return . zero
96- }
97- if viewModel. isLoading {
98- return 0.5
99- } else {
100- return 1
101- }
144+ guard !needToHideMap else { return . zero }
145+ return viewModel. isLoading ? 0.5 : 1
102146 }
103147
104148 var isLeftToolbarPartDisabled : Bool {
@@ -150,8 +194,8 @@ private extension SportsGroundsMapView {
150194 ContentInSheet ( title: " Новая площадка " , spacing: . zero) {
151195 SportsGroundFormView (
152196 . createNew(
153- address: $ viewModel. addressString,
154- coordinate: $ viewModel. region. center,
197+ address: viewModel. addressString,
198+ coordinate: viewModel. region. center,
155199 cityID: defaults. mainUserCityID
156200 ) ,
157201 refreshClbk: updateRecent
@@ -173,10 +217,13 @@ private extension SportsGroundsMapView {
173217 }
174218
175219 func updateDeleted( groundID: Int ) {
176- viewModel. deleteSportsGroundFromList ( )
220+ viewModel. deleteSportsGroundFromList ( with : groundID )
177221 }
178222
179- func updateFilterCountry( countryID: Int ) {
223+ /// Обновляем фильтр
224+ ///
225+ /// Параметр не используем, т.к. передаем `defaults` во вьюмодель
226+ func updateFilterForUser( info: UserResponse ? ) {
180227 viewModel. updateFilter ( with: defaults)
181228 }
182229
0 commit comments