Indoor navigation implementation & Landing page swiper card updates
parent
1656ca58c1
commit
02930a901e
@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.98978 14.0362H21.2589C22.0592 14.0362 22.7076 13.3877 22.7076 12.5874C22.7076 11.7871 22.0592 11.1387 21.2589 11.1387H1.98978C1.18949 11.1387 0.541029 11.7871 0.541029 12.5874C0.541029 13.3877 1.18949 14.0362 1.98978 14.0362Z" fill="#2E3039"/>
|
||||
<path d="M14.6241 20.8879C14.9764 20.8879 15.3299 20.7598 15.6087 20.5013L22.9973 13.6488C23.2952 13.3723 23.4638 12.9835 23.4609 12.5767C23.458 12.1704 23.2847 11.7833 22.9828 11.511L15.3914 4.65838C14.7974 4.12234 13.8812 4.16928 13.3451 4.76327C12.8091 5.35726 12.856 6.27345 13.45 6.80949L19.8663 12.601L13.6384 18.3769C13.0519 18.921 13.0171 19.8378 13.5613 20.4243C13.847 20.732 14.2347 20.8879 14.6241 20.8879Z" fill="#2E3039"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 803 B |
@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.0102 14.0362H2.74111C1.94082 14.0362 1.29236 13.3877 1.29236 12.5874C1.29236 11.7871 1.94082 11.1387 2.74111 11.1387H22.0102C22.8105 11.1387 23.459 11.7871 23.459 12.5874C23.459 13.3877 22.8105 14.0362 22.0102 14.0362Z" fill="#2E3039"/>
|
||||
<path d="M9.3759 20.8879C9.02357 20.8879 8.67007 20.7598 8.39133 20.5013L1.0027 13.6488C0.704836 13.3723 0.536202 12.9835 0.539099 12.5767C0.541997 12.1704 0.715267 11.7833 1.01719 11.511L8.60864 4.65838C9.20263 4.12234 10.1188 4.16928 10.6549 4.76327C11.1909 5.35726 11.144 6.27345 10.55 6.80949L4.13374 12.601L10.3616 18.3769C10.9481 18.921 10.9829 19.8378 10.4387 20.4243C10.153 20.732 9.76533 20.8879 9.3759 20.8879Z" fill="#2E3039"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 800 B |
@ -0,0 +1,96 @@
|
||||
class NotificationResponseModel {
|
||||
int? id;
|
||||
int? recordId;
|
||||
int? patientID;
|
||||
bool? projectOutSA;
|
||||
String? deviceType;
|
||||
String? deviceToken;
|
||||
String? message;
|
||||
String? messageType;
|
||||
String? messageTypeData;
|
||||
String? videoURL;
|
||||
bool? isQueue;
|
||||
String? isQueueOn;
|
||||
String? createdOn;
|
||||
dynamic createdBy;
|
||||
String? notificationType;
|
||||
bool? isSent;
|
||||
String? isSentOn;
|
||||
bool? isRead;
|
||||
dynamic isReadOn;
|
||||
int? channelID;
|
||||
int? projectID;
|
||||
|
||||
NotificationResponseModel(
|
||||
{this.id,
|
||||
this.recordId,
|
||||
this.patientID,
|
||||
this.projectOutSA,
|
||||
this.deviceType,
|
||||
this.deviceToken,
|
||||
this.message,
|
||||
this.messageType,
|
||||
this.messageTypeData,
|
||||
this.videoURL,
|
||||
this.isQueue,
|
||||
this.isQueueOn,
|
||||
this.createdOn,
|
||||
this.createdBy,
|
||||
this.notificationType,
|
||||
this.isSent,
|
||||
this.isSentOn,
|
||||
this.isRead,
|
||||
this.isReadOn,
|
||||
this.channelID,
|
||||
this.projectID});
|
||||
|
||||
NotificationResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['Id'];
|
||||
recordId = json['RecordId'];
|
||||
patientID = json['PatientID'];
|
||||
projectOutSA = json['ProjectOutSA'];
|
||||
deviceType = json['DeviceType'];
|
||||
deviceToken = json['DeviceToken'];
|
||||
message = json['Message'];
|
||||
messageType = json['MessageType'];
|
||||
messageTypeData = json['MessageTypeData'];
|
||||
videoURL = json['VideoURL'];
|
||||
isQueue = json['IsQueue'];
|
||||
isQueueOn = json['IsQueueOn'];
|
||||
createdOn = json['CreatedOn'];
|
||||
createdBy = json['CreatedBy'];
|
||||
notificationType = json['NotificationType'];
|
||||
isSent = json['IsSent'];
|
||||
isSentOn = json['IsSentOn'];
|
||||
isRead = json['IsRead'];
|
||||
isReadOn = json['IsReadOn'];
|
||||
channelID = json['ChannelID'];
|
||||
projectID = json['ProjectID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['Id'] = this.id;
|
||||
data['RecordId'] = this.recordId;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['ProjectOutSA'] = this.projectOutSA;
|
||||
data['DeviceType'] = this.deviceType;
|
||||
data['DeviceToken'] = this.deviceToken;
|
||||
data['Message'] = this.message;
|
||||
data['MessageType'] = this.messageType;
|
||||
data['MessageTypeData'] = this.messageTypeData;
|
||||
data['VideoURL'] = this.videoURL;
|
||||
data['IsQueue'] = this.isQueue;
|
||||
data['IsQueueOn'] = this.isQueueOn;
|
||||
data['CreatedOn'] = this.createdOn;
|
||||
data['CreatedBy'] = this.createdBy;
|
||||
data['NotificationType'] = this.notificationType;
|
||||
data['IsSent'] = this.isSent;
|
||||
data['IsSentOn'] = this.isSentOn;
|
||||
data['IsRead'] = this.isRead;
|
||||
data['IsReadOn'] = this.isReadOn;
|
||||
data['ChannelID'] = this.channelID;
|
||||
data['ProjectID'] = this.projectID;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
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/features/notifications/models/resp_models/notification_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||
|
||||
abstract class NotificationsRepo {
|
||||
Future<Either<Failure, GenericApiModel<List<NotificationResponseModel>>>> getAllNotifications({
|
||||
required int notificationStatusID,
|
||||
required int pagingSize,
|
||||
required int currentPage,
|
||||
});
|
||||
}
|
||||
|
||||
class NotificationsRepoImp implements NotificationsRepo {
|
||||
final ApiClient apiClient;
|
||||
final LoggerService loggerService;
|
||||
|
||||
NotificationsRepoImp({required this.loggerService, required this.apiClient});
|
||||
|
||||
@override
|
||||
Future<Either<Failure, GenericApiModel<List<NotificationResponseModel>>>> getAllNotifications({
|
||||
required int notificationStatusID,
|
||||
required int pagingSize,
|
||||
required int currentPage,
|
||||
}) async {
|
||||
Map<String, dynamic> mapDevice = {
|
||||
"NotificationStatusID": notificationStatusID,
|
||||
"pagingSize": pagingSize,
|
||||
"currentPage": currentPage,
|
||||
};
|
||||
|
||||
try {
|
||||
GenericApiModel<List<NotificationResponseModel>>? apiResponse;
|
||||
Failure? failure;
|
||||
await apiClient.post(
|
||||
GET_ALL_NOTIFICATIONS,
|
||||
body: mapDevice,
|
||||
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||
failure = failureType;
|
||||
},
|
||||
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||
try {
|
||||
final list = response['List_GetAllNotificationsFromPool'];
|
||||
if (list == null || list.isEmpty) {
|
||||
// Return empty list if no notifications
|
||||
apiResponse = GenericApiModel<List<NotificationResponseModel>>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: [],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final notifications = list.map((item) => NotificationResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<NotificationResponseModel>();
|
||||
|
||||
apiResponse = GenericApiModel<List<NotificationResponseModel>>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: notifications,
|
||||
);
|
||||
} catch (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,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/features/notifications/models/resp_models/notification_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/notifications/notifications_repo.dart';
|
||||
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
|
||||
|
||||
class NotificationsViewModel extends ChangeNotifier {
|
||||
bool isNotificationsLoading = false;
|
||||
bool hasMoreNotifications = true;
|
||||
|
||||
NotificationsRepo notificationsRepo;
|
||||
ErrorHandlerService errorHandlerService;
|
||||
|
||||
List<NotificationResponseModel> notificationsList = [];
|
||||
|
||||
int currentPage = 0;
|
||||
int pagingSize = 14;
|
||||
int notificationStatusID = 2; // Default to status 2 (e.g., unread)
|
||||
|
||||
NotificationsViewModel({
|
||||
required this.notificationsRepo,
|
||||
required this.errorHandlerService,
|
||||
});
|
||||
|
||||
initNotificationsViewModel({int? statusID}) {
|
||||
notificationsList.clear();
|
||||
currentPage = 0;
|
||||
hasMoreNotifications = true;
|
||||
isNotificationsLoading = true;
|
||||
// if (statusID != null) {
|
||||
// notificationStatusID = statusID;
|
||||
// }
|
||||
// getAllNotifications();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setNotificationStatusID(int statusID) {
|
||||
notificationStatusID = statusID;
|
||||
notificationsList.clear();
|
||||
currentPage = 0;
|
||||
hasMoreNotifications = true;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getAllNotifications({
|
||||
Function(dynamic)? onSuccess,
|
||||
Function(String)? onError,
|
||||
}) async {
|
||||
isNotificationsLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
final result = await notificationsRepo.getAllNotifications(
|
||||
notificationStatusID: notificationStatusID,
|
||||
pagingSize: pagingSize,
|
||||
currentPage: currentPage,
|
||||
);
|
||||
|
||||
result.fold(
|
||||
(failure) async {
|
||||
isNotificationsLoading = false;
|
||||
notifyListeners();
|
||||
await errorHandlerService.handleError(failure: failure);
|
||||
if (onError != null) {
|
||||
onError(failure.toString());
|
||||
}
|
||||
},
|
||||
(apiResponse) {
|
||||
isNotificationsLoading = false;
|
||||
if (apiResponse.messageStatus == 2) {
|
||||
notifyListeners();
|
||||
if (onError != null) {
|
||||
onError(apiResponse.errorMessage ?? "Unknown error");
|
||||
}
|
||||
} else if (apiResponse.messageStatus == 1) {
|
||||
final newNotifications = apiResponse.data ?? [];
|
||||
|
||||
if (newNotifications.isEmpty || newNotifications.length < pagingSize) {
|
||||
hasMoreNotifications = false;
|
||||
}
|
||||
|
||||
notificationsList.addAll(newNotifications);
|
||||
currentPage++;
|
||||
|
||||
notifyListeners();
|
||||
if (onSuccess != null) {
|
||||
onSuccess(apiResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> refreshNotifications({
|
||||
Function(dynamic)? onSuccess,
|
||||
Function(String)? onError,
|
||||
}) async {
|
||||
notificationsList.clear();
|
||||
currentPage = 0;
|
||||
hasMoreNotifications = true;
|
||||
await getAllNotifications(onSuccess: onSuccess, onError: onError);
|
||||
}
|
||||
|
||||
Future<void> loadMoreNotifications({
|
||||
Function(dynamic)? onSuccess,
|
||||
Function(String)? onError,
|
||||
}) async {
|
||||
await getAllNotifications(onSuccess: onSuccess, onError: onError);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NotificationsListPage extends StatelessWidget {
|
||||
const NotificationsListPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CollapsingListView(
|
||||
title: "Notifications".needTranslation,
|
||||
child: SingleChildScrollView(
|
||||
child: Consumer<NotificationsViewModel>(builder: (context, notificationsVM, child) {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 24.h),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 24.h,
|
||||
hasShadow: false,
|
||||
),
|
||||
child: ListView.builder(
|
||||
itemCount: notificationsVM.isNotificationsLoading ? 4 : notificationsVM.notificationsList.length,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsetsGeometry.zero,
|
||||
itemBuilder: (context, index) {
|
||||
return notificationsVM.isNotificationsLoading
|
||||
? LabResultItemView(
|
||||
onTap: () {},
|
||||
labOrder: null,
|
||||
index: index,
|
||||
isLoading: true,
|
||||
)
|
||||
: AnimationConfiguration.staggeredList(
|
||||
position: index,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: SlideAnimation(
|
||||
verticalOffset: 100.0,
|
||||
child: FadeInAnimation(
|
||||
child: AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 16.h),
|
||||
"Notification Title".toText14(),
|
||||
SizedBox(height: 8.h),
|
||||
notificationsVM.notificationsList[index].message!.toText14(),
|
||||
SizedBox(height: 12.h),
|
||||
1.divider,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).paddingSymmetrical(16.w, 0.h),
|
||||
).paddingSymmetrical(24.w, 0.h);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue