appointment reminder & weather
parent
7bf69c52f0
commit
2b0f8b45b0
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,9 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.00439 1.5C9.41861 1.5 9.75439 1.83579 9.75439 2.25V4.50003L10.1913 4.50001C10.323 4.49992 10.4848 4.4998 10.6171 4.51636L10.6196 4.51667C10.7144 4.5285 11.1465 4.58237 11.3522 5.00657C11.5585 5.43169 11.332 5.80679 11.283 5.88795L11.0287 6.23932C10.8077 6.52119 10.5034 6.90703 10.2181 7.20028C10.0757 7.34661 9.91277 7.49754 9.73959 7.61668C9.58565 7.72258 9.323 7.87503 9 7.87503C8.677 7.87503 8.41436 7.72258 8.26041 7.61668C8.08723 7.49754 7.92428 7.34661 7.78191 7.20028C7.49659 6.90703 7.19231 6.52118 6.97134 6.23931L6.71698 5.88795C6.66799 5.80679 6.44154 5.43169 6.64776 5.00657C6.85353 4.58237 7.28556 4.5285 7.38039 4.51667L7.3829 4.51636C7.51523 4.49981 7.67697 4.49992 7.8087 4.50001L8.25439 4.50003V2.25C8.25439 1.83579 8.59018 1.5 9.00439 1.5Z" fill="#2E3039"/>
|
||||
<path d="M14.3028 8.50787C14.5957 8.21498 14.5957 7.7401 14.3028 7.44721C14.0099 7.15432 13.535 7.15432 13.2421 7.44721L12.4466 8.2427C12.1537 8.5356 12.1537 9.01047 12.4466 9.30336C12.7395 9.59626 13.2144 9.59626 13.5073 9.30336L14.3028 8.50787Z" fill="#2E3039"/>
|
||||
<path d="M4.75778 7.44767C4.46489 7.15478 3.99002 7.15478 3.69712 7.44767C3.40423 7.74057 3.40423 8.21544 3.69712 8.50833L4.49262 9.30383C4.78551 9.59672 5.26039 9.59672 5.55328 9.30383C5.84617 9.01094 5.84617 8.53606 5.55328 8.24317L4.75778 7.44767Z" fill="#2E3039"/>
|
||||
<path d="M2.25 12.0005C1.83579 12.0005 1.5 12.3363 1.5 12.7505C1.5 13.1648 1.83579 13.5005 2.25 13.5005H3.375C3.78921 13.5005 4.125 13.1648 4.125 12.7505C4.125 12.3363 3.78921 12.0005 3.375 12.0005H2.25Z" fill="#2E3039"/>
|
||||
<path d="M14.625 12.0005C14.2108 12.0005 13.875 12.3363 13.875 12.7505C13.875 13.1648 14.2108 13.5005 14.625 13.5005H15.75C16.1642 13.5005 16.5 13.1648 16.5 12.7505C16.5 12.3363 16.1642 12.0005 15.75 12.0005H14.625Z" fill="#2E3039"/>
|
||||
<path d="M16.5 15.75C16.5 16.1642 16.1642 16.5 15.75 16.5L2.25 16.5C1.83579 16.5 1.5 16.1642 1.5 15.75C1.5 15.3358 1.83579 15 2.25 15L15.75 15C16.1642 15 16.5 15.3358 16.5 15.75Z" fill="#2E3039"/>
|
||||
<path d="M9 9C6.92893 9 5.25 10.6789 5.25 12.75C5.25 13.1642 5.58579 13.5 6 13.5H12C12.4142 13.5 12.75 13.1642 12.75 12.75C12.75 10.6789 11.0711 9 9 9Z" fill="#2E3039"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,9 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.00439 7.87503C9.41861 7.87503 9.75439 7.53924 9.75439 7.12503L9.75439 4.875L10.1913 4.87501C10.323 4.87511 10.4848 4.87522 10.6171 4.85867L10.6196 4.85836C10.7144 4.84653 11.1465 4.79266 11.3522 4.36846C11.5585 3.94334 11.332 3.56824 11.283 3.48708L11.0287 3.13571C10.8077 2.85384 10.5034 2.468 10.2181 2.17474C10.0757 2.02841 9.91277 1.87749 9.73959 1.75835C9.58565 1.65245 9.323 1.5 9 1.5C8.677 1.5 8.41436 1.65245 8.26041 1.75835C8.08723 1.87749 7.92428 2.02841 7.78191 2.17474C7.49658 2.468 7.19231 2.85385 6.97134 3.13572L6.71698 3.48708C6.66799 3.56823 6.44154 3.94334 6.64776 4.36846C6.85353 4.79265 7.28556 4.84653 7.38039 4.85836L7.38291 4.85867C7.51523 4.87522 7.67697 4.87511 7.8087 4.87501L8.25439 4.875L8.25439 7.12503C8.25439 7.53924 8.59018 7.87503 9.00439 7.87503Z" fill="#2E3039"/>
|
||||
<path d="M14.3028 8.5079C14.5957 8.215 14.5957 7.74013 14.3028 7.44724C14.0099 7.15434 13.535 7.15434 13.2421 7.44724L12.4466 8.24273C12.1537 8.53563 12.1537 9.0105 12.4466 9.30339C12.7395 9.59629 13.2144 9.59629 13.5073 9.30339L14.3028 8.5079Z" fill="#2E3039"/>
|
||||
<path d="M4.75778 7.4477C4.46489 7.15481 3.99002 7.15481 3.69712 7.4477C3.40423 7.74059 3.40423 8.21547 3.69712 8.50836L4.49262 9.30386C4.78551 9.59675 5.26039 9.59675 5.55328 9.30386C5.84617 9.01096 5.84617 8.53609 5.55328 8.2432L4.75778 7.4477Z" fill="#2E3039"/>
|
||||
<path d="M2.25 12.0006C1.83579 12.0006 1.5 12.3364 1.5 12.7506C1.5 13.1648 1.83579 13.5006 2.25 13.5006H3.375C3.78921 13.5006 4.125 13.1648 4.125 12.7506C4.125 12.3364 3.78921 12.0006 3.375 12.0006H2.25Z" fill="#2E3039"/>
|
||||
<path d="M14.625 12.0006C14.2108 12.0006 13.875 12.3364 13.875 12.7506C13.875 13.1648 14.2108 13.5006 14.625 13.5006H15.75C16.1642 13.5006 16.5 13.1648 16.5 12.7506C16.5 12.3364 16.1642 12.0006 15.75 12.0006H14.625Z" fill="#2E3039"/>
|
||||
<path d="M16.5 15.75C16.5 16.1642 16.1642 16.5 15.75 16.5L2.25 16.5C1.83579 16.5 1.5 16.1642 1.5 15.75C1.5 15.3358 1.83579 15 2.25 15L15.75 15C16.1642 15 16.5 15.3358 16.5 15.75Z" fill="#2E3039"/>
|
||||
<path d="M9 9.00003C6.92893 9.00003 5.25 10.679 5.25 12.75C5.25 13.1642 5.58579 13.5 6 13.5H12C12.4142 13.5 12.75 13.1642 12.75 12.75C12.75 10.679 11.0711 9.00003 9 9.00003Z" fill="#2E3039"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,257 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class GetCityInfoList {
|
||||
CategoriesNames? categoriesNames;
|
||||
String? category;
|
||||
String? categoryValue;
|
||||
int? cityId;
|
||||
String? cityName;
|
||||
String? cityNameN;
|
||||
ColorName? colorName;
|
||||
String? createdOn;
|
||||
String? id;
|
||||
int? iniceId;
|
||||
bool? isOrderEmpty;
|
||||
bool? isValuesReversed;
|
||||
bool? language;
|
||||
double? latitude;
|
||||
double? longitude;
|
||||
String? name;
|
||||
int? orderNum;
|
||||
double? temperature;
|
||||
String? value;
|
||||
|
||||
GetCityInfoList({
|
||||
this.categoriesNames,
|
||||
this.category,
|
||||
this.categoryValue,
|
||||
this.cityId,
|
||||
this.cityName,
|
||||
this.cityNameN,
|
||||
this.colorName,
|
||||
this.createdOn,
|
||||
this.id,
|
||||
this.iniceId,
|
||||
this.isOrderEmpty,
|
||||
this.isValuesReversed,
|
||||
this.language,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.name,
|
||||
this.orderNum,
|
||||
this.temperature,
|
||||
this.value,
|
||||
});
|
||||
|
||||
factory GetCityInfoList.fromRawJson(String str) => GetCityInfoList.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory GetCityInfoList.fromJson(Map<String, dynamic> json) {
|
||||
ColorName? parseColorName(dynamic value) {
|
||||
if (value == null) return null;
|
||||
try {
|
||||
return colorNameValues.map[value.toString()];
|
||||
} catch (e) {
|
||||
print("Unknown color name: $value");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
CategoriesNames? parseCategoriesNames(dynamic value) {
|
||||
if (value == null) return null;
|
||||
try {
|
||||
return CategoriesNames.fromJson(value as Map<String, dynamic>);
|
||||
} catch (e) {
|
||||
print("Error parsing CategoriesNames: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return GetCityInfoList(
|
||||
categoriesNames: parseCategoriesNames(json["CategoriesNames"]),
|
||||
category: json["Category"],
|
||||
categoryValue: json["CategoryValue"],
|
||||
cityId: json["CityID"],
|
||||
cityName: json["CityName"],
|
||||
cityNameN: json["CityNameN"],
|
||||
colorName: parseColorName(json["ColorName"]),
|
||||
createdOn: json["CreatedOn"],
|
||||
id: json["ID"],
|
||||
iniceId: json["IniceID"],
|
||||
isOrderEmpty: json["IsOrderEmpty"],
|
||||
isValuesReversed: json["IsValuesReversed"],
|
||||
language: json["Language"],
|
||||
latitude: json["Latitude"]?.toDouble(),
|
||||
longitude: json["Longitude"]?.toDouble(),
|
||||
name: json["Name"],
|
||||
orderNum: json["OrderNum"],
|
||||
temperature: json["Temperature"]?.toDouble(),
|
||||
value: json["Value"],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"CategoriesNames": categoriesNames?.toJson(),
|
||||
"Category": category,
|
||||
"CategoryValue": categoryValue,
|
||||
"CityID": cityId,
|
||||
"CityName": cityName,
|
||||
"CityNameN": cityNameN,
|
||||
"ColorName": colorNameValues.reverse[colorName],
|
||||
"CreatedOn": createdOn,
|
||||
"ID": id,
|
||||
"IniceID": iniceId,
|
||||
"IsOrderEmpty": isOrderEmpty,
|
||||
"IsValuesReversed": isValuesReversed,
|
||||
"Language": language,
|
||||
"Latitude": latitude,
|
||||
"Longitude": longitude,
|
||||
"Name": name,
|
||||
"OrderNum": orderNum,
|
||||
"Temperature": temperature,
|
||||
"Value": value,
|
||||
};
|
||||
}
|
||||
|
||||
class CategoriesNames {
|
||||
Category1? category1;
|
||||
Category2? category2;
|
||||
Category3? category3;
|
||||
Category4? category4;
|
||||
Category5? category5;
|
||||
|
||||
CategoriesNames({
|
||||
this.category1,
|
||||
this.category2,
|
||||
this.category3,
|
||||
this.category4,
|
||||
this.category5,
|
||||
});
|
||||
|
||||
factory CategoriesNames.fromRawJson(String str) => CategoriesNames.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory CategoriesNames.fromJson(Map<String, dynamic> json) {
|
||||
T? parseEnum<T>(dynamic value, EnumValues<T> enumValues, String enumName) {
|
||||
if (value == null) return null;
|
||||
try {
|
||||
return enumValues.map[value.toString()];
|
||||
} catch (e) {
|
||||
print("Unknown $enumName value: $value");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return CategoriesNames(
|
||||
category1: parseEnum(json["Category1"], category1Values, "Category1"),
|
||||
category2: parseEnum(json["Category2"], category2Values, "Category2"),
|
||||
category3: parseEnum(json["Category3"], category3Values, "Category3"),
|
||||
category4: parseEnum(json["Category4"], category4Values, "Category4"),
|
||||
category5: parseEnum(json["Category5"], category5Values, "Category5"),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"Category1": category1Values.reverse[category1],
|
||||
"Category2": category2Values.reverse[category2],
|
||||
"Category3": category3Values.reverse[category3],
|
||||
"Category4": category4Values.reverse[category4],
|
||||
"Category5": category5Values.reverse[category5],
|
||||
};
|
||||
}
|
||||
|
||||
enum Category1 {
|
||||
AT_EXTREME_RISK,
|
||||
CATEGORY1_EXTREME,
|
||||
EXTREME,
|
||||
POOR
|
||||
}
|
||||
|
||||
final category1Values = EnumValues({
|
||||
"At Extreme Risk": Category1.AT_EXTREME_RISK,
|
||||
"Extreme\u000d\n": Category1.CATEGORY1_EXTREME,
|
||||
"Extreme": Category1.EXTREME,
|
||||
"Poor": Category1.POOR
|
||||
});
|
||||
|
||||
enum Category2 {
|
||||
AT_HIGH_RISK,
|
||||
CATEGORY2_VERY_HIGH,
|
||||
FAIR,
|
||||
VERY_HIGH
|
||||
}
|
||||
|
||||
final category2Values = EnumValues({
|
||||
"At High Risk": Category2.AT_HIGH_RISK,
|
||||
"Very High\u000d\n": Category2.CATEGORY2_VERY_HIGH,
|
||||
"Fair": Category2.FAIR,
|
||||
"Very High": Category2.VERY_HIGH
|
||||
});
|
||||
|
||||
enum Category3 {
|
||||
AT_RISK,
|
||||
CATEGORY3_HIGH,
|
||||
GOOD,
|
||||
HIGH
|
||||
}
|
||||
|
||||
final category3Values = EnumValues({
|
||||
"At Risk": Category3.AT_RISK,
|
||||
"High\u000d\n": Category3.CATEGORY3_HIGH,
|
||||
"Good": Category3.GOOD,
|
||||
"High": Category3.HIGH
|
||||
});
|
||||
|
||||
enum Category4 {
|
||||
CATEGORY4_MODERATE,
|
||||
MODERATE,
|
||||
NEUTRAL,
|
||||
VERY_GOOD
|
||||
}
|
||||
|
||||
final category4Values = EnumValues({
|
||||
"Moderate\u000d\n": Category4.CATEGORY4_MODERATE,
|
||||
"Moderate": Category4.MODERATE,
|
||||
"Neutral": Category4.NEUTRAL,
|
||||
"Very Good": Category4.VERY_GOOD
|
||||
});
|
||||
|
||||
enum Category5 {
|
||||
BENEFICIAL,
|
||||
CATEGORY5_LOW,
|
||||
EXCELLENT,
|
||||
LOW
|
||||
}
|
||||
|
||||
final category5Values = EnumValues({
|
||||
"Beneficial": Category5.BENEFICIAL,
|
||||
"Low\u000d\n": Category5.CATEGORY5_LOW,
|
||||
"Excellent": Category5.EXCELLENT,
|
||||
"Low": Category5.LOW
|
||||
});
|
||||
|
||||
enum ColorName {
|
||||
GREEN,
|
||||
ORANGE,
|
||||
RED
|
||||
}
|
||||
|
||||
final colorNameValues = EnumValues({
|
||||
"green": ColorName.GREEN,
|
||||
"orange": ColorName.ORANGE,
|
||||
"red": ColorName.RED
|
||||
});
|
||||
|
||||
class EnumValues<T> {
|
||||
Map<String, T> map;
|
||||
late Map<T, String> reverseMap;
|
||||
|
||||
EnumValues(this.map);
|
||||
|
||||
Map<T, String> get reverse {
|
||||
reverseMap = map.map((k, v) => MapEntry(v, k));
|
||||
return reverseMap;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:hmg_patient_app_new/core/api/api_client.dart';
|
||||
import 'package:hmg_patient_app_new/core/api_consts.dart';
|
||||
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
|
||||
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
|
||||
import 'package:hmg_patient_app_new/core/location_util.dart';
|
||||
import 'package:hmg_patient_app_new/features/weather/models/waether_cities_model.dart';
|
||||
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||
|
||||
abstract class WeatherRepo {
|
||||
Future<Either<Failure, GenericApiModel<List<GetCityInfoList>>>> getCityInfo();
|
||||
}
|
||||
|
||||
class WeatherRepoImp implements WeatherRepo {
|
||||
final ApiClient apiClient;
|
||||
final LoggerService loggerService;
|
||||
|
||||
WeatherRepoImp({required this.loggerService, required this.apiClient});
|
||||
|
||||
@override
|
||||
Future<Either<Failure, GenericApiModel<List<GetCityInfoList>>>> getCityInfo() async {
|
||||
Map<String, dynamic> request = {};
|
||||
|
||||
try {
|
||||
GenericApiModel<List<GetCityInfoList>>? apiResponse;
|
||||
Failure? failure;
|
||||
await apiClient.post(
|
||||
WEATHER_INDICATOR,
|
||||
body: request,
|
||||
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||
failure = failureType;
|
||||
},
|
||||
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||
try {
|
||||
loggerService.logInfo("Weather API Response: $response");
|
||||
final list = response['GetCityInfo_List'];
|
||||
|
||||
if (list == null || list.isEmpty) {
|
||||
loggerService.logInfo("Weather API returned empty or null list");
|
||||
// Return empty list if no city info
|
||||
apiResponse = GenericApiModel<List<GetCityInfoList>>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: [],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
loggerService.logInfo("Parsing ${list.length} city info items");
|
||||
final cityInfoList = list.map((item) => GetCityInfoList.fromJson(item as Map<String, dynamic>)).toList().cast<GetCityInfoList>();
|
||||
|
||||
apiResponse = GenericApiModel<List<GetCityInfoList>>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: cityInfoList,
|
||||
);
|
||||
} catch (e) {
|
||||
loggerService.logError("Error parsing weather data: $e");
|
||||
failure = DataParsingFailure(e.toString());
|
||||
}
|
||||
},
|
||||
);
|
||||
if (failure != null) return Left(failure!);
|
||||
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
|
||||
return Right(apiResponse!);
|
||||
} catch (e) {
|
||||
return Left(UnknownFailure(e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hmg_patient_app_new/core/location_util.dart';
|
||||
import 'package:hmg_patient_app_new/features/weather/models/waether_cities_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/weather/weather_repo.dart';
|
||||
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
|
||||
|
||||
class WeatherMonitorViewModel extends ChangeNotifier {
|
||||
WeatherRepo weatherRepo;
|
||||
ErrorHandlerService errorHandlerService;
|
||||
LocationUtils locationUtils;
|
||||
|
||||
WeatherMonitorViewModel({required this.weatherRepo, required this.errorHandlerService, required this.locationUtils});
|
||||
|
||||
final List<GetCityInfoList> _cityInfoList = [];
|
||||
bool isLoading = false;
|
||||
|
||||
List<GetCityInfoList> get cityInfoList => _cityInfoList;
|
||||
|
||||
Future<void> fetchCityInfoList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||
isLoading = true;
|
||||
_cityInfoList.clear();
|
||||
|
||||
locationUtils.getLocation(
|
||||
isShowConfirmDialog: true,
|
||||
onSuccess: (position) async {
|
||||
final result = await weatherRepo.getCityInfo();
|
||||
result.fold(
|
||||
(failure) async {
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
await errorHandlerService.handleError(failure: failure);
|
||||
if (onError != null) {
|
||||
onError(failure.toString());
|
||||
}
|
||||
},
|
||||
(apiResponse) {
|
||||
isLoading = false;
|
||||
if (apiResponse.messageStatus == 2) {
|
||||
notifyListeners();
|
||||
if (onError != null) {
|
||||
onError(apiResponse.errorMessage ?? "Unknown error");
|
||||
}
|
||||
} else if (apiResponse.messageStatus == 1) {
|
||||
final cities = apiResponse.data ?? [];
|
||||
_cityInfoList.addAll(cities);
|
||||
notifyListeners();
|
||||
if (onSuccess != null) {
|
||||
onSuccess(apiResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue