Line data Source code
1 : // ignore_for_file: avoid_bool_literals_in_conditional_expressions, always_specify_types
2 :
3 : import 'dart:async';
4 : import 'dart:io';
5 :
6 : import 'package:flutter_map/flutter_map.dart';
7 : import 'package:equatable/equatable.dart';
8 : import 'package:flutter_bloc/flutter_bloc.dart';
9 : import 'package:latlong2/latlong.dart';
10 : import 'package:memories_app/routes/create_story/model/story_request_model.dart';
11 : import 'package:memories_app/routes/edit_story/model/edit_story_repository.dart';
12 : import 'package:memories_app/routes/edit_story/model/edit_story_response_model.dart';
13 : import 'package:memories_app/routes/story_detail/model/tag_model.dart';
14 :
15 : part 'edit_story_event.dart';
16 :
17 : part 'edit_story_state.dart';
18 :
19 : class _Constants {
20 : static const String offlineMessage =
21 : 'You are currently offline.\n Please check your internet connection!';
22 : }
23 :
24 : class EditStoryBloc extends Bloc<EditStoryEvent, EditStoryState> {
25 : final EditStoryRepository _repository;
26 :
27 1 : EditStoryBloc({required EditStoryRepository repository})
28 : : _repository = repository,
29 1 : super(const EditStoryState()) {
30 2 : on<EditStoryUpdateStoryEvent>(_updateStoryEvent);
31 2 : on<EditStoryErrorPopupClosedEvent>(_onErrorPopupClosed);
32 : }
33 : late StoryRequestModel storyModel;
34 :
35 1 : Future<void> _updateStoryEvent(
36 : EditStoryUpdateStoryEvent event, Emitter<EditStoryState> emit) async {
37 2 : storyModel = _createStoryModel(event);
38 : EditStoryResponseModel? response;
39 : try {
40 4 : response = await _repository.editStory(storyModel, event.id);
41 0 : } on SocketException {
42 0 : emit(const EditStoryOffline(offlineMessage: _Constants.offlineMessage));
43 : } catch (error) {
44 0 : emit(EditStoryFailure(error: error.toString()));
45 : }
46 : if (response != null) {
47 2 : if (response.success == true) {
48 1 : emit(const EditStorySuccess());
49 : } else {
50 4 : emit(EditStoryFailure(error: response.msg.toString()));
51 : }
52 : }
53 : }
54 :
55 1 : void _onErrorPopupClosed(
56 : EditStoryErrorPopupClosedEvent event, Emitter<EditStoryState> emit) {
57 1 : emit(const EditStoryState());
58 : }
59 :
60 1 : StoryRequestModel _createStoryModel(EditStoryUpdateStoryEvent event) {
61 3 : final String dateType = mapDateTypeToValue(event.dateType.toLowerCase());
62 1 : StoryRequestModel createStoryModel = StoryRequestModel(
63 1 : title: event.title,
64 1 : content: event.content,
65 1 : storyTags: event.storyTags,
66 1 : locationIds: createLocationId(
67 1 : event.markersForPoint,
68 1 : event.circleMarkers,
69 1 : event.polygons,
70 1 : event.polyLines,
71 1 : event.pointAdresses,
72 1 : event.circleAdresses,
73 1 : event.polylineAdresses),
74 : dateType: dateType,
75 1 : date: dateType == "normal_date" ? event.date : null,
76 1 : decade: dateType == "decade" ? extractDecade(event.decade) : null,
77 1 : endDate: dateType == "interval_date" ? event.endDate : null,
78 1 : endYear: dateType == "year_interval" ? event.endYear : null,
79 1 : includeTime: _includeTime(dateType, event) ? true : false,
80 1 : seasonName: dateType == "year" || dateType == "year_interval"
81 1 : ? event.seasonName
82 : : null,
83 1 : startDate: dateType == "interval_date" ? event.startDate : null,
84 1 : startYear: dateType == "year_interval" ? event.startYear : null,
85 2 : year: dateType == "year" ? event.year : null,
86 : );
87 : return createStoryModel;
88 : }
89 :
90 1 : bool _includeTime(String dateType, EditStoryUpdateStoryEvent event) {
91 1 : return dateType.contains("normal_date") &&
92 0 : (event.startDate != null &&
93 0 : event.startDate!.isNotEmpty &&
94 0 : event.startDate!.contains(" ")) ||
95 1 : (event.date != null &&
96 0 : event.date!.isNotEmpty &&
97 0 : event.date!.contains(" ")) ||
98 1 : (event.endDate != null &&
99 0 : event.endDate!.isNotEmpty &&
100 0 : event.endDate!.contains(" "));
101 : }
102 :
103 1 : List<LocationId> createLocationId(
104 : List<Marker>? markersForPoint,
105 : List<CircleMarker>? circleMarkers,
106 : List<Polygon>? polygons,
107 : List<Polyline>? polyLines,
108 : List<String>? pointAdresses,
109 : List<String>? circleAdresses,
110 : List<String>? polylineAdresses) {
111 1 : List<LocationId> locationIds = [];
112 1 : if (markersForPoint != null && markersForPoint.isNotEmpty) {
113 1 : createPointLocations(markersForPoint, pointAdresses, locationIds);
114 : }
115 :
116 1 : if (circleMarkers != null && circleMarkers.isNotEmpty) {
117 1 : createCircleLocations(circleMarkers, circleAdresses, locationIds);
118 : }
119 1 : if (polygons != null && polygons.isNotEmpty) {
120 1 : createPolygonLocations(polygons, locationIds);
121 : }
122 :
123 1 : if (polyLines != null && polyLines.isNotEmpty) {
124 1 : createPolylineLocations(polyLines, polylineAdresses, locationIds);
125 : }
126 :
127 : return locationIds;
128 : }
129 :
130 1 : void createPolylineLocations(List<Polyline> polyLines,
131 : List<String>? polylineAdresses, List<LocationId> locationIds) {
132 3 : for (int i = 0; i < polyLines.length; i++) {
133 1 : List<List<double>> coordinates = [];
134 :
135 3 : if (polyLines[i].points.isNotEmpty) {
136 3 : for (LatLng point in polyLines[i].points) {
137 3 : List<double> coordinatesList = [point.longitude, point.latitude];
138 1 : coordinates.add(coordinatesList);
139 : }
140 : }
141 :
142 1 : LocationId locationId = LocationId(
143 1 : name: polylineAdresses != null && polylineAdresses.isNotEmpty
144 1 : ? polylineAdresses[i]
145 : : "Address not found",
146 1 : line: LineStringLocation(coordinates: coordinates),
147 : );
148 :
149 1 : locationIds.add(locationId);
150 : }
151 : }
152 :
153 1 : void createPolygonLocations(
154 : List<Polygon> polygons, List<LocationId> locationIds) {
155 3 : for (int i = 0; i < polygons.length; i++) {
156 1 : List<List<List<double>>> coordinates = [];
157 :
158 3 : if (polygons[i].points.isNotEmpty) {
159 1 : List<List<double>> singlePolygon = [];
160 :
161 3 : LatLng firstPoint = polygons[i].points.first;
162 1 : List<double> firstCoordinates = [
163 1 : firstPoint.longitude,
164 1 : firstPoint.latitude
165 : ];
166 :
167 3 : for (LatLng point in polygons[i].points) {
168 3 : List<double> coordinatesList = [point.longitude, point.latitude];
169 1 : singlePolygon.add(coordinatesList);
170 : }
171 :
172 : // Add the first coordinate again to close the polygon
173 1 : singlePolygon.add(firstCoordinates);
174 :
175 1 : coordinates.add(singlePolygon);
176 : }
177 :
178 1 : LocationId polygon = LocationId(
179 2 : name: polygons[i].label ?? "Address not found",
180 1 : polygon: PolygonLocation(coordinates: coordinates),
181 : );
182 :
183 1 : locationIds.add(polygon);
184 : }
185 : }
186 :
187 1 : void createCircleLocations(List<CircleMarker> circleMarkers,
188 : List<String>? circleAdresses, List<LocationId> locationIds) {
189 3 : for (int i = 0; i < circleMarkers.length; i++) {
190 1 : LocationId circleLocation = LocationId(
191 1 : name: circleAdresses != null && circleAdresses.isNotEmpty
192 1 : ? circleAdresses[i]
193 : : "Adress not found",
194 1 : circle: PointLocation(
195 1 : coordinates: [
196 3 : circleMarkers[i].point.longitude,
197 3 : circleMarkers[i].point.latitude
198 : ],
199 : ),
200 4 : radius: double.parse((circleMarkers[i].radius).toStringAsFixed(10)),
201 : );
202 1 : locationIds.add(circleLocation);
203 : }
204 : }
205 :
206 1 : void createPointLocations(List<Marker> markersForPoint,
207 : List<String>? pointAdresses, List<LocationId> locationIds) {
208 3 : for (int i = 0; i < markersForPoint.length; i++) {
209 1 : LocationId pointLocation = LocationId(
210 1 : name: pointAdresses != null && pointAdresses.isNotEmpty
211 1 : ? pointAdresses[i]
212 : : "Adress not found",
213 1 : point: PointLocation(
214 1 : coordinates: [
215 3 : markersForPoint[i].point.longitude,
216 3 : markersForPoint[i].point.latitude
217 : ],
218 : ),
219 : );
220 1 : locationIds.add(pointLocation);
221 : }
222 : }
223 :
224 1 : int? extractDecade(String? decade) {
225 1 : if (decade == null || decade.isEmpty) {
226 : return null;
227 : }
228 :
229 : // Remove trailing 's' and parse the remaining part as an integer
230 3 : String numericPart = decade.substring(0, decade.length - 1);
231 1 : return int.tryParse(numericPart);
232 : }
233 :
234 1 : String mapDateTypeToValue(String selectedDateType) {
235 1 : switch (selectedDateType.toLowerCase()) {
236 1 : case "year":
237 : return "year";
238 1 : case "interval year":
239 : return "year_interval";
240 1 : case "normal date":
241 : return "normal_date";
242 1 : case "interval date":
243 : return "interval_date";
244 1 : case "decade":
245 : return "decade";
246 : default:
247 : return "year";
248 : }
249 : }
250 : }
251 :
252 : enum StoryDateType {
253 : year,
254 : yearInterval,
255 : normalDate,
256 : intervalDate,
257 : decade,
258 : }
|