fist commit ftc staff app clone
This commit is contained in:
89
lib/view/screens/auth_module/agency_sign_in.dart
Normal file
89
lib/view/screens/auth_module/agency_sign_in.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AgencySignIn extends StatefulWidget {
|
||||
const AgencySignIn({super.key});
|
||||
|
||||
@override
|
||||
State<AgencySignIn> createState() => _AgencySignInState();
|
||||
}
|
||||
|
||||
class _AgencySignInState extends State<AgencySignIn> {
|
||||
final AgencySignInController _controller = Get.put(AgencySignInController());
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
screenKey: _controller.screenKey,
|
||||
onScreenTap: _controller.removeFocus,
|
||||
showAppBar: true,
|
||||
titleText: "",
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15.0.w),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kAppIcon,
|
||||
imageColor: CustomAppColors.kIconColor,
|
||||
height: 132.h,
|
||||
width: 203.w,
|
||||
),
|
||||
|
||||
CustomTextWidget(
|
||||
text: ConstantText.kAgencyLogin,
|
||||
fontColor: CustomAppColors.kIconColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 24.sp,
|
||||
),
|
||||
|
||||
CustomTextWidget(
|
||||
text: ConstantText.kPleaseLoginToContinue,
|
||||
fontColor: CustomAppColors.kIconColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 30.0.h),
|
||||
child: CustomTextFieldWidget(
|
||||
controller: _controller.emailPhoneController,
|
||||
hintText: ConstantText.kInputEmailOrPhone,
|
||||
heading: ConstantText.kEmailOrPhoneHeading,
|
||||
onChange: (_){
|
||||
_controller.validateEmailPhone();
|
||||
},
|
||||
),
|
||||
),
|
||||
Obx((){
|
||||
return CustomErrorMsg(
|
||||
message: _controller.emailPhoneErrorMsg.value,
|
||||
);
|
||||
}),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 25.0.h),
|
||||
child: Obx((){
|
||||
return CustomAppButton(
|
||||
isLoading: _controller.isLoading.value,
|
||||
buttonText: ConstantText.kSendCode.toUpperCase(),
|
||||
onTap: _controller.onSendCodeButton,
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
4
lib/view/screens/auth_module/export_auth_module.dart
Normal file
4
lib/view/screens/auth_module/export_auth_module.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
export 'splash_screen.dart';
|
||||
export 'sign_in_screen.dart';
|
||||
export 'agency_sign_in.dart';
|
||||
export 'otp_screen.dart';
|
||||
124
lib/view/screens/auth_module/otp_screen.dart
Normal file
124
lib/view/screens/auth_module/otp_screen.dart
Normal file
@@ -0,0 +1,124 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pin_code_fields/pin_code_fields.dart';
|
||||
|
||||
class OTPScreen extends StatefulWidget {
|
||||
const OTPScreen({super.key});
|
||||
|
||||
@override
|
||||
State<OTPScreen> createState() => _OTPScreenState();
|
||||
}
|
||||
|
||||
class _OTPScreenState extends State<OTPScreen> {
|
||||
final OTPScreenController _controller = Get.put(OTPScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
screenKey: _controller.screenKey,
|
||||
onScreenTap: _controller.removeFocus,
|
||||
avoidBottomInsets: false,
|
||||
showAppBar: true,
|
||||
titleText: "",
|
||||
body: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15.0.w),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kLockIcon,
|
||||
imageColor: CustomAppColors.kIconColor,
|
||||
height: 84.h,
|
||||
width: 75.w,
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 30.0.h),
|
||||
child: CustomTextWidget(
|
||||
text: ConstantText.kTwoFactorAuth,
|
||||
fontColor: CustomAppColors.kIconColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 24.sp,
|
||||
alignment: Alignment.centerLeft,
|
||||
),
|
||||
),
|
||||
|
||||
CustomTextWidget(
|
||||
text: ConstantText.kOTPScreenMsg,
|
||||
fontColor: CustomAppColors.kIconColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20.0.h),
|
||||
child: PinCodeTextField(
|
||||
keyboardType: TextInputType.number,
|
||||
textInputAction: TextInputAction.done,
|
||||
autoDisposeControllers: false,
|
||||
controller: _controller.otpController,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
],
|
||||
onAutoFillDisposeAction: AutofillContextAction.cancel,
|
||||
appContext: context,
|
||||
length: 6,
|
||||
onChanged: (otp) {
|
||||
_controller.validateOTP();
|
||||
},
|
||||
cursorColor: CustomAppColors.kIconColor,
|
||||
textStyle: TextStyle(
|
||||
color: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
),
|
||||
pinTheme: PinTheme(
|
||||
shape: PinCodeFieldShape.box,
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
fieldHeight: 56.0.h,
|
||||
fieldWidth: 43.33.w,
|
||||
borderWidth: 0.5.w,
|
||||
fieldOuterPadding: EdgeInsets.symmetric(vertical: 10.0.h,),
|
||||
activeFillColor: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
activeColor: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
errorBorderColor: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
selectedColor: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
inactiveColor: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
selectedFillColor: CustomAppColors.kIconColor.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
Obx(() {
|
||||
return CustomErrorMsg(
|
||||
message: _controller.otpErrorMsg.value,
|
||||
);
|
||||
}),
|
||||
const Spacer(),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: Platform.isIOS ? 30.0.h : 20.0.h,
|
||||
),
|
||||
child: Obx((){
|
||||
return CustomAppButton(
|
||||
isLoading: _controller.isLoading.value,
|
||||
buttonText: ConstantText.kSubmit.toUpperCase(),
|
||||
onTap: _controller.onSubmitButton,
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
160
lib/view/screens/auth_module/sign_in_screen.dart
Normal file
160
lib/view/screens/auth_module/sign_in_screen.dart
Normal file
@@ -0,0 +1,160 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SignInScreen extends StatefulWidget {
|
||||
const SignInScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SignInScreen> createState() => _SignInScreenState();
|
||||
}
|
||||
|
||||
class _SignInScreenState extends State<SignInScreen> {
|
||||
final SignInScreenController _controller = Get.put(SignInScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
screenKey: _controller.screenKey,
|
||||
onScreenTap: _controller.removeFocus,
|
||||
showAppBar: true,
|
||||
titleText: "",
|
||||
body: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15.0.w),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kAppIcon,
|
||||
imageColor: CustomAppColors.kIconColor,
|
||||
height: 132.h,
|
||||
width: 203.w,
|
||||
),
|
||||
|
||||
CustomTextWidget(
|
||||
text: ConstantText.kWelcomeBack,
|
||||
fontColor: CustomAppColors.kIconColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 24.sp,
|
||||
),
|
||||
|
||||
CustomTextWidget(
|
||||
text: ConstantText.kPleaseLoginToContinue,
|
||||
fontColor: CustomAppColors.kIconColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 30.0.h),
|
||||
child: CustomTextFieldWidget(
|
||||
controller: _controller.emailController,
|
||||
hintText: ConstantText.kPleaseInputEmail,
|
||||
heading: ConstantText.kEmailHeading,
|
||||
onChange: (_){
|
||||
_controller.validateEmail();
|
||||
},
|
||||
),
|
||||
),
|
||||
Obx((){
|
||||
return CustomErrorMsg(
|
||||
message: _controller.emailErrorMsg.value,
|
||||
);
|
||||
}),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 15.0.h),
|
||||
child: CustomTextFieldWidget(
|
||||
controller: _controller.passwordController,
|
||||
hintText: "******",
|
||||
heading: ConstantText.kPasswordHeading,
|
||||
onChange: (_){
|
||||
_controller.validatePassword();
|
||||
},
|
||||
isObscure: true,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
Obx((){
|
||||
return CustomErrorMsg(
|
||||
message: _controller.passwordErrorMsg.value,
|
||||
);
|
||||
}),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 15.0.h,
|
||||
bottom: 25.h,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// Obx((){
|
||||
// return CustomCheckBox(
|
||||
// checkBoxValue: _controller.isRememberMe.value,
|
||||
// titleText: ConstantText.kRememberMe,
|
||||
// onTap: () {
|
||||
// _controller.isRememberMe.toggle();
|
||||
// },
|
||||
// );
|
||||
// }),
|
||||
|
||||
// const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: _controller.onForgotButton,
|
||||
child: CustomTextWidget(
|
||||
text: ConstantText.kForgotPassword,
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 8.0.h),
|
||||
child: Obx((){
|
||||
return CustomAppButton(
|
||||
isLoading: _controller.isLoading.value,
|
||||
buttonText: ConstantText.kLogIn.toUpperCase(),
|
||||
onTap: _controller.onLogInButton,
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.only(
|
||||
// bottom: Platform.isIOS ? 30.0.h : 20.0.h,
|
||||
// ),
|
||||
// child: CustomAppButton(
|
||||
// buttonText: ConstantText.kAgencyLogin.toUpperCase(),
|
||||
// buttonColor: CustomAppColors.kPrimaryColor,
|
||||
// textColor: CustomAppColors.kSecondaryColor,
|
||||
// onTap: _controller.onAgencyLogInButton,
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
41
lib/view/screens/auth_module/splash_screen.dart
Normal file
41
lib/view/screens/auth_module/splash_screen.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/utilities/notification_util.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SplashScreen> createState() => _SplashScreenState();
|
||||
}
|
||||
|
||||
class _SplashScreenState extends State<SplashScreen> {
|
||||
final _controller = Get.put(SplashScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
requestNotificationPermissions();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
screenKey: _controller.screenKey,
|
||||
backgroundColor: CustomAppColors.kSecondaryColor,
|
||||
body: const Center(
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kAppIcon,
|
||||
height: 200,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
20
lib/view/screens/chat/arguments/chat_screen_args.dart
Normal file
20
lib/view/screens/chat/arguments/chat_screen_args.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/chat/ChatModel.dart';
|
||||
import 'group_data_args.dart';
|
||||
|
||||
class ChatScreenArgs {
|
||||
final String name;
|
||||
final String profilePicPath;
|
||||
final String otherUserId;
|
||||
final GroupDataArgs? groupData;
|
||||
|
||||
final ValueChanged<ChatModel>? onLastMessageUpdate;
|
||||
|
||||
ChatScreenArgs({
|
||||
required this.name,
|
||||
required this.profilePicPath,
|
||||
required this.otherUserId,
|
||||
this.groupData,
|
||||
this.onLastMessageUpdate,
|
||||
});
|
||||
}
|
||||
13
lib/view/screens/chat/arguments/group_data_args.dart
Normal file
13
lib/view/screens/chat/arguments/group_data_args.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:ftc_mobile_app/models/chat/combined_last_messages_model_class.dart';
|
||||
|
||||
class GroupDataArgs {
|
||||
final String groupId;
|
||||
final List groupMembersIds;
|
||||
final GroupWorkingScheduleTime scheduleTime;
|
||||
|
||||
GroupDataArgs({
|
||||
required this.groupId,
|
||||
required this.groupMembersIds,
|
||||
required this.scheduleTime,
|
||||
});
|
||||
}
|
||||
190
lib/view/screens/chat/chat_screen.dart
Normal file
190
lib/view/screens/chat/chat_screen.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/chat/ChatModel.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:grouped_list/grouped_list.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'arguments/chat_screen_args.dart';
|
||||
import 'widgets/chat_screen_footer_widget.dart';
|
||||
import 'widgets/message_bubble.dart';
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
final ChatScreenArgs args;
|
||||
|
||||
const ChatScreen({Key? key, required this.args}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ChatScreen> createState() => _ChatScreenState();
|
||||
}
|
||||
|
||||
class _ChatScreenState extends State<ChatScreen> {
|
||||
late final ChatScreenController controller;
|
||||
final sepFormatter = DateFormat("dd MMM yyyy");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(ChatScreenController(widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: Colors.white,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: _appBar,
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(child: messagesList()),
|
||||
Obx(() {
|
||||
return controller.isSocketConnected()
|
||||
? ChatScreenFooterWidget(
|
||||
controller: controller,
|
||||
enabled: controller.isSocketConnected(),
|
||||
)
|
||||
: FrequentFunctions.noWidget;
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar get _appBar {
|
||||
return AppBar(
|
||||
toolbarHeight: 56.r,
|
||||
leading: IconButton(
|
||||
icon: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
centerTitle: false,
|
||||
titleSpacing: 0,
|
||||
leadingWidth: 50.r,
|
||||
surfaceTintColor: Colors.white,
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MyCircleImage(
|
||||
imageSize: 32.r,
|
||||
url: "${WebUrls.baseUrl}${widget.args.profilePicPath}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
imageColor: CustomAppColors.kDarkBlueTextColor,
|
||||
height: 32.r,
|
||||
width: 32.r,
|
||||
),
|
||||
),
|
||||
10.horizontalSpace,
|
||||
CustomTextWidget(
|
||||
text: widget.args.name,
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget messagesList() {
|
||||
return Obx(() {
|
||||
final messages = controller.messages;
|
||||
return (messages.isEmpty)
|
||||
? FrequentFunctions.noWidget
|
||||
: _messagesList(messages());
|
||||
});
|
||||
}
|
||||
|
||||
Widget _messagesList(List<ChatModel> list) {
|
||||
final now = DateTime.now();
|
||||
|
||||
return GroupedListView<ChatModel, String>(
|
||||
reverse: true,
|
||||
elements: list,
|
||||
padding: REdgeInsets.symmetric(horizontal: 18),
|
||||
order: GroupedListOrder.DESC,
|
||||
groupBy: (message) {
|
||||
final messageDate =
|
||||
DateTime.fromMillisecondsSinceEpoch(message.date ?? 0);
|
||||
return DateFormatter.dateFormatter.format(messageDate);
|
||||
},
|
||||
groupSeparatorBuilder: (String date) {
|
||||
final isToday = (date == DateFormatter.dateFormatter.format(now));
|
||||
return _buildGroupSeparatorWidget(isToday
|
||||
? "Today"
|
||||
: sepFormatter.format(DateFormatter.dateFormatter.parse(date)));
|
||||
},
|
||||
itemBuilder: (_, e) => _buildItemWidget(list.indexOf(e), e),
|
||||
sort: false,
|
||||
separator: 8.verticalSpace,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildGroupSeparatorWidget(String susTag) {
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(vertical: 12.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Divider(
|
||||
height: 1,
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
)),
|
||||
Text(
|
||||
susTag,
|
||||
style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w500),
|
||||
).addPaddingHorizontal(10),
|
||||
Expanded(
|
||||
child: Divider(
|
||||
height: 1,
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemWidget(int index, ChatModel message) {
|
||||
final isMyMessage = (message.from?.id == controller.myId);
|
||||
final hasFile = message.filePath.isNotNullOrEmpty();
|
||||
print("filePath: ${message.filePath}");
|
||||
|
||||
return MessageBubble(
|
||||
senderName: message.from?.name ?? "",
|
||||
profilePic: !isMyMessage ? (message.from?.profilePictureUrl ?? "") : "",
|
||||
content: hasFile ? (message.filePath ?? '') : (message.message ?? ''),
|
||||
type: isMyMessage ? MessageType.sent : MessageType.received,
|
||||
contentType: hasFile
|
||||
? (message.fileType == ChatModel.fileTypeLocalPath)
|
||||
? MessageContentType.file
|
||||
: MessageContentType.url
|
||||
: MessageContentType.text,
|
||||
sentMessageColor: CustomAppColors.kSmokeColor,
|
||||
receivedMessageColor: CustomAppColors.kSecondaryColor,
|
||||
messageTime: (message.date == null)
|
||||
? ""
|
||||
: DateTime.fromMillisecondsSinceEpoch(message.date!)
|
||||
.toIso8601String(),
|
||||
state: MessageState.stateNone,
|
||||
status: MessageSeenStatus.seen,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
503
lib/view/screens/chat/controller/chat_screen_controller.dart
Normal file
503
lib/view/screens/chat/controller/chat_screen_controller.dart
Normal file
@@ -0,0 +1,503 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:ftc_mobile_app/controllers/home/inbox_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/models/chat/all_group_messages_model.dart';
|
||||
import 'package:ftc_mobile_app/models/chat/single_chat.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/utilities/frequent_functions.dart';
|
||||
import 'package:ftc_mobile_app/utilities/image_picker_popup.dart';
|
||||
import 'package:ftc_mobile_app/utilities/local_storage_manager/export_local_storage.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/home/custom_message_dialog.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/chat/arguments/chat_screen_args.dart';
|
||||
import 'package:ftc_mobile_app/web_services/chat_services.dart';
|
||||
import 'package:ftc_mobile_app/web_services/web_url.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:socket_io_client/socket_io_client.dart';
|
||||
import '../../../../models/chat/ChatModel.dart';
|
||||
|
||||
class ChatScreenController extends GetxController {
|
||||
final GlobalKey<ScaffoldState> screenKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
final messageTEC = TextEditingController();
|
||||
final messageFN = FocusNode();
|
||||
|
||||
final messages = RxList<ChatModel>();
|
||||
final isSocketConnected = false.obs;
|
||||
|
||||
late final ChatScreenArgs args;
|
||||
|
||||
String myId = "";
|
||||
|
||||
ChatScreenController(ChatScreenArgs data) {
|
||||
args = data;
|
||||
}
|
||||
|
||||
late Socket _socketIO;
|
||||
String listenId = "";
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
//Getting my ID
|
||||
// String userJson = LocalStorageManager.getSessionToken(
|
||||
// tokenKey: LocalStorageKeys.kUserModelKey,
|
||||
// );
|
||||
// UserModel userModel = UserModel.fromJson(json.decode(userJson));
|
||||
myId = LocalStorageManager.userId;
|
||||
|
||||
if (_canChat) {
|
||||
initializeSocket();
|
||||
}
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
if (isGroup) {
|
||||
fetchGroupMessagesFromService(args.groupData!.groupId);
|
||||
} else {
|
||||
fetchSingleMessagesFromService();
|
||||
}
|
||||
|
||||
if (_canChat.not) {
|
||||
showCantMessageDialog();
|
||||
}
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
bool get isGroup => args.groupData != null;
|
||||
|
||||
/// This method checks the current date if it lies within schedule time or not.
|
||||
/// If it does, it means chat is enabled else chat will be disabled.
|
||||
/// If schedule times not available, it returns true;
|
||||
bool get _canChat {
|
||||
final startMills = args.groupData?.scheduleTime.startTime ?? 0;
|
||||
final endMills = args.groupData?.scheduleTime.endTime ?? 0;
|
||||
|
||||
if (startMills > 0 && endMills > 0) {
|
||||
// Schedule times are available
|
||||
|
||||
final scheduleTime = _getScheduleTime(startMills, endMills);
|
||||
final currentTime = TimeOfDay.now();
|
||||
|
||||
// Current time within start, end schedule time
|
||||
return (currentTime.isAfter(scheduleTime.start) &&
|
||||
currentTime.isBefore(scheduleTime.end));
|
||||
} else {
|
||||
// Schedule times not available
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Make sure to pass correct millis values
|
||||
({TimeOfDay start, TimeOfDay end}) _getScheduleTime(
|
||||
int startMills, int endMills) {
|
||||
final sd = DateTime.fromMillisecondsSinceEpoch(startMills);
|
||||
final ed = DateTime.fromMillisecondsSinceEpoch(endMills);
|
||||
|
||||
final startTime = TimeOfDay(hour: sd.hour, minute: sd.minute);
|
||||
final endTime = TimeOfDay(hour: ed.hour, minute: ed.minute);
|
||||
|
||||
return (start: startTime, end: endTime);
|
||||
}
|
||||
|
||||
initializeSocket() {
|
||||
debugPrint('Socket address: ${WebUrls.socketUrl}');
|
||||
|
||||
_socketIO = io(
|
||||
WebUrls.socketUrl,
|
||||
OptionBuilder()
|
||||
.setTransports(['websocket']) // for Flutter or Dart VM
|
||||
.enableForceNewConnection()
|
||||
.enableAutoConnect()
|
||||
.setExtraHeaders({'foo': 'bar'}) // optional
|
||||
.build());
|
||||
|
||||
isSocketConnected.value = true;
|
||||
_socketIO.onConnect((_) {
|
||||
isSocketConnected.value = true;
|
||||
debugPrint('Socket Connected');
|
||||
});
|
||||
_socketIO.onDisconnect((_) {
|
||||
debugPrint('Socket Disconnected');
|
||||
// isSocketConnected.value = false;
|
||||
});
|
||||
_socketIO.onConnectError((e) {
|
||||
debugPrint('Socket Connection Error: ${e.toString()}');
|
||||
// isSocketConnected.value = false;
|
||||
});
|
||||
_socketIO.onConnectTimeout((e) {
|
||||
debugPrint('Socket timeout Error: ${e.toString()}');
|
||||
// isSocketConnected.value = false;
|
||||
});
|
||||
|
||||
//listenIdReceive
|
||||
listenId = (isGroup) ? args.groupData!.groupId : (myId + args.otherUserId);
|
||||
debugPrint('listen on: $listenId');
|
||||
_socketIO.on(listenId, (data) {
|
||||
debugPrint('listen on listenId: $data');
|
||||
_handleIncomingMessages(data);
|
||||
});
|
||||
}
|
||||
|
||||
_handleIncomingMessages(Map<String, dynamic> chatJson) {
|
||||
log("chat listen: $chatJson");
|
||||
// _total += 1;
|
||||
// _skip += 1;
|
||||
final chatModel = ChatModel.fromJson(chatJson);
|
||||
|
||||
if (chatJson.containsKey('createdAt')) {
|
||||
chatModel.date =
|
||||
DateTime.tryParse(chatJson["createdAt"])?.millisecondsSinceEpoch ?? 0;
|
||||
} else {
|
||||
chatModel.date = DateTime.now().millisecondsSinceEpoch;
|
||||
}
|
||||
|
||||
if (isGroup) {
|
||||
if (chatJson.containsKey('userId') && chatJson["userId"] is Map) {
|
||||
chatModel.from = UserData.fromJson(chatJson["userId"]);
|
||||
}
|
||||
_onFirstMessageSent();
|
||||
} else {
|
||||
chatModel.from = UserData(
|
||||
id: args.otherUserId,
|
||||
name: args.name,
|
||||
profilePictureUrl: args.profilePicPath);
|
||||
chatModel.to = UserData(id: chatJson['to']);
|
||||
}
|
||||
messages.insert(0, chatModel);
|
||||
args.onLastMessageUpdate?.call(chatModel);
|
||||
}
|
||||
|
||||
Future fetchSingleMessagesFromService() async {
|
||||
// _skip = 0;
|
||||
final response = await ChatService()
|
||||
.allSingleUsersChatMessagesServerAdmin(
|
||||
from: myId,
|
||||
to: args.otherUserId,
|
||||
)
|
||||
.showLoader();
|
||||
|
||||
if (response is List<ChatModel>) {
|
||||
if (response.isNotEmpty) {
|
||||
//Note: Converting this response to List of ChatModel objects
|
||||
// List<ChatModel> chats = [];
|
||||
// await Future.forEach(response.reversed, (e) {
|
||||
// chats.add(ChatModel(
|
||||
// id: e.id,
|
||||
// from: e.from,
|
||||
// to: e.to,
|
||||
// message: e.message,
|
||||
// date:
|
||||
// DateTime.tryParse(e.createdAt)?.millisecondsSinceEpoch ?? 0));
|
||||
// });
|
||||
messages.value = response.reversed.toList();
|
||||
}
|
||||
} else if (response is String) {
|
||||
FrequentFunctions.showToast(message: response);
|
||||
}
|
||||
}
|
||||
|
||||
void fetchGroupMessagesFromService(String idOfGroup) async {
|
||||
dynamic response = await ChatService().allGroupMessages(
|
||||
sortOrder: -1,
|
||||
offset: 0,
|
||||
limit: 100000,
|
||||
groupId: idOfGroup,
|
||||
isDeleted: false).showLoader();
|
||||
|
||||
if (response is List<AllGroupMessages>) {
|
||||
if (response.isNotEmpty) {
|
||||
//Note: Converting this response to List of ChatModel objects
|
||||
List<ChatModel> chats = [];
|
||||
await Future.forEach(response, (e) {
|
||||
chats.add(ChatModel(
|
||||
id: e.id,
|
||||
from: e.userId,
|
||||
message: e.message,
|
||||
messageType: e.messageType,
|
||||
filePath: e.filePath,
|
||||
date:
|
||||
DateTime.tryParse(e.createdAt)?.millisecondsSinceEpoch ?? 0));
|
||||
});
|
||||
messages.value = chats;
|
||||
}
|
||||
} else if (response is String) {
|
||||
FrequentFunctions.showToast(message: response);
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessageButtonPressed() async {
|
||||
if (messageTEC.text.trim().isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sendMessage(
|
||||
message: messageTEC.text.trim(),
|
||||
);
|
||||
messageTEC.clear();
|
||||
}
|
||||
|
||||
//if sending first message, then updating chat list screen by calling it's listing api
|
||||
_onFirstMessageSent() {
|
||||
if (messages.length == 1) {
|
||||
try {
|
||||
final iController = Get.find<InboxScreenController>();
|
||||
iController.onFirstMessageSend.value = true;
|
||||
print("Got controller");
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sendMessage({
|
||||
String? message,
|
||||
File? file,
|
||||
}) {
|
||||
if (isGroup) {
|
||||
_sendGroupMessage(
|
||||
message: message,
|
||||
file: file,
|
||||
);
|
||||
} else {
|
||||
_sendPrivateMessage(
|
||||
message: message,
|
||||
file: file,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
///Note: no need to update ui for sent message here because
|
||||
///it's gonna handled by socket event
|
||||
_sendGroupMessage({
|
||||
String? message,
|
||||
File? file,
|
||||
}) async {
|
||||
await ChatService().addGroupMessageService(
|
||||
message: message ?? "",
|
||||
messageType: (file != null) ? MessageType.file : MessageType.message,
|
||||
file: file,
|
||||
userId: myId,
|
||||
groupId: args.groupData!.groupId,
|
||||
);
|
||||
}
|
||||
|
||||
///Note: handling messages list update also here
|
||||
_sendPrivateMessage({
|
||||
String? message,
|
||||
File? file,
|
||||
}) async {
|
||||
final id = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
final model = ChatModel(
|
||||
id: id.toString(),
|
||||
from: UserData(id: LocalStorageManager.userId),
|
||||
to: UserData(
|
||||
id: args.otherUserId,
|
||||
name: args.name,
|
||||
profilePictureUrl: args.profilePicPath,
|
||||
),
|
||||
message: message,
|
||||
messageType:
|
||||
(file != null) ? MessageType.file.name : MessageType.message.name,
|
||||
fileType: (file != null) ? ChatModel.fileTypeLocalPath : null,
|
||||
date: id,
|
||||
state: ChatModel.stateLoading,
|
||||
);
|
||||
|
||||
messages.insert(0, model);
|
||||
args.onLastMessageUpdate?.call(model);
|
||||
|
||||
dynamic response = await ChatService().addSingleMessage(
|
||||
message: message ?? "",
|
||||
messageType: (file != null) ? MessageType.file : MessageType.message,
|
||||
file: file,
|
||||
senderId: LocalStorageManager.userId,
|
||||
receiverId: args.otherUserId,
|
||||
);
|
||||
|
||||
final msg = messages.firstWhereOrNull((e) {
|
||||
return e.id == id.toString();
|
||||
});
|
||||
|
||||
if (msg != null) {
|
||||
final index = messages.indexOf(msg);
|
||||
|
||||
if (response is SingleChatModelClass) {
|
||||
//message sent successfully
|
||||
msg.id = response.id;
|
||||
msg.fileType = null;
|
||||
msg.state = ChatModel.stateSuccess;
|
||||
|
||||
messages
|
||||
..removeAt(index)
|
||||
..insert(index, msg);
|
||||
|
||||
_onFirstMessageSent();
|
||||
} else {
|
||||
msg.state = ChatModel.stateError;
|
||||
messages.removeAt(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pickAndSendFile() async {
|
||||
Get.focusScope?.unfocus();
|
||||
Get.bottomSheet(CupertinoActionSheet(
|
||||
actions: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
ImagePickerPopup.getImageFromSource(
|
||||
fromCamera: true,
|
||||
onFetchImage: (f) {
|
||||
_sendMessage(file: f);
|
||||
});
|
||||
},
|
||||
leading: const Icon(CupertinoIcons.camera),
|
||||
title: const Text("Camera"),
|
||||
trailing: Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
size: 18.r,
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(type: FileType.media);
|
||||
|
||||
if (result != null && result.files.single.path != null) {
|
||||
if (result.files.single.path!.isImageFileName) {
|
||||
_sendMessage(file: File(result.files.single.path!));
|
||||
} else {
|
||||
FrequentFunctions.showToast(message: "File doesn't supported ");
|
||||
}
|
||||
}
|
||||
},
|
||||
leading: const Icon(CupertinoIcons.photo_on_rectangle),
|
||||
title: const Text("Gallery"),
|
||||
trailing: Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
size: 18.r,
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
final FilePickerResult? result = await FilePicker.platform
|
||||
.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ["pdf", "doc", "docx", "xlsx", "xls"]);
|
||||
|
||||
if (result != null) {
|
||||
_sendMessage(file: File(result.files.single.path!));
|
||||
}
|
||||
},
|
||||
leading: const Icon(Icons.attach_file),
|
||||
title: const Text("File"),
|
||||
trailing: Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
size: 18.r,
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
// _sendImage(File file) async {
|
||||
// debugPrint("file: ${file.path}");
|
||||
// //
|
||||
// // ChatModel model = ChatModel(
|
||||
// // sentBy: UserData(id: myId),
|
||||
// // sentTo: otherUser,
|
||||
// // date: DateTime.now().toUtc().millisecondsSinceEpoch,
|
||||
// // files: [file.path],
|
||||
// // fileType: fileTypeLocalPath,
|
||||
// // state: ChatModel.stateLoading);
|
||||
// //
|
||||
// // final modelHash = model.hashCode.toString();
|
||||
// // model.localId = modelHash;
|
||||
// //
|
||||
// // debugPrint("message modelHash: $modelHash");
|
||||
// // _handleChat(model.toJson());
|
||||
// //
|
||||
// // // return;
|
||||
// // var res = await repository.sendChatAttachmentApi(
|
||||
// // req: ChatMessageRequest(
|
||||
// // sentBy: myId,
|
||||
// // sentTo: otherUser.id!,
|
||||
// // files: [file],
|
||||
// // fileType: "image"),
|
||||
// // );
|
||||
// //
|
||||
// // final i = messages.indexWhere((e) => e.localId == modelHash);
|
||||
// //
|
||||
// // if (res.success == true) {
|
||||
// // if (i != -1) {
|
||||
// // messages[i].state = ChatModel.stateSuccess;
|
||||
// // messages.refresh();
|
||||
// // }
|
||||
// // } else {
|
||||
// // if (i != -1) {
|
||||
// // messages[i].state = ChatModel.stateError;
|
||||
// // messages.refresh();
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
|
||||
//Always call this method if _canChat is false
|
||||
void showCantMessageDialog() {
|
||||
final startMills = args.groupData!.scheduleTime.startTime;
|
||||
final endMills = args.groupData!.scheduleTime.endTime;
|
||||
|
||||
final scheduleTime = _getScheduleTime(startMills, endMills);
|
||||
final sd = DateTime(
|
||||
2024, 1, 1, scheduleTime.start.hour, scheduleTime.start.minute, 0);
|
||||
final ed =
|
||||
DateTime(2024, 1, 1, scheduleTime.end.hour, scheduleTime.end.minute, 0);
|
||||
|
||||
showDialog(
|
||||
context: screenKey.currentState!.context,
|
||||
builder: (BuildContext context) {
|
||||
return CustomMessageDialog(
|
||||
dialogButtonText: "Close",
|
||||
dialogMessageText:
|
||||
"It is currently outside the working hours. You can only send message during the working hours",
|
||||
dialogMessageTextBold:
|
||||
"Working hours: ${DateFormat("hh:mm aa").format(sd)} - ${DateFormat("hh:mm aa").format(ed)}",
|
||||
headingText: "You Can't message right now",
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// new
|
||||
void removeFocus() {
|
||||
FocusScope.of(screenKey.currentContext!).unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
try {
|
||||
_socketIO.clearListeners();
|
||||
_socketIO.disconnect();
|
||||
_socketIO.destroy();
|
||||
_socketIO.dispose();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
messageTEC.dispose();
|
||||
messageFN.dispose();
|
||||
// scrollController.dispose();
|
||||
Get.delete<ChatScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
89
lib/view/screens/chat/widgets/chat_screen_footer_widget.dart
Normal file
89
lib/view/screens/chat/widgets/chat_screen_footer_widget.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ChatScreenFooterWidget extends StatelessWidget {
|
||||
const ChatScreenFooterWidget({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.enabled,
|
||||
});
|
||||
|
||||
final ChatScreenController controller;
|
||||
final bool enabled;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: controller.pickAndSendFile,
|
||||
icon: SvgPicture.asset(
|
||||
AssetsManager.svgIcAdd,
|
||||
width: 32.r,
|
||||
height: 32.r,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
textAlign: TextAlign.left,
|
||||
controller: controller.messageTEC,
|
||||
keyboardType: TextInputType.multiline,
|
||||
focusNode: controller.messageFN,
|
||||
enabled: enabled,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Type Message...',
|
||||
// border: InputBorder.none,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: 4.toRadius(),
|
||||
borderSide: BorderSide(
|
||||
width: 1,
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: 4.toRadius(),
|
||||
borderSide: BorderSide(
|
||||
width: 1,
|
||||
color: Get.theme.primaryColor,
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
),
|
||||
),
|
||||
),
|
||||
5.horizontalSpace,
|
||||
SizedBox(
|
||||
width: 80.w,
|
||||
height: 40.r,
|
||||
child: IgnorePointer(
|
||||
ignoring: enabled.not,
|
||||
child: CustomAppButton(
|
||||
buttonText: "Send",
|
||||
buttonColor:
|
||||
enabled ? Get.theme.primaryColor : Colors.grey,
|
||||
borderColor:
|
||||
enabled ? Get.theme.primaryColor : Colors.grey,
|
||||
onTap: controller.sendMessageButtonPressed,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
8.verticalSpace,
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
420
lib/view/screens/chat/widgets/message_bubble.dart
Normal file
420
lib/view/screens/chat/widgets/message_bubble.dart
Normal file
@@ -0,0 +1,420 @@
|
||||
import 'dart:io';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../../custom_widgets/my_circle_image.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
enum MessageType { sent, received }
|
||||
|
||||
enum MessageSeenStatus { delivered, seen }
|
||||
|
||||
enum MessageContentType { text, file, url }
|
||||
|
||||
enum MessageState {
|
||||
stateNone(0),
|
||||
stateError(-1),
|
||||
stateSending(1),
|
||||
stateSuccess(2);
|
||||
|
||||
final int intValue;
|
||||
|
||||
static MessageState stateFromIntValue(int value) {
|
||||
switch (value) {
|
||||
case -1:
|
||||
return MessageState.stateError;
|
||||
case 1:
|
||||
return MessageState.stateSending;
|
||||
case 2:
|
||||
return MessageState.stateSuccess;
|
||||
default:
|
||||
return MessageState.stateNone;
|
||||
}
|
||||
}
|
||||
|
||||
const MessageState(this.intValue);
|
||||
}
|
||||
|
||||
class MessageBubble extends StatelessWidget {
|
||||
final String senderName;
|
||||
final String content;
|
||||
final MessageState state;
|
||||
final MessageContentType contentType;
|
||||
final String profilePic;
|
||||
final MessageType type;
|
||||
final MessageSeenStatus status;
|
||||
final String messageTime;
|
||||
final Color? sentMessageColor;
|
||||
final Color? receivedMessageColor;
|
||||
final Color? sentMessageTextColor;
|
||||
final Color? receivedMessageTextColor;
|
||||
final bool showReportButton;
|
||||
|
||||
const MessageBubble({
|
||||
Key? key,
|
||||
required this.senderName,
|
||||
required this.content,
|
||||
required this.contentType,
|
||||
required this.state,
|
||||
required this.profilePic,
|
||||
required this.type,
|
||||
required this.status,
|
||||
required this.messageTime,
|
||||
this.sentMessageColor,
|
||||
this.receivedMessageColor,
|
||||
this.sentMessageTextColor,
|
||||
this.receivedMessageTextColor,
|
||||
this.showReportButton = true,
|
||||
}) : super(key: key);
|
||||
|
||||
Color get _backgroundColor => (type == MessageType.sent)
|
||||
? (sentMessageColor ?? Get.theme.primaryColor)
|
||||
: (receivedMessageColor ?? const Color(0xffC1C1C5));
|
||||
|
||||
Color get messageColor => (type == MessageType.sent)
|
||||
? (sentMessageTextColor ?? Colors.black)
|
||||
: (receivedMessageTextColor ?? Colors.white);
|
||||
|
||||
// double get _paddingLeft => (type == MessageType.sent) ? 0.15.sw : 0;
|
||||
|
||||
final radius = 16.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final loader = Visibility(
|
||||
visible: (state == MessageState.stateSending),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: SizedBox.square(
|
||||
dimension: 18,
|
||||
child: CircularProgressIndicator(
|
||||
color: Get.theme.primaryColor,
|
||||
strokeWidth: 2,
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
final messageBox = SizedBox(
|
||||
width: 0.7.sw,
|
||||
child: Padding(
|
||||
padding: REdgeInsets.symmetric(vertical: 5),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(type == MessageType.received)
|
||||
? MyCircleImage(
|
||||
imageSize: 20.r,
|
||||
url: WebUrls.baseUrl + profilePic,
|
||||
errorWidget: const DecoratedBox(
|
||||
decoration: BoxDecoration(color: Color(0xffC1C1C5)),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.image_not_supported_outlined,
|
||||
color: Colors.black,
|
||||
size: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
).paddingOnly(right: 8.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
Expanded(
|
||||
child: (contentType == MessageContentType.text)
|
||||
? _textMessage()
|
||||
: (content.isImageFileName)
|
||||
? _imageWidget()
|
||||
: _documentFileWidget(),
|
||||
),
|
||||
],
|
||||
),
|
||||
4.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
(type == MessageType.received)
|
||||
? SizedBox(width: 28.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
(state == MessageState.stateSending)
|
||||
? loader
|
||||
: (state == MessageState.stateError)
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: Colors.red,
|
||||
size: 14.r,
|
||||
),
|
||||
4.horizontalSpace,
|
||||
Text(
|
||||
'Message not sent',
|
||||
style: const TextStyle().copyWith(
|
||||
color: Colors.red,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: FrequentFunctions.noWidget
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: (type == MessageType.sent)
|
||||
? MainAxisAlignment.end
|
||||
: MainAxisAlignment.start,
|
||||
children: [messageBox],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _textMessage() => Container(
|
||||
padding: REdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
decoration:
|
||||
BoxDecoration(color: _backgroundColor, borderRadius: 10.toRadius()),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
(type == MessageType.received)
|
||||
? CustomTextWidget(
|
||||
text: senderName,
|
||||
fontColor: messageColor,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
).paddingOnly(bottom: 10.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
CustomTextWidget(
|
||||
text: content,
|
||||
fontColor: messageColor,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
4.verticalSpace,
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: _messageTimeWidget(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget _imageWidget() {
|
||||
return InkWell(
|
||||
onTap: _openPreviewDialog,
|
||||
child: Container(
|
||||
width: 200.r,
|
||||
height: 250.r,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
padding: REdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
color: _backgroundColor,
|
||||
borderRadius: radius.toRadius()),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
//Sender Name
|
||||
(type == MessageType.received)
|
||||
? CustomTextWidget(
|
||||
text: senderName,
|
||||
fontColor: messageColor,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
).paddingOnly(bottom: 10.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
|
||||
//image
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
borderRadius: (radius - 4).toRadius(),
|
||||
child: (contentType == MessageContentType.file)
|
||||
? Image.file(File(content), fit: BoxFit.cover)
|
||||
: CachedNetworkImage(
|
||||
imageUrl: (WebUrls.baseUrl + content),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
8.verticalSpace,
|
||||
|
||||
//Time
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: _messageTimeWidget(),
|
||||
).addPaddingHorizontal(12),
|
||||
8.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _documentFileWidget() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _backgroundColor,
|
||||
borderRadius: radius.toRadius(),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
padding: REdgeInsets.all(4),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
//Sender Name
|
||||
(type == MessageType.received)
|
||||
? CustomTextWidget(
|
||||
text: senderName,
|
||||
fontColor: messageColor,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
).paddingOnly(bottom: 10.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
|
||||
//File
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if (contentType == MessageContentType.url) {
|
||||
_launchUrl(WebUrls.baseUrl + content);
|
||||
} else {
|
||||
_launchUrl(content);
|
||||
}
|
||||
},
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
surfaceTintColor: Colors.white,
|
||||
child: Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 24.r,
|
||||
backgroundColor:
|
||||
CustomAppColors.kSecondaryColor.withOpacity(0.1),
|
||||
child: const Icon(
|
||||
Icons.file_copy_outlined,
|
||||
color: CustomAppColors.kSecondaryColor,
|
||||
),
|
||||
),
|
||||
12.horizontalSpace,
|
||||
Expanded(
|
||||
child: CustomTextWidget(
|
||||
text: path.basename(content),
|
||||
fontColor: messageColor,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
4.verticalSpace,
|
||||
|
||||
//Time
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: _messageTimeWidget(),
|
||||
).addPaddingHorizontal(12),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _messageTimeWidget() {
|
||||
return (messageTime.isNotEmpty)
|
||||
? Text(
|
||||
DateFormat("hh:mm aa")
|
||||
.format(DateTime.parse(messageTime).toLocal()),
|
||||
style: TextStyle(
|
||||
color: (type == MessageType.sent) ? Colors.grey : Colors.white,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
)
|
||||
: FrequentFunctions.noWidget;
|
||||
}
|
||||
|
||||
void _openPreviewDialog() {
|
||||
final img = (contentType == MessageContentType.file)
|
||||
? FileImage(File(content))
|
||||
: CachedNetworkImageProvider(WebUrls.baseUrl + content);
|
||||
Get.dialog(
|
||||
Material(
|
||||
type: MaterialType.transparency,
|
||||
child: SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: PhotoViewGestureDetectorScope(
|
||||
axis: Axis.vertical,
|
||||
child: PhotoView(
|
||||
tightMode: true,
|
||||
backgroundDecoration: const BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
maxScale: PhotoViewComputedScale.covered * 1.1,
|
||||
initialScale: PhotoViewComputedScale.contained,
|
||||
imageProvider: img as ImageProvider,
|
||||
heroAttributes:
|
||||
const PhotoViewHeroAttributes(tag: "someTag"),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 12,
|
||||
top: 12,
|
||||
child: InkWell(
|
||||
onTap: Get.back,
|
||||
child: Card(
|
||||
color: Colors.white,
|
||||
shape: 24.toRoundedRectRadius(),
|
||||
elevation: 4,
|
||||
child: RSizedBox.square(
|
||||
dimension: 40,
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
color: Colors.black,
|
||||
size: 24.r,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _launchUrl(String url) async {
|
||||
try {
|
||||
await launchUrl(Uri.parse(url));
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/memoryListResponse/MemoryListData.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_network_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'controller/add_edit_memory_box_screen_controller.dart';
|
||||
import 'widget/VideoPlayerWidget.dart';
|
||||
|
||||
class AddEditMemoryBoxScreenArgs {
|
||||
final UserData userData;
|
||||
final MemoryListData? data;
|
||||
final bool viewOnly;
|
||||
|
||||
AddEditMemoryBoxScreenArgs({
|
||||
required this.userData,
|
||||
this.data,
|
||||
this.viewOnly = false,
|
||||
});
|
||||
}
|
||||
|
||||
//This screen is used to view, add and edit memory box
|
||||
class AddEditMemoryBoxScreen extends StatefulWidget {
|
||||
final AddEditMemoryBoxScreenArgs args;
|
||||
|
||||
const AddEditMemoryBoxScreen({super.key, required this.args});
|
||||
|
||||
@override
|
||||
State<AddEditMemoryBoxScreen> createState() => _AddEditMemoryBoxScreenState();
|
||||
}
|
||||
|
||||
class _AddEditMemoryBoxScreenState extends State<AddEditMemoryBoxScreen> {
|
||||
final controller = Get.put(AddEditMemoryBoxScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUserId = widget.args.userData.id!;
|
||||
|
||||
if (forUpdate) {
|
||||
controller.filePath.value =
|
||||
'${WebUrls.baseUrl}${widget.args.data!.filePath ?? ""}';
|
||||
controller.noteDetailsController.text = widget.args.data!.note ?? "";
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
bool get forUpdate => widget.args.data != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText:
|
||||
"${widget.args.viewOnly ? "View" : forUpdate ? "Update" : "Add"} Memory Box",
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.r),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: (widget.args.viewOnly)
|
||||
? _viewOnlyWidgets
|
||||
: [
|
||||
12.verticalSpace,
|
||||
Obx(() {
|
||||
final path = controller.filePath();
|
||||
return mediaViewer(path: path);
|
||||
}),
|
||||
CustomTextWidget(
|
||||
text: "Upload File",
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16.sp,
|
||||
fontColor: Colors.black,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
// CustomTextWidget(
|
||||
// text: "Please upload a file that is 1MB or smaller.",
|
||||
// textAlign: TextAlign.left,
|
||||
// fontSize: 12.sp,
|
||||
// fontColor: Colors.grey,
|
||||
// ),
|
||||
12.verticalSpace,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: SizedBox(
|
||||
height: 32.r,
|
||||
child: CustomAppButton(
|
||||
buttonColor: Get.theme.primaryColor,
|
||||
buttonText: "Choose File",
|
||||
onTap: controller.onFileChooseButtonTap,
|
||||
),
|
||||
).paddingOnly(right: 8.r),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Obx(() {
|
||||
return controller.filePath.isNotEmpty
|
||||
? Obx(
|
||||
() => CustomTextWidget(
|
||||
text: controller.filePath.value
|
||||
.split("/")
|
||||
.last,
|
||||
isExpanded: false,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
)
|
||||
: FrequentFunctions.noWidget;
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
controller: controller.noteDetailsController,
|
||||
heading: "Note Details",
|
||||
hintText: "Type here...",
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: forUpdate ? "Update" : "Save",
|
||||
onTap: () {
|
||||
forUpdate
|
||||
? controller
|
||||
.updateButtonPress(widget.args.data!.id!)
|
||||
: controller.saveButtonPress();
|
||||
},
|
||||
),
|
||||
5.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> get _viewOnlyWidgets {
|
||||
return [
|
||||
12.verticalSpace,
|
||||
mediaViewer(
|
||||
path: '${WebUrls.baseUrl}${widget.args.data?.filePath ?? ""}'),
|
||||
20.verticalSpace,
|
||||
Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Note Details",
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: widget.args.data?.note ?? "",
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 14.sp,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
],
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
Widget mediaViewer({required String path}) {
|
||||
if (path.isVideoFileName) {
|
||||
return VideoPlayerWidget(
|
||||
path: path,
|
||||
type: path.startsWith("http")
|
||||
? VideoSourceType.network
|
||||
: VideoSourceType.file,
|
||||
);
|
||||
} else if (path.isImageFileName) {
|
||||
if (path.startsWith("http")) {
|
||||
return MyNetworkImage(url: path);
|
||||
} else {
|
||||
return Image.file(File(path));
|
||||
}
|
||||
} else {
|
||||
return FrequentFunctions.noWidget;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import 'dart:io';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/utilities/frequent_functions.dart';
|
||||
import 'package:ftc_mobile_app/web_services/client_services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AddEditMemoryBoxScreenController extends GetxController {
|
||||
final GlobalKey<ScaffoldState> screenKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
TextEditingController documentTitleController = TextEditingController();
|
||||
TextEditingController noteDetailsController = TextEditingController();
|
||||
|
||||
late final String serviceUserId;
|
||||
|
||||
final file = Rx<File?>(null);
|
||||
|
||||
//Should stores full path of file or url
|
||||
final filePath = "".obs;
|
||||
|
||||
onFileChooseButtonTap() async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(type: FileType.media);
|
||||
|
||||
if (result != null && result.files.single.path != null) {
|
||||
if (result.files.single.path!.isVideoFileName ||
|
||||
result.files.single.path!.isImageFileName) {
|
||||
file.value = File(result.files.single.path!);
|
||||
filePath.value = result.files.single.path!;
|
||||
} else {
|
||||
FrequentFunctions.showToast(message: "Unsupported File");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveButtonPress() async {
|
||||
if (file() == null) {
|
||||
FrequentFunctions.showToast(message: "Please select file first");
|
||||
return;
|
||||
}
|
||||
if (noteDetailsController.text.trim().isEmpty) {
|
||||
FrequentFunctions.showToast(message: "Note details field is required");
|
||||
return;
|
||||
}
|
||||
|
||||
var response = await ClientService()
|
||||
.addMemoryBoxFile(
|
||||
userId: serviceUserId,
|
||||
filePath: file.value!.path,
|
||||
noteDetails: noteDetailsController.text,
|
||||
)
|
||||
.showLoader();
|
||||
|
||||
if (response == true) {
|
||||
backButtonPressed(argument: true);
|
||||
} else {
|
||||
FrequentFunctions.showToast(message: response);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateButtonPress(String id) async {
|
||||
if (noteDetailsController.text.trim().isEmpty) {
|
||||
FrequentFunctions.showToast(message: "Note details field is required");
|
||||
return;
|
||||
}
|
||||
|
||||
var response = await ClientService()
|
||||
.updateMemoryBoxFile(
|
||||
id: id,
|
||||
userId: serviceUserId,
|
||||
filePath: file.value?.path ?? "",
|
||||
noteDetails: noteDetailsController.text,
|
||||
)
|
||||
.showLoader();
|
||||
|
||||
if (response == true) {
|
||||
backButtonPressed(argument: true);
|
||||
} else {
|
||||
FrequentFunctions.showToast(message: response);
|
||||
}
|
||||
}
|
||||
|
||||
void backButtonPressed({dynamic argument}) {
|
||||
Navigator.of(screenKey.currentContext!).pop(argument);
|
||||
}
|
||||
|
||||
void removeFocus() {
|
||||
FocusScope.of(screenKey.currentContext!).unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
noteDetailsController.dispose();
|
||||
Get.delete<AddEditMemoryBoxScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
enum VideoSourceType { file, network }
|
||||
|
||||
class VideoPlayerWidget extends StatefulWidget {
|
||||
final String path;
|
||||
final VideoSourceType type;
|
||||
|
||||
const VideoPlayerWidget({
|
||||
super.key,
|
||||
required this.path,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
State<VideoPlayerWidget> createState() => _VideoPlayerWidgetState();
|
||||
}
|
||||
|
||||
class _VideoPlayerWidgetState extends State<VideoPlayerWidget> {
|
||||
VideoPlayerController? _videoPlayerController;
|
||||
final RxBool isInitialized = false.obs;
|
||||
final RxBool isError = false.obs;
|
||||
final RxBool isPlaying = false.obs;
|
||||
double aspectRatio = 16.0 / 9.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
print("Video path: ${widget.path}");
|
||||
if (widget.type == VideoSourceType.network) {
|
||||
print("VideoSourceType.network");
|
||||
_videoPlayerController =
|
||||
VideoPlayerController.networkUrl(Uri.parse(widget.path));
|
||||
} else {
|
||||
print("VideoSourceType.file");
|
||||
_videoPlayerController = VideoPlayerController.file(File(widget.path));
|
||||
}
|
||||
|
||||
_videoPlayerController?.initialize().then((_) {
|
||||
isInitialized.value = true;
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio: aspectRatio,
|
||||
child: Obx(() {
|
||||
return (isError())
|
||||
? FrequentFunctions.centerText(text: "Something went wrong")
|
||||
: isInitialized.isFalse
|
||||
? FrequentFunctions.centerText(text: "Loading video...")
|
||||
: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: VideoPlayer(_videoPlayerController!),
|
||||
),
|
||||
Center(
|
||||
child: Obx(() {
|
||||
return (isPlaying())
|
||||
? FrequentFunctions.noWidget
|
||||
: InkWell(
|
||||
onTap: () {
|
||||
if (isPlaying.isFalse) {
|
||||
isPlaying.value = true;
|
||||
_videoPlayerController?.play();
|
||||
}
|
||||
},
|
||||
child: Icon(
|
||||
Icons.play_circle,
|
||||
color: Get.theme.primaryColor,
|
||||
size: 56.r,
|
||||
),
|
||||
);
|
||||
}),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_videoPlayerController?.dispose();
|
||||
_videoPlayerController = null;
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/riskAssessmentResponse/RiskAssessmentData.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'controller/add_edit_risk_assessment_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class AddEditRiskAssessmentScreenArgs {
|
||||
final UserData userData;
|
||||
|
||||
//If [issueData] is not null, then this screen will update its content instead
|
||||
final RiskAssessmentData? riskAssessmentData;
|
||||
|
||||
AddEditRiskAssessmentScreenArgs({
|
||||
required this.userData,
|
||||
this.riskAssessmentData,
|
||||
});
|
||||
}
|
||||
|
||||
class AddEditRiskAssessmentScreen extends StatefulWidget {
|
||||
final AddEditRiskAssessmentScreenArgs args;
|
||||
|
||||
const AddEditRiskAssessmentScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<AddEditRiskAssessmentScreen> createState() =>
|
||||
_AddDetailsToNewBodyPointScreenState();
|
||||
}
|
||||
|
||||
class _AddDetailsToNewBodyPointScreenState
|
||||
extends State<AddEditRiskAssessmentScreen> {
|
||||
final AddEditRiskAssessmentScreenController controller =
|
||||
Get.put(AddEditRiskAssessmentScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
//Note: Important
|
||||
controller.serviceUserId = widget.args.userData.id!;
|
||||
|
||||
if (widget.args.riskAssessmentData != null) {
|
||||
controller.isEditing.value = true;
|
||||
|
||||
controller.hazardTEC.text = widget.args.riskAssessmentData!.hazard ?? "";
|
||||
controller.personsExposedToHazardTEC.text =
|
||||
widget.args.riskAssessmentData!.personsExposedToHazard ?? "";
|
||||
controller.riskIdentifiedTEC.text =
|
||||
widget.args.riskAssessmentData!.riskIdentified ?? "";
|
||||
controller.controlMeasuresRequiredTEC.text =
|
||||
widget.args.riskAssessmentData!.coldMeasureRequired ?? "";
|
||||
|
||||
//Pure Risk Rating
|
||||
controller.pureRiskRatingCTEC.text =
|
||||
widget.args.riskAssessmentData!.pureRiskRating?.c?.toString() ?? "";
|
||||
controller.pureRiskRatingLTEC.text =
|
||||
widget.args.riskAssessmentData!.pureRiskRating?.l?.toString() ?? "";
|
||||
controller.pureRiskRatingRTEC.text =
|
||||
widget.args.riskAssessmentData!.pureRiskRating?.r?.toString() ?? "";
|
||||
|
||||
//In Place Rating
|
||||
controller.inPlaceYTEC.text =
|
||||
widget.args.riskAssessmentData!.inPlace?.y?.toString() ?? "";
|
||||
controller.inPlaceNTEC.text =
|
||||
widget.args.riskAssessmentData!.inPlace?.n?.toString() ?? "";
|
||||
|
||||
//Residual Risk Rating
|
||||
controller.residualRiskRatingCTEC.text =
|
||||
widget.args.riskAssessmentData!.residualRiskRating?.c?.toString() ??
|
||||
"";
|
||||
controller.residualRiskRatingLTEC.text =
|
||||
widget.args.riskAssessmentData!.residualRiskRating?.l?.toString() ??
|
||||
"";
|
||||
controller.residualRiskRatingRTEC.text =
|
||||
widget.args.riskAssessmentData!.residualRiskRating?.r?.toString() ??
|
||||
"";
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(context,
|
||||
titleText: controller.isEditing()
|
||||
? "Update Risk Assessment"
|
||||
: "Add New Risk Assessment"),
|
||||
body: SafeArea(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.r),
|
||||
children: [
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.hazardTEC,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Hazard",
|
||||
hintText: "",
|
||||
),
|
||||
20.verticalSpace,
|
||||
headingText("Pure Risk Rating"),
|
||||
8.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("C"),
|
||||
4.verticalSpace,
|
||||
dropdown(
|
||||
textEditingController:
|
||||
controller.pureRiskRatingCTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("L"),
|
||||
4.verticalSpace,
|
||||
dropdown(
|
||||
textEditingController:
|
||||
controller.pureRiskRatingLTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("R"),
|
||||
4.verticalSpace,
|
||||
dropdown(
|
||||
textEditingController:
|
||||
controller.pureRiskRatingRTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
headingText("In Place"),
|
||||
8.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("Y"),
|
||||
4.verticalSpace,
|
||||
dropdown(textEditingController: controller.inPlaceYTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("N"),
|
||||
4.verticalSpace,
|
||||
dropdown(textEditingController: controller.inPlaceNTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
headingText("Residual Risk Rating"),
|
||||
8.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("C"),
|
||||
4.verticalSpace,
|
||||
dropdown(
|
||||
textEditingController:
|
||||
controller.residualRiskRatingCTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("L"),
|
||||
4.verticalSpace,
|
||||
dropdown(
|
||||
textEditingController:
|
||||
controller.residualRiskRatingLTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("R"),
|
||||
4.verticalSpace,
|
||||
dropdown(
|
||||
textEditingController:
|
||||
controller.residualRiskRatingRTEC),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.personsExposedToHazardTEC,
|
||||
inputType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Personal (s) Exposed to hazard",
|
||||
hintText: "",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.riskIdentifiedTEC,
|
||||
inputType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Risk Identified",
|
||||
hintText: "",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.controlMeasuresRequiredTEC,
|
||||
inputType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Control Measures Required",
|
||||
hintText: "",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
Obx(
|
||||
() => CustomAppButton(
|
||||
buttonText: controller.isEditing() ? "Update" : "Save",
|
||||
onTap: () => controller.submitButtonPressed(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget headingText(String text) => CustomTextWidget(
|
||||
text: text,
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
textAlign: TextAlign.left,
|
||||
);
|
||||
|
||||
Widget dropdown({
|
||||
required TextEditingController textEditingController,
|
||||
}) {
|
||||
return SizedBox(
|
||||
height: 48.r,
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: textEditingController.text,
|
||||
isDense: true,
|
||||
onTap: () {
|
||||
FocusScopeNode().unfocus();
|
||||
},
|
||||
dropdownColor: Colors.white,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: REdgeInsets.symmetric(horizontal: 12),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: CustomAppColors.kLightGreyColor.withOpacity(0.2)),
|
||||
borderRadius: 8.toRadius(),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: CustomAppColors.kLightGreyColor),
|
||||
borderRadius: 8.toRadius(),
|
||||
),
|
||||
),
|
||||
hint: Text(
|
||||
"Select...",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
color: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
items: controller.ratings
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e.toString(),
|
||||
child: Text(e.toString()),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
isExpanded: true,
|
||||
iconSize: 20.h,
|
||||
icon: Padding(
|
||||
padding: REdgeInsets.only(right: 4.0),
|
||||
child: const Icon(Icons.arrow_drop_down_sharp, color: Colors.grey),
|
||||
),
|
||||
onChanged: (v) {
|
||||
textEditingController.text = v ?? "1";
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/riskAssessmentResponse/InPlace.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/riskAssessmentResponse/PureRiskRating.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/riskAssessmentResponse/ResidualRiskRating.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/riskAssessmentResponse/RiskAssessmentData.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AddEditRiskAssessmentScreenController extends GetxController {
|
||||
final GlobalKey<ScaffoldState> screenKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
final ratings = List.generate(9, (i) => i + 1);
|
||||
|
||||
final hazardTEC = TextEditingController();
|
||||
final personsExposedToHazardTEC = TextEditingController();
|
||||
final riskIdentifiedTEC = TextEditingController();
|
||||
final controlMeasuresRequiredTEC = TextEditingController();
|
||||
|
||||
final pureRiskRatingCTEC = TextEditingController(text: "1");
|
||||
final pureRiskRatingLTEC = TextEditingController(text: "1");
|
||||
final pureRiskRatingRTEC = TextEditingController(text: "1");
|
||||
|
||||
final residualRiskRatingCTEC = TextEditingController(text: "1");
|
||||
final residualRiskRatingLTEC = TextEditingController(text: "1");
|
||||
final residualRiskRatingRTEC = TextEditingController(text: "1");
|
||||
|
||||
final inPlaceYTEC = TextEditingController(text: "1");
|
||||
final inPlaceNTEC = TextEditingController(text: "1");
|
||||
|
||||
///[isEditing] will be true if using [AddDetailsToNewBodyPointScreen] screen to edit issue details,
|
||||
/// or say issueData is not null
|
||||
final isEditing = false.obs;
|
||||
|
||||
String serviceUserId = "";
|
||||
RiskAssessmentData? issueData;
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
if (issueData != null) {
|
||||
isEditing.value = true;
|
||||
hazardTEC.text = issueData!.hazard ?? "";
|
||||
personsExposedToHazardTEC.text = issueData!.personsExposedToHazard ?? "";
|
||||
}
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
Future<void> submitButtonPressed(BuildContext context) async {
|
||||
if (hazardTEC.text.trim().isEmpty) {
|
||||
FrequentFunctions.showToast(message: "Hazard is required");
|
||||
return;
|
||||
}
|
||||
if (personsExposedToHazardTEC.text.trim().isEmpty) {
|
||||
FrequentFunctions.showToast(
|
||||
message: "Personal (s) Exposed to hazard is required");
|
||||
return;
|
||||
}
|
||||
if (riskIdentifiedTEC.text.trim().isEmpty) {
|
||||
FrequentFunctions.showToast(message: "Risk Identified is required");
|
||||
return;
|
||||
}
|
||||
if (controlMeasuresRequiredTEC.text.trim().isEmpty) {
|
||||
FrequentFunctions.showToast(
|
||||
message: "Control Measures Required is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// var result = (isEditing.isFalse)
|
||||
final result = await ClientService()
|
||||
.createRiskAssesments(
|
||||
data: RiskAssessmentData(
|
||||
userId: serviceUserId,
|
||||
hazard: hazardTEC.text.trim(),
|
||||
personsExposedToHazard: personsExposedToHazardTEC.text.trim(),
|
||||
riskIdentified: riskIdentifiedTEC.text.trim(),
|
||||
coldMeasureRequired: controlMeasuresRequiredTEC.text.trim(),
|
||||
pureRiskRating: PureRiskRating(
|
||||
c: int.parse(pureRiskRatingCTEC.text.trim()),
|
||||
l: int.parse(pureRiskRatingLTEC.text.trim()),
|
||||
r: int.parse(pureRiskRatingRTEC.text.trim()),
|
||||
),
|
||||
residualRiskRating: ResidualRiskRating(
|
||||
c: int.parse(residualRiskRatingCTEC.text.trim()),
|
||||
l: int.parse(residualRiskRatingLTEC.text.trim()),
|
||||
r: int.parse(residualRiskRatingRTEC.text.trim()),
|
||||
),
|
||||
inPlace: InPlace(
|
||||
y: int.parse(inPlaceYTEC.text.trim()),
|
||||
n: int.parse(inPlaceNTEC.text.trim()),
|
||||
),
|
||||
),
|
||||
)
|
||||
.showLoader();
|
||||
if (result == true) {
|
||||
Navigator.of(screenKey.currentContext!).pop(true);
|
||||
} else {
|
||||
FrequentFunctions.showToast(message: result);
|
||||
}
|
||||
// : await ClientService()
|
||||
// .updateHealthIssueData(
|
||||
// issueId: issueData!.id,
|
||||
// categoryId: issueData!.bodyPointsCategory!.id,
|
||||
// healthNote: healthNoteController.text.trim(),
|
||||
// complaint: complaintController.text.trim())
|
||||
// .showLoader();
|
||||
//
|
||||
// if (result is! String) {
|
||||
// Navigator.of(context).pop(true);
|
||||
// } else {
|
||||
// if (result.isNotEmpty) {
|
||||
// FrequentFunctions.showToast(message: result);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void removeFocus() {
|
||||
FocusScope.of(screenKey.currentContext!).unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
hazardTEC.dispose();
|
||||
personsExposedToHazardTEC.dispose();
|
||||
riskIdentifiedTEC.dispose();
|
||||
controlMeasuresRequiredTEC.dispose();
|
||||
|
||||
pureRiskRatingCTEC.dispose();
|
||||
pureRiskRatingLTEC.dispose();
|
||||
pureRiskRatingRTEC.dispose();
|
||||
|
||||
residualRiskRatingCTEC.dispose();
|
||||
residualRiskRatingLTEC.dispose();
|
||||
residualRiskRatingRTEC.dispose();
|
||||
|
||||
inPlaceYTEC.dispose();
|
||||
inPlaceNTEC.dispose();
|
||||
|
||||
Get.delete<AddEditRiskAssessmentScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/HealthIssuesDetailsModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../controllers/clients/add_details_to_new_body_point_screen_controller.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import '../../custom_widgets/clients/category_subcategory_dropdowns_widget.dart';
|
||||
|
||||
class AddDetailsToNewBodyPointScreenArgs {
|
||||
final UserData userData;
|
||||
|
||||
//If [issueData] is not null, then this screen will update its content instead
|
||||
final HealthIssueDetailsModel? issueData;
|
||||
|
||||
AddDetailsToNewBodyPointScreenArgs({
|
||||
required this.userData,
|
||||
this.issueData,
|
||||
});
|
||||
}
|
||||
|
||||
class AddDetailsToNewBodyPointScreen extends StatefulWidget {
|
||||
final AddDetailsToNewBodyPointScreenArgs args;
|
||||
|
||||
const AddDetailsToNewBodyPointScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<AddDetailsToNewBodyPointScreen> createState() =>
|
||||
_AddDetailsToNewBodyPointScreenState();
|
||||
}
|
||||
|
||||
class _AddDetailsToNewBodyPointScreenState
|
||||
extends State<AddDetailsToNewBodyPointScreen> {
|
||||
final AddDetailsToNewBodyPointScreenController controller =
|
||||
Get.put(AddDetailsToNewBodyPointScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUserId = widget.args.userData.id!;
|
||||
controller.issueData = widget.args.issueData;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(context,
|
||||
titleText: controller.isEditing()
|
||||
? "Update Health Issue - ${widget.args.issueData!.bodyPointsCategory?.name}"
|
||||
: "Add Health Issue"),
|
||||
body: SafeArea(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.r),
|
||||
children: [
|
||||
controller.isEditing()
|
||||
? FrequentFunctions.noWidget
|
||||
: CategorySubcategoryDropdownsWidget(
|
||||
controller: controller.catSubCatController),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.healthNoteController,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Health Note",
|
||||
hintText: "Example: Eye Pain / Headache",
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.complaintController,
|
||||
inputType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Complaint",
|
||||
hintText: "Example: Minor Pain on right Side",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
Obx(
|
||||
() => CustomAppButton(
|
||||
buttonText:
|
||||
controller.isEditing() ? "Update Issue" : "Add Issue",
|
||||
onTap: () => controller.submitButtonPressed(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<AddDetailsToNewBodyPointScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
183
lib/view/screens/clients/add_new_document_screen.dart
Normal file
183
lib/view/screens/clients/add_new_document_screen.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../controllers/clients/add_new_document_screen_controller.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class AddNewDocumentScreen extends StatefulWidget {
|
||||
const AddNewDocumentScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AddNewDocumentScreen> createState() => _AddNewDocumentScreenState();
|
||||
}
|
||||
|
||||
class _AddNewDocumentScreenState extends State<AddNewDocumentScreen> {
|
||||
final controller = Get.put(AddNewDocumentScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
// onBackButton: () => controller.backButtonPressed(),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: controller.docIdReceived.value
|
||||
? " Update Document"
|
||||
: controller.viewOnly.value
|
||||
? " View Document"
|
||||
: " Add Document",
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
controller: controller.documentTitleController,
|
||||
hintText: "Document title",
|
||||
heading: "Title",
|
||||
onChange: (_) {},
|
||||
),
|
||||
// ConsentScreenTextField(
|
||||
// headingText: "Document title",
|
||||
// hintText: "Title of Document",
|
||||
// viewOnly: controller.viewOnly.value,
|
||||
// fieldController: controller.documentTitleController),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
controller: controller.documentDetailsController,
|
||||
heading: "Document Details",
|
||||
hintText: "Details Of Document",
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
onChange: (_) {},
|
||||
),
|
||||
// ConsentScreenTextField(
|
||||
// headingText: "Document Details",
|
||||
// hintText: "Details Of Document",
|
||||
// viewOnly: controller.viewOnly.isTrue,
|
||||
// fieldController: controller.documentDetailsController),
|
||||
20.verticalSpace,
|
||||
|
||||
// Text(
|
||||
// "Upload document",
|
||||
// style: TextStyle(
|
||||
// fontSize: 14.sp,
|
||||
// fontWeight: FontWeight.w400,
|
||||
// color: CustomAppColors.kDarkBlueTextColor,
|
||||
// ),
|
||||
// ),
|
||||
// 6.verticalSpace,
|
||||
|
||||
// Obx(() {
|
||||
//
|
||||
// }),
|
||||
|
||||
// SizedBox(
|
||||
// width: 150.r,
|
||||
// height: 32.r,
|
||||
// child: const CustomAppButton(buttonText: "Choose file"),
|
||||
// ),
|
||||
|
||||
controller.viewOnly.value
|
||||
? controller.docFilePath.isNotEmpty
|
||||
? Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 3,
|
||||
child: CustomTextWidget(
|
||||
text: "Document:",
|
||||
fontSize: 20.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 2,
|
||||
child: Obx(
|
||||
() => CustomTextWidget(
|
||||
text: controller.docFilePath.value
|
||||
.split("/")
|
||||
.last,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Container(
|
||||
width: MediaQuery.of(context).size.width / 2,
|
||||
)
|
||||
: Obx(
|
||||
() => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
controller.docFilePath.isNotEmpty
|
||||
? Expanded(
|
||||
flex: 1,
|
||||
child: SizedBox(
|
||||
width:
|
||||
MediaQuery.of(context).size.width / 2,
|
||||
child: Obx(
|
||||
() => CustomTextWidget(
|
||||
text: controller.docFilePath.value
|
||||
.split("/")
|
||||
.last,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
width: MediaQuery.of(context).size.width / 2,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: CustomAppButton(
|
||||
buttonColor: CustomAppColors.kIconColor,
|
||||
borderColor: CustomAppColors.kIconColor,
|
||||
buttonText: controller.docIdReceived.value
|
||||
? "Change Document File"
|
||||
: "Add Document File",
|
||||
onTap: controller.onFileChooseButtonTap,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
32.verticalSpace,
|
||||
Obx(
|
||||
() => CustomAppButton(
|
||||
buttonText: controller.docIdReceived.value
|
||||
? "Update Document"
|
||||
: controller.viewOnly.value
|
||||
? "Ok"
|
||||
: "Add Document",
|
||||
onTap: () => controller.submitButtonPressed(),
|
||||
),
|
||||
),
|
||||
5.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<AddNewDocumentScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
237
lib/view/screens/clients/add_new_recent_incident_screen.dart
Normal file
237
lib/view/screens/clients/add_new_recent_incident_screen.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/add_new_recent_incident_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/recent_incidents_model.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quill_html_editor/quill_html_editor.dart';
|
||||
|
||||
class AddNewRecentIncidentsScreenArgs {
|
||||
final String? userId;
|
||||
final RecentIncidentsModel? incidentsModel;
|
||||
|
||||
AddNewRecentIncidentsScreenArgs({this.userId, this.incidentsModel});
|
||||
}
|
||||
|
||||
class AddNewRecentIncidentsScreen extends StatefulWidget {
|
||||
final AddNewRecentIncidentsScreenArgs args;
|
||||
|
||||
const AddNewRecentIncidentsScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<AddNewRecentIncidentsScreen> createState() =>
|
||||
_AddNewRecentIncidentsScreenState();
|
||||
}
|
||||
|
||||
class _AddNewRecentIncidentsScreenState
|
||||
extends State<AddNewRecentIncidentsScreen> {
|
||||
late final AddNewRecentIncidentScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(AddNewRecentIncidentScreenController(widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.onBackPress(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.onBackPress(context);
|
||||
// Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: widget.args.userId.isNotNullOrEmpty()
|
||||
? 'Add Recent Incident'
|
||||
: 'Update Recent Incident',
|
||||
// text: 'Add New Recent Incidents',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
// const CustomTextWidget(
|
||||
// text: "Select Incident Date",
|
||||
// textAlign: TextAlign.left,
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.incidentDateTEC,
|
||||
hintText: "Select Incident Date",
|
||||
heading: "Select Incident Date",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
|
||||
// InkWell(
|
||||
// onTap: () => controller.selectDateFromPicker(
|
||||
// context: context,
|
||||
// maxDate: DateTime(DateTime.now().year + 1),
|
||||
// minDate: DateTime(DateTime.now().year - 4)),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Obx(
|
||||
// () => CustomTextWidget(
|
||||
// text: DateFormatter()
|
||||
// .getHolidayDate(controller.selectedDate.value),
|
||||
// isExpanded: false,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// fontColor: CustomAppColors.kSecondaryColor,
|
||||
// ),
|
||||
// ),
|
||||
// const Spacer(),
|
||||
// const Icon(Icons.calendar_today_outlined),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
// Container(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 5.h),
|
||||
// child: CustomTextFieldWidget(
|
||||
// controller: controller.incidentTitleTEC,
|
||||
// heading: "Incident Title"),
|
||||
// ),
|
||||
|
||||
12.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.incidentTitleTEC,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
hintText: "Incident Title",
|
||||
heading: "Incident Title",
|
||||
onChange: (_) {},
|
||||
),
|
||||
|
||||
12.verticalSpace,
|
||||
|
||||
ToolBar(
|
||||
toolBarColor: Colors.cyan.shade50,
|
||||
activeIconColor: Colors.green,
|
||||
padding: const EdgeInsets.all(8),
|
||||
iconSize: 20,
|
||||
toolBarConfig: ToolBarStyle.values
|
||||
.where((e) => [
|
||||
ToolBarStyle.image,
|
||||
ToolBarStyle.video,
|
||||
].contains(e).not)
|
||||
.toList(),
|
||||
controller: controller.incidentDetailsQuillFieldController,
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: LayoutBuilder(builder: (_, c) {
|
||||
return QuillHtmlEditor(
|
||||
hintText: 'Recent Incident Details',
|
||||
controller: controller.incidentDetailsQuillFieldController,
|
||||
isEnabled: true,
|
||||
minHeight: c.maxHeight,
|
||||
text: widget.args.incidentsModel?.note ?? "",
|
||||
hintTextAlign: TextAlign.start,
|
||||
padding: REdgeInsets.only(left: 10, top: 5, right: 5),
|
||||
hintTextPadding:
|
||||
REdgeInsets.only(left: 10, top: 5, right: 5),
|
||||
backgroundColor: Colors.grey.withOpacity(0.1),
|
||||
onFocusChanged: (hasFocus) {
|
||||
debugPrint('has focus $hasFocus');
|
||||
if (hasFocus && FocusScope.of(context).hasFocus) {
|
||||
controller.removeFocus();
|
||||
}
|
||||
},
|
||||
// onTextChanged: (text) =>
|
||||
// debugPrint('widget text change $text'),
|
||||
// onEditorCreated: () => debugPrint('Editor has been loaded'),
|
||||
// onEditingComplete: (s) => debugPrint('Editing completed $s'),
|
||||
onEditorResized: (height) =>
|
||||
debugPrint('Editor resized $height'),
|
||||
onSelectionChanged: (sel) =>
|
||||
debugPrint('${sel.index},${sel.length}'),
|
||||
loadingBuilder: (context) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 0.4.r,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
24.verticalSpace,
|
||||
Obx(() {
|
||||
return IgnorePointer(
|
||||
ignoring: controller.isButtonEnabled.isFalse,
|
||||
child: CustomAppButton(
|
||||
buttonText: widget.args.incidentsModel == null
|
||||
? "Submit"
|
||||
: "Update",
|
||||
buttonColor: controller.isButtonEnabled()
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: CustomAppColors.kLightGreyColor,
|
||||
borderColor: controller.isButtonEnabled()
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: CustomAppColors.kLightGreyColor,
|
||||
onTap: () {
|
||||
controller.submitButtonPressed(context);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
163
lib/view/screens/clients/all_care_notes_screen.dart
Normal file
163
lib/view/screens/clients/all_care_notes_screen.dart
Normal file
@@ -0,0 +1,163 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/all_care_notes_screen_contorller.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/allCareNotes/CarePlans.dart';
|
||||
import 'package:ftc_mobile_app/utilities/enums/care_note_form_type.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
||||
|
||||
class AllCareNotesScreenArgs {
|
||||
final String serviceUserId;
|
||||
|
||||
AllCareNotesScreenArgs({required this.serviceUserId});
|
||||
}
|
||||
|
||||
class AllCareNotesScreen extends StatefulWidget {
|
||||
final AllCareNotesScreenArgs args;
|
||||
|
||||
const AllCareNotesScreen({super.key, required this.args});
|
||||
|
||||
@override
|
||||
State<AllCareNotesScreen> createState() => _AllCareNotesScreenState();
|
||||
}
|
||||
|
||||
class _AllCareNotesScreenState extends State<AllCareNotesScreen> {
|
||||
final AllCareNotesScreenController controller =
|
||||
Get.put(AllCareNotesScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
//Important
|
||||
controller.serviceUserId = widget.args.serviceUserId;
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
controller.getCareNotesList();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kSmokeColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'All Care Notes',
|
||||
),
|
||||
body: SafeArea(
|
||||
child: _listView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _listView() {
|
||||
return Obx(() {
|
||||
final list = controller.notesList();
|
||||
final canLoadMore = controller.canLoadMore.value;
|
||||
return SmartRefresher(
|
||||
controller: controller.listRC,
|
||||
scrollController: controller.listSC,
|
||||
header: FrequentFunctions.waterDropHeader,
|
||||
enablePullUp: canLoadMore,
|
||||
onRefresh: controller.onRefresh,
|
||||
onLoading: controller.onLoading,
|
||||
child: (list.isEmpty)
|
||||
? Container(
|
||||
color: Colors.white,
|
||||
child: const Center(
|
||||
child: Text("No data found"),
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (_, index) {
|
||||
final item = list[index];
|
||||
return _listItem(item);
|
||||
},
|
||||
separatorBuilder: (_, i) => 8.verticalSpace,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _listItem(CarePlan item) {
|
||||
final isMoodRatingForm =
|
||||
item.noteType == CareNotesFormType.moodRatingForm.apiValue;
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
_onListItemTap(item);
|
||||
},
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(color: Colors.white),
|
||||
padding: REdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: item.noteType ?? "",
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
(item.eventDateTime == null)
|
||||
? FrequentFunctions.noWidget
|
||||
: CustomTextWidget(
|
||||
text: DateFormatter.ddMMyyyyhhmmFormat(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
item.eventDateTime!)
|
||||
.toLocal()),
|
||||
fontColor: Colors.grey,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 10.sp,
|
||||
),
|
||||
(item.isHTML != true)
|
||||
? CustomTextWidget(
|
||||
text: isMoodRatingForm
|
||||
? (item.title ?? "")
|
||||
: (item.noteDetails ?? ""),
|
||||
textAlign: TextAlign.left,
|
||||
fontColor: Colors.black54,
|
||||
fontSize: 12.sp,
|
||||
maxLines: 3,
|
||||
fontWeight: FontWeight.w400,
|
||||
).paddingOnly(top: 6.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
(item.flag == true)
|
||||
? CustomTextWidget(
|
||||
text: "Handover Review",
|
||||
fontColor: Colors.green,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
).paddingOnly(top: 6.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(Icons.keyboard_arrow_right_rounded)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onListItemTap(CarePlan item) {
|
||||
Navigator.pushNamed(context, CustomRouteNames.kCareNoteDetailScreenRoute,
|
||||
arguments: item);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
259
lib/view/screens/clients/appointments_screen.dart
Normal file
259
lib/view/screens/clients/appointments_screen.dart
Normal file
@@ -0,0 +1,259 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/app_dialogs.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:grouped_list/grouped_list.dart';
|
||||
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import '../../../models/appointmentsListResponse/AppointmentsListResponse.dart';
|
||||
import '../../custom_widgets/my_circle_image.dart';
|
||||
|
||||
class AppointmentScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const AppointmentScreen({Key? key, required this.userData}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AppointmentScreen> createState() => _AppointmentScreenState();
|
||||
}
|
||||
|
||||
class _AppointmentScreenState extends State<AppointmentScreen> {
|
||||
final controller = Get.put(AppointmentScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUserId = widget.userData.id ?? "";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Appointments',
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url: "${WebUrls.baseUrl}${widget.userData.profilePictureUrl}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 80.r,
|
||||
width: 80.r,
|
||||
),
|
||||
),
|
||||
16.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: widget.userData.displayName,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
16.verticalSpace,
|
||||
Expanded(child: _appointmentsList()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _appointmentsList() {
|
||||
return ObxValue((RxList<AppointmentsListResponseData> appointments) {
|
||||
return SmartRefresher(
|
||||
key: const ValueKey("refreshListAppointments"),
|
||||
controller: controller.listRC,
|
||||
scrollController: controller.listSC,
|
||||
enablePullUp: false,
|
||||
header: FrequentFunctions.waterDropHeader,
|
||||
onRefresh: controller.onRefresh,
|
||||
child: (appointments.isEmpty)
|
||||
? FrequentFunctions.centerText(text: "No appointments yet")
|
||||
: GroupedListView<AppointmentsListResponseData, int>(
|
||||
elements: appointments(),
|
||||
groupBy: (d) {
|
||||
return DateTime.fromMillisecondsSinceEpoch(d.appointmentDate!)
|
||||
.toLocal()
|
||||
.isAfter(DateTime.now())
|
||||
? 0
|
||||
: 1;
|
||||
},
|
||||
groupSeparatorBuilder: (int groupByValue) {
|
||||
final label = groupByValue == 0
|
||||
? "Upcoming Appointments"
|
||||
: "Previous Appointments";
|
||||
|
||||
return _buildGroupSeparatorWidget(label);
|
||||
},
|
||||
itemBuilder: (context, element) =>
|
||||
_buildItemWidget(appointments.indexOf(element), element),
|
||||
separator: 8.verticalSpace,
|
||||
groupComparator: (item1, item2) {
|
||||
return item1.compareTo(item2);
|
||||
},
|
||||
),
|
||||
);
|
||||
}, controller.appointments);
|
||||
}
|
||||
|
||||
Widget _buildGroupSeparatorWidget(String susTag) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20.w),
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
isExpanded: false,
|
||||
text: susTag,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemWidget(int index, AppointmentsListResponseData data) {
|
||||
return AppointmentWidget(data: data);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class AppointmentWidget extends StatelessWidget {
|
||||
final AppointmentsListResponseData data;
|
||||
|
||||
const AppointmentWidget({
|
||||
super.key,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
// height: 150,
|
||||
alignment: Alignment.center,
|
||||
margin: EdgeInsets.only(left: 20.w, bottom: 5.h, right: 10.w, top: 10.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.h),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(
|
||||
left: BorderSide(color: Get.theme.primaryColor, width: 6),
|
||||
top: BorderSide(color: Get.theme.primaryColor, width: 1),
|
||||
right: BorderSide(color: Get.theme.primaryColor, width: 1),
|
||||
bottom: BorderSide(color: Get.theme.primaryColor, width: 1),
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(2.0.r),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: data.staff?.name ?? "",
|
||||
fontWeight: FontWeight.bold,
|
||||
isExpanded: false),
|
||||
CustomTextWidget(
|
||||
text: data.appointmentStartTime ?? "",
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextWidget(
|
||||
text: data.appointmentDetails ?? "",
|
||||
fontSize: 12.sp,
|
||||
isExpanded: false,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
10.horizontalSpace,
|
||||
CustomTextWidget(
|
||||
text: DateFormatter().getAppointmentTime(
|
||||
DateTime.fromMillisecondsSinceEpoch(data.appointmentDate!)),
|
||||
fontSize: 14.sp,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
],
|
||||
),
|
||||
10.verticalSpace,
|
||||
SizedBox(
|
||||
height: 32.r,
|
||||
child: CustomAppButton(
|
||||
onTap: () {
|
||||
AppDialog.showAppointmentDetailDialog(data: data);
|
||||
},
|
||||
buttonText: "View Appointment",
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
),
|
||||
),
|
||||
// SizedBox(
|
||||
// height: 5.h,
|
||||
// ),
|
||||
// const ViewAppointmentButtonWidget(
|
||||
// text: "+Add Note",
|
||||
// textColor: CustomAppColors.kSecondaryColor,
|
||||
// buttonColor: CustomAppColors.kPrimaryColor,
|
||||
// borderColor: CustomAppColors.kSecondaryColor,
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ViewAppointmentButtonWidget extends StatelessWidget {
|
||||
const ViewAppointmentButtonWidget({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.textColor,
|
||||
required this.buttonColor,
|
||||
this.borderColor,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final Color textColor;
|
||||
final Color buttonColor;
|
||||
final Color? borderColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(vertical: 5.h),
|
||||
margin: EdgeInsets.symmetric(horizontal: 2.w),
|
||||
decoration: BoxDecoration(
|
||||
border: borderColor != null ? Border.all(color: borderColor!) : null,
|
||||
color: buttonColor,
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
),
|
||||
child: CustomTextWidget(
|
||||
text: text,
|
||||
fontColor: textColor,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
116
lib/view/screens/clients/careNoteForms/ABC_form_screen.dart
Normal file
116
lib/view/screens/clients/careNoteForms/ABC_form_screen.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import '../../../../controllers/clients/careNoteFormControllers/ABC_form_screen_controller.dart';
|
||||
|
||||
class ABCFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const ABCFormScreen({Key? key, required this.args}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ABCFormScreen> createState() => _ABCFormScreenState();
|
||||
}
|
||||
|
||||
class _ABCFormScreenState extends State<ABCFormScreen> {
|
||||
late final ABCFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(ABCFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add ABC Note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () =>controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.antecedentEventsController,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: 'Antecedent Events',
|
||||
hintText: 'Type here...',
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.behaviourController,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: 'Behaviour',
|
||||
hintText: 'Type here...',
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.consequenceEventsController,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: 'Consequence Events',
|
||||
hintText: 'Type here...',
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,663 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/consent_capacity_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class ConsentCapacityFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const ConsentCapacityFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ConsentCapacityFormScreen> createState() =>
|
||||
_ConsentCapacityFormScreenState();
|
||||
}
|
||||
|
||||
class _ConsentCapacityFormScreenState extends State<ConsentCapacityFormScreen> {
|
||||
late final ConsentCapacityFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(ConsentCapacityFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Consent, Capacity, MCA & DOLS note',
|
||||
),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.commentsController,
|
||||
heading: "Comments",
|
||||
hintText: "Type comments here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "Is an MCA required to be completed?",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
_radioGroup(controller.selectedMCARequiredOption),
|
||||
20.verticalSpace,
|
||||
Obx(() {
|
||||
return controller.selectedMCARequiredOption() == "Yes"
|
||||
? Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _otherFormWidgets(),
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
}),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _radioGroup(Rx<String?> selectedOption) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Yes',
|
||||
selectedOption: selectedOption,
|
||||
),
|
||||
),
|
||||
16.horizontalSpace,
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'No',
|
||||
selectedOption: selectedOption,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _otherFormWidgets() {
|
||||
return [
|
||||
Html(data: """<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p><strong>This Mental Capacity Assessment must adhere to the Act’s 5 principles:</strong>
|
||||
</p>
|
||||
<ul>
|
||||
<li>Every adult has the right to make his or her own decisions and must be assumed to
|
||||
have capacity to make them unless proved otherwise.
|
||||
</li>
|
||||
<li>A person must be given all practicable help before anyone treat them as not being
|
||||
able to make their own decisions.
|
||||
</li>
|
||||
<li>Just because an individual makes what may be seen as an unwise decision, they should
|
||||
not be treated as lacking capacity to make that decision
|
||||
</li>
|
||||
<li>Anything done or any decision made on behalf of a person who lacks capacity must be
|
||||
done in their best interests.
|
||||
</li>
|
||||
<li>Anything done or any decision made on behalf of a person who lacks capacity should
|
||||
be the least restrictive of their basic rights and freedoms.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-12"><p>This form has been developed to support compliance with the Mental
|
||||
Capacity Act 2005. There is a statutory requirement for anyone undertaking an assessment to
|
||||
have regard to the Code of Practice for the Mental Capacity Act. References given below
|
||||
refer to the relevant paragraphs of the Mental Capacity Act Code of Practice. Please also
|
||||
refer to MCA and DoLS Policy and Guidance. (For day to day decisions, please print out/ fill
|
||||
in relevant sections 1.1 - 1.10)</p>
|
||||
</div>
|
||||
</div>"""),
|
||||
10.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.mentalCapacityAssessmentDetailController,
|
||||
heading: "Detail",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data: """<div class="row">
|
||||
<div class="col-md-12"><p><strong>1.2 What is the specific decision relevant to this mental
|
||||
capacity assessment?</strong> Please ensure that the decision is phrased in a way to enable
|
||||
all viable options to be discussed. The MCA Code paragraph 4.4 states 'An assessment of a
|
||||
person’s capacity must be based on their ability to make a specific decision at the time it
|
||||
needs to be made, and not their ability to make decisions in general.'</p>
|
||||
</div>
|
||||
</div>""",
|
||||
),
|
||||
10.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.specificDecisionDetailController,
|
||||
heading: "Detail",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>1.3 Person undertaking/or who has undertaken this assessment of
|
||||
capacity?</strong> The person with greatest responsibility for the specific decision is known as
|
||||
the ‘decision-maker’ and should assess capacity. The decision maker is the person intending to
|
||||
make the decision or carry out the action. Complex decisions may require specialist assessment -
|
||||
seek guidance. See 4.38 to 4.43 of the Code.</p></div>
|
||||
""",
|
||||
),
|
||||
10.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.name1Controller,
|
||||
heading: "Name",
|
||||
hintText: "Type here...",
|
||||
inputType: TextInputType.name,
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.roleController,
|
||||
heading: "Role",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.organisationController,
|
||||
heading: "Organisation",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.addressController,
|
||||
heading: "Address",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.telController,
|
||||
heading: "Tel",
|
||||
hintText: "Type here...",
|
||||
inputType: TextInputType.phone,
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.emailController,
|
||||
heading: "Email",
|
||||
hintText: "Type here...",
|
||||
inputType: TextInputType.emailAddress,
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectAssessmentDateTime(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.assessmentDateTimeController,
|
||||
hintText: "Select...",
|
||||
heading: "Date and time of assessment",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>1.4 What concerns/triggers have given rise to this assessment of
|
||||
capacity?</strong> People have the right to make decisions that others might think are unwise. A
|
||||
person who makes a decision that others think is unwise should not automatically be labelled as
|
||||
lacking the capacity to make a decision. See MCA Code 4.35.</p></div>
|
||||
<p><strong>What is the reason to believe this person may lack capacity to make this particular decision? State your evidence:</strong></p>
|
||||
""",
|
||||
),
|
||||
10.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller:
|
||||
controller.lackCapacityToMakeParticularDecisionDetailController,
|
||||
heading: "Detail",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>1.5 Record your evidence here of the actions you have taken to
|
||||
support the person. </strong>Consider what kind of help and support you can give the person to
|
||||
help them understand, retain, weigh up information and communicate their decision. </p>
|
||||
<p><strong>Have you discussed with the person and/or appropriate others the most suitable venue
|
||||
for the assessment? </strong>For example: Does the person feel more comfortable in their own
|
||||
room? Does it need to be quiet? See MCA Code 3.13.</p>
|
||||
<p><strong>Have you discussed with the person and/or appropriate others to establish timing of
|
||||
assessment</strong> For example: Is there a time of day that is better for the person? Would
|
||||
it help to have a particular person present? See MCA Code 3.14.</p>
|
||||
<p><strong>Does the person have any language/communication issues? </strong> For example: Do
|
||||
they have hearing or speech difficulties? Do you need an interpreter? Do they communicate
|
||||
using special equipment e.g. a light talker communication device? See MCA Code 3.11.</p>
|
||||
<p><strong>Have you provided all the information, regarding all viable and available options
|
||||
that the person needs to consider, to make an informed decision? </strong>See MCA Code 3.7.
|
||||
The assessor must ensure that the person has:</p>
|
||||
<ol>
|
||||
<li>Sufficiently detailed alternative plans explained to them to allow them to weigh up the
|
||||
alternatives and make an informed choice where possible.
|
||||
</li>
|
||||
<li>Been supported by the assessor to explore the reasonably foreseeable consequences of
|
||||
deciding one way or another, or failing to make the decision.
|
||||
</li>
|
||||
</ol>
|
||||
</div>""",
|
||||
),
|
||||
10.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.recordYourEvidenceDescribeController,
|
||||
heading: "Describe",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.viableOptionsConsideredController,
|
||||
heading: "Viable options considered",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>If the decision is not urgent can it be delayed because the person
|
||||
is likely to regain or develop the capacity to make it for themselves?</strong></p>
|
||||
</div>""",
|
||||
),
|
||||
10.verticalSpace,
|
||||
...List.generate(controller.canDecisionBeDelayedOptions.length, (index) {
|
||||
final e = controller.canDecisionBeDelayedOptions[index];
|
||||
return ObxValue((RxBool isChecked) {
|
||||
return CheckboxListTile(
|
||||
value: isChecked(),
|
||||
onChanged: isChecked,
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: CustomAppColors.kSmokeColor)),
|
||||
tileColor:
|
||||
(index % 2 == 0) ? CustomAppColors.kSmokeColor : Colors.white,
|
||||
title: CustomTextWidget(
|
||||
text: e.requirements,
|
||||
isExpanded: false,
|
||||
fontSize: 13.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
);
|
||||
}, e.isChecked);
|
||||
}),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.explainWhyTickedBoxController,
|
||||
heading: "Explain why you have ticked box(s)",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>1.6 Two Stage Capacity Assessment</strong> Answer the question
|
||||
with facts. The questions cannot be answered with a simple “yes” or “no” and you are asked to
|
||||
describe the assessment process. See MCA Code Ch. 4. </p>
|
||||
<p><strong>Stage 1. Is there an impairment or disturbance in the functioning of the person’s
|
||||
mind or brain</strong> The person may not have a diagnosis but the Code says that proof of
|
||||
an impairment or disturbance of the functioning of the mind or brain is required. You should
|
||||
record here your reasons for believing this to be the case. See 4.11 - 4.12 of the Code.
|
||||
This could be because of, for example, a head injury, a suspected infection or stroke, a
|
||||
diagnosed dementia, mental illness, or learning disability.</p>
|
||||
</div>""",
|
||||
),
|
||||
_radioGroup(controller.selectedImpairmentOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.impairmentDescribeController,
|
||||
heading: "Describe",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data: """<div>
|
||||
<p><strong>If the person does not meet Stage 1, the assessment should immediately stop. Stage 2.
|
||||
Record here how the identified impairment or disturbance in Stage 1 is affecting the
|
||||
person’s ability to make the decision.</strong>See 4.13 to 4.30 of the Code.</p>
|
||||
<p><strong>Can the person understand the information relevant to the decision? </strong> See
|
||||
4.16 to 4.19 of the Code.</p>
|
||||
</div>""",
|
||||
),
|
||||
_radioGroup(controller.selectedCanPersonDecisionInfoOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.describeCanPersonDecisionInfoController,
|
||||
heading: "Describe how you assessed this",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<p><strong>Can they retain that information long enough to make the decision? </strong>See 4.20 to 4.22 of the Code.</p>""",
|
||||
),
|
||||
_radioGroup(controller.selectedCanTheyRetainOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.describeCanTheyRetainController,
|
||||
heading: "Describe how you assessed this",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<p><strong>Can they use or weigh up that information as part of the process of making the decision? </strong>See 4.21 to 4.22 of the Code.</p>""",
|
||||
),
|
||||
_radioGroup(controller.selectedCanTheyUseOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.describeCanTheyUseController,
|
||||
heading: "Describe how you assessed this",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<p><strong>Can they communicate their decision, by any means available to them? </strong>See 4.23 to 4.25 of the Code.</p>""",
|
||||
),
|
||||
_radioGroup(controller.selectedCanTheyCommunicateOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.describeCanTheyCommunicateController,
|
||||
heading: "Describe how you assessed this",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data: """<div>
|
||||
<p><strong>NB. If all of the answers to the four questions above are YES, then Stage 2 is not
|
||||
met
|
||||
and the assessment must end. </strong></p>
|
||||
<p><strong>Stage 3: Causative Nexus</strong> There is a causative link between the impairment or
|
||||
disturbance in the functioning of mind and brain AND the inability to make the required
|
||||
decision. You must be able to evidence that the reason the person is unable to make the
|
||||
decision is because of the impairment or disturbance in the functioning of mind or brain and
|
||||
for no other reason. </p>
|
||||
</div>""",
|
||||
),
|
||||
...List.generate(controller.causativeNexusOptions.length, (index) {
|
||||
final e = controller.causativeNexusOptions[index];
|
||||
return ObxValue((RxBool isChecked) {
|
||||
return CheckboxListTile(
|
||||
value: isChecked(),
|
||||
onChanged: isChecked,
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: CustomAppColors.kSmokeColor)),
|
||||
tileColor:
|
||||
(index % 2 == 0) ? CustomAppColors.kSmokeColor : Colors.white,
|
||||
title: CustomTextWidget(
|
||||
text: e.requirements,
|
||||
isExpanded: false,
|
||||
fontSize: 13.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
);
|
||||
}, e.isChecked);
|
||||
}),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.evidenceController,
|
||||
heading: "Evidence",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div><p><strong>1.7 Lack of mental capacity as a result of an impairment/disturbance in mind/brain
|
||||
must
|
||||
be distinguished from a situation where a person is unable to make their own decision as a
|
||||
result of duress or undue influence. A person who has the mental capacity to make decisions may
|
||||
have their ability to give free and true consent impaired if they are under constraint, coercion
|
||||
or undue influence. Duress and undue influence may be affected by eroded confidence due to fear
|
||||
of reprisal or abandonment, sense of obligation, cultural factors, power relationships or
|
||||
coercive control within domestic abuse. Do you have a concern that the person may be under
|
||||
duress/coercion or undue influence in relation to the making of this decision? If so, this will
|
||||
not satisfy the Stage 1 (Diagnostic) test. You have to have an impairment or disturbance of the
|
||||
mind or brain to satisfy that test. </strong></p><p><strong>Do you have a concern that the person may be under duress, coercion or undue influence?</strong></p></div>""",
|
||||
),
|
||||
_radioGroup(controller.selectedDoYouHaveConcernOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.whatIsYourEvidenceController,
|
||||
heading: "If yes, what is your evidence for saying this?",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
10.verticalSpace,
|
||||
Html(
|
||||
data:
|
||||
"""<p>If yes, what actions you intend to take (including consideration of seeking management/legal advice)</p>"""),
|
||||
_multilineTextField(
|
||||
controller: controller.seekingManagementDescribeController,
|
||||
heading: "Describe",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<p><strong>1.8 Please record here any further information or content of your interview with the person.</strong></p>"""),
|
||||
_multilineTextField(
|
||||
controller: controller.recordInterviewDescribeController,
|
||||
heading: "Describe",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>1.9 Determination of Capacity</strong></p>
|
||||
<p>I have assessed this person’s capacity to make the specific decision and determined on the
|
||||
balance of probability that they do not have the capacity to make this decision at this
|
||||
time.</p></div>"""),
|
||||
_singleLineTextField(
|
||||
controller: controller.dontHaveDecisionNameController,
|
||||
heading: "Name",
|
||||
hintText: "Type here...",
|
||||
inputType: TextInputType.name,
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDontHaveDecisionDateTime(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dontHaveDecisionDateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p>I have assessed this person’s capacity to make the specific decision and
|
||||
determined that on the balance of probability that they have the capacity to make this decision
|
||||
at this time.</p></div>"""),
|
||||
_singleLineTextField(
|
||||
controller: controller.haveDecisionNameController,
|
||||
heading: "Name",
|
||||
hintText: "Type here...",
|
||||
inputType: TextInputType.name,
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectHaveDecisionDateTime(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.haveDecisionDateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
Html(
|
||||
data:
|
||||
"""<div class="col-md-12"><p><strong>Is an IMCA Required?</strong></p>
|
||||
<ul>
|
||||
<li>If the person (16+) is unbefriended and the decision is about a change of accommodation,
|
||||
or serious medical treatment, you MUST involve an IMCA.
|
||||
</li>
|
||||
<li>If a friend or family member exists, but they may not act in the person’s best interests
|
||||
(for example because they are the alleged victim or abuser in a Safeguarding Adults
|
||||
investigation) you MAY involve an IMCA.
|
||||
</li>
|
||||
<li>If the person is unbefriended and a health or social care review is being carried out,
|
||||
you MAY CONSIDER involving an IMCA as good practice.
|
||||
</li>
|
||||
<li>Although you may involve an IMCA under the Mental Capacity Act legislation, if there is
|
||||
no appropriate person, for people over age 18, you MUST instruct a Care Act Advocate if
|
||||
the person has substantial difficulty engaging with the relevant assessment &
|
||||
support planning/review/safeguarding process. Please use the most appropriate
|
||||
legislation to ensure entitlement to advocacy.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Does the individual require an IMCA?</p>
|
||||
</div>"""),
|
||||
_radioGroup(controller.selectedDoesRequireIMCAOption),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
controller: controller.requireIMCAController,
|
||||
heading: "If not, please give reasons.",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDateTimeOfWhyIMCARequired(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.whyIMCARequiredDateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date and time of assessment",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
Html(
|
||||
data: """<p><strong>Assessors Details.</strong></p>""",
|
||||
),
|
||||
10.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.assessorsName4Controller,
|
||||
heading: "Name",
|
||||
hintText: "Type here...",
|
||||
inputType: TextInputType.name,
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.designationController,
|
||||
heading: "Designation",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.baseAddressController,
|
||||
heading: "Base / Address",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
controller: controller.contactDetailsController,
|
||||
heading: "Contact Details",
|
||||
hintText: "Type here...",
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _multilineTextField(
|
||||
{required TextEditingController controller,
|
||||
required String heading,
|
||||
required String hintText}) {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller,
|
||||
heading: heading,
|
||||
hintText: hintText,
|
||||
onChange: (_) {},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _singleLineTextField(
|
||||
{required TextEditingController controller,
|
||||
required String heading,
|
||||
required String hintText,
|
||||
TextInputType inputType = TextInputType.text}) {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller,
|
||||
heading: heading,
|
||||
hintText: hintText,
|
||||
inputType: inputType,
|
||||
onChange: (_) {},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/ABC_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/consent_capacity_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/free_text_entries_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/health_appointments_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/injury_health_issue_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/observations_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/physical_intervention_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/safeguarding_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/showering_bath_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/toileting_note_form_screen.dart';
|
||||
export 'package:ftc_mobile_app/view/screens/clients/careNoteForms/weight_height_form_screen.dart';
|
||||
@@ -0,0 +1,139 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/free_text_entries_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class FreeTextEntriesFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const FreeTextEntriesFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<FreeTextEntriesFormScreen> createState() =>
|
||||
_FreeTextEntriesFormScreenState();
|
||||
}
|
||||
|
||||
class _FreeTextEntriesFormScreenState extends State<FreeTextEntriesFormScreen> {
|
||||
late final FreeTextEntriesFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(FreeTextEntriesFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () =>controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select date and time",
|
||||
heading: "Event Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.titleController,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
hintText: ConstantText.kTypeTitle,
|
||||
heading: ConstantText.kTitle,
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.noteDetailsController,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: ConstantText.kNoteDetails,
|
||||
hintText: ConstantText.kNoteDetailsHint,
|
||||
onChange: (_) {},
|
||||
),
|
||||
10.verticalSpace,
|
||||
SizedBox(
|
||||
height: 30.h,
|
||||
child: GestureDetector(
|
||||
onTap: controller.flagForHandover.toggle,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Obx(
|
||||
() => Ink(
|
||||
width: 32.r,
|
||||
height: 32.r,
|
||||
child: Checkbox(
|
||||
value: controller.flagForHandover.value,
|
||||
activeColor: CustomAppColors.kSecondaryColor,
|
||||
onChanged: (value) {
|
||||
controller.flagForHandover.value = value ?? false;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: ConstantText.kFlagForHandover,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/health_appointments_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class HealthAppointmentsFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const HealthAppointmentsFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<HealthAppointmentsFormScreen> createState() =>
|
||||
_HealthAppointmentsFormScreenState();
|
||||
}
|
||||
|
||||
class _HealthAppointmentsFormScreenState
|
||||
extends State<HealthAppointmentsFormScreen> {
|
||||
late final HealthAppointmentsFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(HealthAppointmentsFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Health Appointments note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
_appointmentWithDropdown,
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.reasonController,
|
||||
heading: "Reason for appointment",
|
||||
hintText: "Reason for appointment",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.commentsController,
|
||||
heading: "Comments",
|
||||
hintText: "Type comments here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _appointmentWithDropdown {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
width: 1.sp,
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 5.h,
|
||||
horizontal: 15.w,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Appointment With",
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
alignment: Alignment.centerLeft,
|
||||
),
|
||||
DropdownButtonHideUnderline(
|
||||
child: DropdownButtonFormField<String>(
|
||||
onTap: () {
|
||||
FocusScopeNode().unfocus();
|
||||
},
|
||||
dropdownColor: Colors.white,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
),
|
||||
hint: Text(
|
||||
"Appointment With",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
color: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
items: controller.appointmentWith
|
||||
.map(
|
||||
(e) => DropdownMenuItem<String>(
|
||||
value: e,
|
||||
child: Text(e),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
isExpanded: true,
|
||||
iconSize: 20.h,
|
||||
icon: Padding(
|
||||
padding: REdgeInsets.only(right: 4.0),
|
||||
child:
|
||||
const Icon(Icons.arrow_drop_down_sharp, color: Colors.grey),
|
||||
),
|
||||
onChanged: (category) {
|
||||
controller.selectedAppointmentWith = category;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/injury_health_issue_form_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/clients/category_subcategory_dropdowns_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class InjuryHealthIssueFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const InjuryHealthIssueFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<InjuryHealthIssueFormScreen> createState() =>
|
||||
_InjuryHealthIssueFormScreenState();
|
||||
}
|
||||
|
||||
class _InjuryHealthIssueFormScreenState
|
||||
extends State<InjuryHealthIssueFormScreen> {
|
||||
late final InjuryHealthIssueFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(InjuryHealthIssueFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Injury Health Issue note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () =>controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select date and time",
|
||||
heading: "Date and time of accident",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.nameOfWitnesses,
|
||||
heading: "Name of witnesses/adults present",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.placeOfAccident,
|
||||
heading: "Place accident occured",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.accidentDescription,
|
||||
heading: "Description how the accident occured",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.recordOfInjury,
|
||||
heading: "Record of any injury and action taken",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.conditionOfPatient,
|
||||
heading: "Condition of the patient following of the accident",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CategorySubcategoryDropdownsWidget(
|
||||
controller: controller.catSubCatController,
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "Parent Contacted",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
radioGroup(),
|
||||
Obx(() => controller.isParentContacted() == "Yes"
|
||||
? Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: widgetsIfParentContacted(),
|
||||
)
|
||||
: const SizedBox.shrink()),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> widgetsIfParentContacted() {
|
||||
return [
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.nameOfParentContacted,
|
||||
heading: "Name of parent contacted",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectParentContactTime(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.parentContactedTime,
|
||||
hintText: "Contact time",
|
||||
heading: "Contact time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "How parent was contacted",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
howParentContactedRadioGroup(),
|
||||
];
|
||||
}
|
||||
|
||||
Widget radioGroup() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Yes',
|
||||
selectedOption: controller.isParentContacted,
|
||||
),
|
||||
),
|
||||
16.horizontalSpace,
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'No',
|
||||
selectedOption: controller.isParentContacted,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget howParentContactedRadioGroup() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Call',
|
||||
selectedOption: controller.howParentContacted,
|
||||
),
|
||||
),
|
||||
16.horizontalSpace,
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Email',
|
||||
selectedOption: controller.howParentContacted,
|
||||
),
|
||||
),
|
||||
16.horizontalSpace,
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Text',
|
||||
selectedOption: controller.howParentContacted,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
110
lib/view/screens/clients/careNoteForms/mood_rating_form.dart
Normal file
110
lib/view/screens/clients/careNoteForms/mood_rating_form.dart
Normal file
@@ -0,0 +1,110 @@
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../../controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import '../../../../controllers/clients/careNoteFormControllers/mood_rating_form_controller.dart';
|
||||
|
||||
class MoodRatingFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const MoodRatingFormScreen({super.key, required this.args});
|
||||
|
||||
@override
|
||||
State<MoodRatingFormScreen> createState() => _MoodRatingFormScreenState();
|
||||
}
|
||||
|
||||
class _MoodRatingFormScreenState extends State<MoodRatingFormScreen> {
|
||||
late final MoodRatingFormController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(MoodRatingFormController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Mood Rating note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select date and time",
|
||||
heading: "Event Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
//...Other widgets
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: controller.ratings.length,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (_, index) {
|
||||
return Obx(() {
|
||||
return CheckboxListTile(
|
||||
value: controller.selectedRating() ==
|
||||
controller.ratings[index],
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
|
||||
secondary: Image.asset(
|
||||
controller.ratings[index].icon,
|
||||
width: 40.r,
|
||||
height: 40.r,
|
||||
),
|
||||
title: CustomTextWidget(
|
||||
text: controller.ratings[index].name,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
onChanged: (bool? value) {
|
||||
if (value == true) {
|
||||
controller.selectedRating.value =
|
||||
controller.ratings[index];
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
separatorBuilder: (_, index) => 10.verticalSpace,
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/nutrition_hydration_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class NutritionHydrationFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const NutritionHydrationFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<NutritionHydrationFormScreen> createState() =>
|
||||
_NutritionHydrationFormScreenState();
|
||||
}
|
||||
|
||||
class _NutritionHydrationFormScreenState
|
||||
extends State<NutritionHydrationFormScreen> {
|
||||
late final NutritionHydrationFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(NutritionHydrationFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Nutrition Hydration Note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select date and time",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
_radioGroup(controller.typeOptions, controller.selectedType),
|
||||
20.verticalSpace,
|
||||
Obx(() {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.mealDrinkTypeController,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
heading:
|
||||
(controller.selectedType() == NutritionHydrationType.food)
|
||||
? "Meal Type: (Breakfast, Lunch, Dinner, Snack etc)"
|
||||
: 'Drink Type',
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
);
|
||||
}),
|
||||
20.verticalSpace,
|
||||
Obx(() {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.amountController,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
heading:
|
||||
(controller.selectedType() == NutritionHydrationType.food)
|
||||
? "Amount Eaten"
|
||||
: "Amount (ML)",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
);
|
||||
}),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.commentsController,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
heading: "Comments",
|
||||
hintText: "Type comments here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _radioGroup(List<String> options, Rx<String?> selected) {
|
||||
options.map((e) => Flexible(
|
||||
child: RadioButton(
|
||||
value: e,
|
||||
selectedOption: selected,
|
||||
),
|
||||
));
|
||||
return Wrap(
|
||||
runAlignment: WrapAlignment.start,
|
||||
direction: Axis.horizontal,
|
||||
runSpacing: 8.r,
|
||||
spacing: 16.r,
|
||||
children: options
|
||||
.map((e) => RadioButton(
|
||||
value: e,
|
||||
selectedOption: selected,
|
||||
))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/observations_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class ObservationsFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const ObservationsFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ObservationsFormScreen> createState() => _ObservationsFormScreenState();
|
||||
}
|
||||
|
||||
class _ObservationsFormScreenState extends State<ObservationsFormScreen> {
|
||||
late final ObservationsFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(ObservationsFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Health Observations note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () =>controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
textEditingController: controller.heartRateController,
|
||||
hint: "Heart Rate (BPM)",
|
||||
heading: "Heart Rate (BPM)",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
textEditingController: controller.bloodPressureController,
|
||||
hint: "Blood Pressure (/MMHG)",
|
||||
heading: "Blood Pressure (/MMHG)",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
textEditingController: controller.respiratoryRateController,
|
||||
hint: "Respiratory Rate",
|
||||
heading: "Respiratory Rate",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
textEditingController: controller.oxygenController,
|
||||
hint: "Oxygen (%)",
|
||||
heading: "Oxygen (%)",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
textEditingController: controller.temperatureController,
|
||||
hint: "Temperature (°C)",
|
||||
heading: "Temperature (°C)",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_singleLineTextField(
|
||||
textEditingController: controller.bloodSugarController,
|
||||
hint: "Blood Sugar (MMOL/L)",
|
||||
heading: "Blood Sugar (MMOL/L)",
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _singleLineTextField(
|
||||
{required TextEditingController textEditingController,
|
||||
required String heading,
|
||||
required String hint}) {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
maxLength: 4,
|
||||
controller: textEditingController,
|
||||
heading: heading,
|
||||
hintText: hint,
|
||||
inputType: const TextInputType.numberWithOptions(),
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onChange: (_) {},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/physical_intervention_form_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/clients/category_subcategory_dropdowns_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class PhysicalInterventionFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const PhysicalInterventionFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<PhysicalInterventionFormScreen> createState() =>
|
||||
_PhysicalInterventionFormScreenState();
|
||||
}
|
||||
|
||||
class _PhysicalInterventionFormScreenState
|
||||
extends State<PhysicalInterventionFormScreen> {
|
||||
late final PhysicalInterventionFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(PhysicalInterventionFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Physical Intervention note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.durationOfIncidentController,
|
||||
heading: "Duration of incident (Mins)",
|
||||
hintText: "Type here...",
|
||||
inputType: const TextInputType.numberWithOptions(),
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.staffDebriefFormNumberController,
|
||||
heading: "Staff Debrief Form Number",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.nameOfWitnessController,
|
||||
heading: "Name of witnesses/adults present",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.incidentPlaceController,
|
||||
heading: "Place incident occured",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.whatWasUsedController,
|
||||
heading:
|
||||
"What was used prior to intervention to defuse/deescalae the situation?",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.wasThePbsFollowedController,
|
||||
heading:
|
||||
"Was the PBS followed and was it sufficient enough to manage this incident?",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.reasonForPhysicalInterventionController,
|
||||
heading: "Reason for physical intervention",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.staffInvolvedController,
|
||||
heading: "Staff involved in the physical intervention",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.conditionOfServiceUserController,
|
||||
heading:
|
||||
"Condition of service user following the incident, including breathing monitoring",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.userClamedController,
|
||||
heading: "How was the service user calmed?",
|
||||
hint: "Type here...",
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: "Why was the use of force necessary?",
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
12.verticalSpace,
|
||||
...List.generate(controller.whyForceNecessaryOptions.length,
|
||||
(index) {
|
||||
final e = controller.whyForceNecessaryOptions[index];
|
||||
return ObxValue((RxBool isChecked) {
|
||||
return CheckboxListTile(
|
||||
value: isChecked(),
|
||||
onChanged: isChecked,
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: CustomAppColors.kSmokeColor)),
|
||||
tileColor: (index % 2 == 0)
|
||||
? CustomAppColors.kSmokeColor
|
||||
: Colors.white,
|
||||
title: CustomTextWidget(
|
||||
text: e.requirements,
|
||||
isExpanded: false,
|
||||
fontSize: 13.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
);
|
||||
}, e.isChecked);
|
||||
}),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.explainController,
|
||||
heading: "If ticked \"Other\" please explain",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
CategorySubcategoryDropdownsWidget(
|
||||
controller: controller.catSubCatController,
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "Parent Contacted",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
_radioGroup(controller.isParentContactedOptions,
|
||||
controller.isParentContacted),
|
||||
Obx(() => controller.isParentContacted() == "Yes"
|
||||
? Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: widgetsIfParentContacted(),
|
||||
)
|
||||
: const SizedBox.shrink()),
|
||||
20.verticalSpace,
|
||||
_multilineTextField(
|
||||
textEditingController: controller.commentsController,
|
||||
heading: "Parent/carer's comments",
|
||||
hint: "Type here...",
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "How was this form shared with parents/carers?",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
_radioGroup(
|
||||
controller.howFormSharedOptions, controller.howFormSharedRx),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _multilineTextField(
|
||||
{required TextEditingController textEditingController,
|
||||
required String heading,
|
||||
required String hint}) {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: textEditingController,
|
||||
heading: heading,
|
||||
hintText: hint,
|
||||
onChange: (_) {},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> widgetsIfParentContacted() {
|
||||
return [
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.nameOfParentContacted,
|
||||
heading: "Name of parent contacted",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectParentContactTime(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.parentContactedTime,
|
||||
hintText: "Contact time",
|
||||
heading: "Contact time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "How parent was contacted",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
_radioGroup(
|
||||
controller.howParentContactedOptions, controller.howParentContacted),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _radioGroup(List<String> options, Rx<String?> selected) {
|
||||
options.map((e) => Flexible(
|
||||
child: RadioButton(
|
||||
value: e,
|
||||
selectedOption: selected,
|
||||
),
|
||||
));
|
||||
return Wrap(
|
||||
runAlignment: WrapAlignment.start,
|
||||
direction: Axis.horizontal,
|
||||
runSpacing: 8.r,
|
||||
spacing: 16.r,
|
||||
children: options
|
||||
.map((e) => RadioButton(
|
||||
value: e,
|
||||
selectedOption: selected,
|
||||
))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/safeguarding_form_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/clients/category_subcategory_dropdowns_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class SafeguardingFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const SafeguardingFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<SafeguardingFormScreen> createState() => _SafeguardingFormScreenState();
|
||||
}
|
||||
|
||||
class _SafeguardingFormScreenState extends State<SafeguardingFormScreen> {
|
||||
late final SafeguardingFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(SafeguardingFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Safeguarding note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select date and time",
|
||||
heading: "Date and time of disclosure/findings",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.concernAboutServiceUserController,
|
||||
heading: "Concerns about the service user",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.voiceOfServiceUserController,
|
||||
heading: "Voice of the service user",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.anyImmediateRisksController,
|
||||
heading: "Are there any immediate risks",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.qActionTakenController,
|
||||
heading: "What action do you feel should be taken?",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: controller.commentsController,
|
||||
heading: "Comments",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CategorySubcategoryDropdownsWidget(
|
||||
controller: controller.catSubCatController),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.nameController1,
|
||||
heading: "Your Name",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.anyWitnessesController,
|
||||
heading: "Any witnesses",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDateAndTimeOfReporting(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.reportingDateTimeController,
|
||||
hintText: "Select date and time",
|
||||
heading: "Date and time of reporting",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: "To be completed by DSL/DDSL",
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
12.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.nameController2,
|
||||
heading: "Your Name",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.actionTakenController,
|
||||
heading: "Action taken",
|
||||
hintText: "Type here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/showering_bath_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class ShoweringBathFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const ShoweringBathFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ShoweringBathFormScreen> createState() =>
|
||||
_ShoweringBathFormScreenState();
|
||||
}
|
||||
|
||||
class _ShoweringBathFormScreenState extends State<ShoweringBathFormScreen> {
|
||||
late final ShoweringBathFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(ShoweringBathFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add ShoweringBath note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () =>controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
radioGroup(),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.commentsController,
|
||||
heading: "Comments",
|
||||
hintText: "Type comments here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget radioGroup() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: RadioButton(
|
||||
value: 'Bath',
|
||||
selectedOption: controller.selectedOption,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: RadioButton(
|
||||
value: 'Shower',
|
||||
selectedOption: controller.selectedOption,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: RadioButton(
|
||||
value: 'Wash',
|
||||
selectedOption: controller.selectedOption,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// _selectDate() async {
|
||||
// Get.focusScope?.unfocus();
|
||||
// final date = await CommonCode.datePicker(context);
|
||||
//
|
||||
// if (date != null) {
|
||||
// controller.date = date;
|
||||
// controller.dateController.text =
|
||||
// CommonCode.careNoteDateFormatter.format(date);
|
||||
// }
|
||||
// }
|
||||
|
||||
// _selectTime() async {
|
||||
// TimeOfDay? timeOfDay = await CommonCode.selectTime(context,
|
||||
// selectedTime: TimeOfDay.now(),
|
||||
// themeColor: Get.theme.colorScheme.primary);
|
||||
//
|
||||
// if (timeOfDay != null) {
|
||||
// controller.timeController.text = timeOfDay.toString();
|
||||
// controller.time = timeOfDay;
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import '../../../../controllers/clients/careNoteFormControllers/toileting_note_form_screen_controller.dart';
|
||||
|
||||
class ToiletingNoteFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const ToiletingNoteFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ToiletingNoteFormScreen> createState() =>
|
||||
_ToiletingNoteFormScreenState();
|
||||
}
|
||||
|
||||
class _ToiletingNoteFormScreenState extends State<ToiletingNoteFormScreen> {
|
||||
late final ToiletingNoteFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(ToiletingNoteFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Toileting note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () =>controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
SizedBox(
|
||||
height: 30.h,
|
||||
child: GestureDetector(
|
||||
onTap: controller.assistanceRequired.toggle,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Obx(
|
||||
() => Ink(
|
||||
width: 32.r,
|
||||
height: 32.r,
|
||||
child: Checkbox(
|
||||
value: controller.assistanceRequired.value,
|
||||
activeColor: CustomAppColors.kSecondaryColor,
|
||||
onChanged: (value) {
|
||||
controller.assistanceRequired.value =
|
||||
value ?? false;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Was assistance required with toileting?",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.only(left: 8.0),
|
||||
child: CustomTextWidget(
|
||||
text: "If yes, what assistance?",
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: Colors.black,
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
radioGroup(),
|
||||
20.verticalSpace,
|
||||
Obx(() {
|
||||
return CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
isEnabled: controller.assistanceRequired(),
|
||||
controller: controller.commentsController,
|
||||
heading: "Comments",
|
||||
hintText: "Type comments here...",
|
||||
onChange: (_) {},
|
||||
);
|
||||
}),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget radioGroup() {
|
||||
return Obx(() {
|
||||
return IgnorePointer(
|
||||
ignoring: controller.assistanceRequired.isFalse,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Bowel',
|
||||
selectedOption: controller.selectedOption,
|
||||
isEnabled: controller.assistanceRequired(),
|
||||
),
|
||||
),
|
||||
16.horizontalSpace,
|
||||
Flexible(
|
||||
child: RadioButton(
|
||||
value: 'Urine',
|
||||
selectedOption: controller.selectedOption,
|
||||
isEnabled: controller.assistanceRequired(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/weight_height_form_screen_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
|
||||
class WeightHeightFormScreen extends StatefulWidget {
|
||||
final CommonCareNoteFormArgs args;
|
||||
|
||||
const WeightHeightFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<WeightHeightFormScreen> createState() => _WeightHeightFormScreenState();
|
||||
}
|
||||
|
||||
class _WeightHeightFormScreenState extends State<WeightHeightFormScreen> {
|
||||
late final WeightHeightFormScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(WeightHeightFormScreenController(args: widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Add Weight/Height note',
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () => controller.selectDate(context),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.dateController,
|
||||
hintText: "Select...",
|
||||
heading: "Date / Time",
|
||||
isEnabled: false,
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
maxLength: 3,
|
||||
controller: controller.heightController,
|
||||
hintText: "Height (CM)",
|
||||
heading: "Height (CM)",
|
||||
inputType: const TextInputType.numberWithOptions(),
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
16.horizontalSpace,
|
||||
Expanded(
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
maxLength: 3,
|
||||
controller: controller.weightController,
|
||||
hintText: 'Weight (KG)',
|
||||
heading: 'Weight (KG',
|
||||
inputType: const TextInputType.numberWithOptions(),
|
||||
onChange: (_) {},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 6,
|
||||
maxLines: 6,
|
||||
controller: controller.commentsController,
|
||||
heading: "Comments",
|
||||
hintText: "Type comments here...",
|
||||
onChange: (_) {},
|
||||
),
|
||||
32.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: ConstantText.kSave,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: controller.onSaveButtonTap,
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
191
lib/view/screens/clients/care_note_detail_screen.dart
Normal file
191
lib/view/screens/clients/care_note_detail_screen.dart
Normal file
@@ -0,0 +1,191 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/utilities/enums/body_parts.dart';
|
||||
import 'package:ftc_mobile_app/utilities/enums/care_note_form_type.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import '../../../controllers/clients/care_note_detail_screen_controller.dart';
|
||||
import '../../../models/clients/allCareNotes/CarePlans.dart';
|
||||
import '../../custom_widgets/human_body_mapper_widget.dart';
|
||||
|
||||
class CareNoteDetailScreen extends StatefulWidget {
|
||||
final CarePlan data;
|
||||
|
||||
const CareNoteDetailScreen({super.key, required this.data});
|
||||
|
||||
static const meta =
|
||||
"""<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
""";
|
||||
|
||||
static const css = """<style>
|
||||
strong {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
p, small {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
border-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
td {padding: 10px;}
|
||||
tr:nth-child(odd) {
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: rgba(255,255,255,1);
|
||||
}
|
||||
</style>
|
||||
""";
|
||||
|
||||
@override
|
||||
State<CareNoteDetailScreen> createState() => _CareNoteDetailScreenState();
|
||||
}
|
||||
|
||||
class _CareNoteDetailScreenState extends State<CareNoteDetailScreen> {
|
||||
late final CareNoteDetailScreenController controller;
|
||||
|
||||
final commonHtmlStyle = {
|
||||
"strong": Style(
|
||||
display: Display.block,
|
||||
fontSize: FontSize(16),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
"p, small": Style(
|
||||
display: Display.block,
|
||||
fontSize: FontSize(14),
|
||||
),
|
||||
};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = Get.put(CareNoteDetailScreenController(widget.data));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (kDebugMode) {
|
||||
log("CarePlan data: ${jsonEncode(widget.data.toJson())}");
|
||||
}
|
||||
|
||||
final isMoodRatingForm =
|
||||
widget.data.noteType == CareNotesFormType.moodRatingForm.apiValue;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: const CustomTextWidget(
|
||||
text: 'View Care Note',
|
||||
fontColor: Colors.white,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
centerTitle: false,
|
||||
actions: const [
|
||||
CloseButton(color: Colors.white),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: (widget.data.isHTML == true)
|
||||
? Obx(() {
|
||||
return (controller.isLoadingWebPage())
|
||||
? Center(
|
||||
child: SizedBox.square(
|
||||
dimension: 48.r,
|
||||
child: const CircularProgressIndicator()),
|
||||
)
|
||||
: ListView(
|
||||
children: [
|
||||
Obx(() {
|
||||
return SizedBox(
|
||||
height: controller.webViewHeight(),
|
||||
child: WebViewWidget(
|
||||
controller: controller.webViewController),
|
||||
);
|
||||
}),
|
||||
// Flexible(child: WebViewWidget(controller: controller)),
|
||||
bodyPoints(),
|
||||
],
|
||||
);
|
||||
})
|
||||
: ListView(
|
||||
children: [
|
||||
Html(
|
||||
data: controller.headerHtml,
|
||||
style: {
|
||||
"strong": Style(
|
||||
display: Display.block,
|
||||
fontSize: FontSize(16),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
},
|
||||
),
|
||||
Html(
|
||||
data: (widget.data.isHTML == true)
|
||||
? widget.data.noteDetails
|
||||
: """<p>
|
||||
<strong>Title</strong>
|
||||
<small>${widget.data.title ?? ""}</small>
|
||||
</p>
|
||||
${(!isMoodRatingForm && widget.data.noteDetails.isNotNullOrEmpty()) ? "<p><small>${widget.data.noteDetails!}</small></p>" : ''}
|
||||
${(!isMoodRatingForm && widget.data.flag == true) ? """<p style="color:green;font-size:14px;">Handover Review</p>""" : ''}
|
||||
""",
|
||||
shrinkWrap: true,
|
||||
style: commonHtmlStyle,
|
||||
),
|
||||
(widget.data.healthIssueId?.category == null)
|
||||
? FrequentFunctions.noWidget
|
||||
: Html(
|
||||
data: """<p>
|
||||
<strong>Effected Body Part</strong>
|
||||
<small>${widget.data.healthIssueId!.category!.name}</small>
|
||||
</p>""",
|
||||
style: commonHtmlStyle,
|
||||
),
|
||||
bodyPoints().paddingOnly(top: 20.r),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget bodyPoints() {
|
||||
if (widget.data.healthIssueId?.category == null) {
|
||||
return FrequentFunctions.noWidget;
|
||||
}
|
||||
|
||||
final Map<BodyPart, Color?> map = {};
|
||||
|
||||
BodyPart.values
|
||||
.where((e) => e.apiValue == widget.data.healthIssueId!.category!.enumed)
|
||||
.forEach((e) {
|
||||
map[e] = Colors.red;
|
||||
});
|
||||
|
||||
return HumanBodyWidget(
|
||||
width: Get.width * 0.8,
|
||||
visibleBodyPoints: map,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<CareNoteDetailScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
142
lib/view/screens/clients/care_notes_screen.dart
Normal file
142
lib/view/screens/clients/care_notes_screen.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/care_note_category.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/clients/CareNoteOptionCard.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'all_care_notes_screen.dart';
|
||||
|
||||
class CareNotesScreenArgs {
|
||||
final String serviceUserId;
|
||||
|
||||
CareNotesScreenArgs({required this.serviceUserId});
|
||||
}
|
||||
|
||||
class CareNotesScreen extends StatefulWidget {
|
||||
final CareNotesScreenArgs args;
|
||||
|
||||
const CareNotesScreen({super.key, required this.args});
|
||||
|
||||
@override
|
||||
State<CareNotesScreen> createState() => _CareNotesScreenState();
|
||||
}
|
||||
|
||||
class _CareNotesScreenState extends State<CareNotesScreen> {
|
||||
final CareNotesScreenController controller =
|
||||
Get.put(CareNotesScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => controller.backButtonPressed(context),
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Care Notes',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 18),
|
||||
child: ListView(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context,
|
||||
CustomRouteNames.kAllCareNotesScreenRoute,
|
||||
arguments: AllCareNotesScreenArgs(
|
||||
serviceUserId: widget.args.serviceUserId));
|
||||
},
|
||||
child: const CareNoteOptionCard(
|
||||
icon: AssetsManager.kIcGeneral,
|
||||
name: "All Care Notes",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Expanded(child: SizedBox.shrink()),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
isExpanded: false,
|
||||
text: "Common Options",
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700),
|
||||
10.verticalSpace,
|
||||
_categoriesList(),
|
||||
// Flexible(child: ),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _categoriesList() {
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2, mainAxisSpacing: 6.r, crossAxisSpacing: 6.r),
|
||||
itemCount: controller.categories.length,
|
||||
itemBuilder: (_, index) {
|
||||
return InkWell(
|
||||
onTap: () => _onCategoryCardTap(controller.categories[index]),
|
||||
child: CareNoteOptionCard(
|
||||
icon: controller.categories[index].iconPath ?? "",
|
||||
name: controller.categories[index].category ?? "",
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// ---------Methods-----------
|
||||
void _onCategoryCardTap(CareNoteCategory category) {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kCareNotesSubcategoriesScreenRoute,
|
||||
arguments: CareNotesSubcategoriesScreenArgs(
|
||||
serviceUserId: widget.args.serviceUserId,
|
||||
category: category,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
235
lib/view/screens/clients/care_notes_subcategories_screen.dart
Normal file
235
lib/view/screens/clients/care_notes_subcategories_screen.dart
Normal file
@@ -0,0 +1,235 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/careNoteFormControllers/common_care_note_forms_controller.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/utilities/enums/care_note_form_type.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../controllers/clients/care_notes_subcategories_screen_controller.dart';
|
||||
import '../../../models/clients/care_note_category.dart';
|
||||
|
||||
class CareNotesSubcategoriesScreenArgs {
|
||||
final String serviceUserId;
|
||||
final CareNoteCategory category;
|
||||
|
||||
CareNotesSubcategoriesScreenArgs(
|
||||
{required this.serviceUserId, required this.category});
|
||||
}
|
||||
|
||||
class CareNotesSubcategoriesScreen extends StatefulWidget {
|
||||
final CareNotesSubcategoriesScreenArgs args;
|
||||
|
||||
const CareNotesSubcategoriesScreen({super.key, required this.args});
|
||||
|
||||
@override
|
||||
State<CareNotesSubcategoriesScreen> createState() =>
|
||||
_CareNotesSubcategoriesScreenState();
|
||||
}
|
||||
|
||||
class _CareNotesSubcategoriesScreenState
|
||||
extends State<CareNotesSubcategoriesScreen> {
|
||||
final CareNotesSubcategoriesScreenController controller =
|
||||
Get.put(CareNotesSubcategoriesScreenController());
|
||||
|
||||
List<Subcategories> get _subcategories =>
|
||||
widget.args.category.subcategories ?? [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: widget.args.category.category ?? "",
|
||||
),
|
||||
// appBar: CustomAppBar(
|
||||
// leadingButton: Container(),
|
||||
// showBoxShadow: false,
|
||||
// titleWidget: Row(
|
||||
// children: [
|
||||
// InkWell(
|
||||
// onTap: () => controller.backButtonPressed(context),
|
||||
// child: CustomImageWidget(
|
||||
// imagePath: AssetsManager.kBackIcon,
|
||||
// height: 11.53.h,
|
||||
// width: 8.66.w,
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: 15.w,
|
||||
// ),
|
||||
// CustomTextWidget(
|
||||
// text: widget.args.category.category ?? "",
|
||||
// isExpanded: false,
|
||||
// fontSize: 16.sp,
|
||||
// fontWeight: FontWeight.w700,
|
||||
// fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
body: Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 18),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
10.verticalSpace,
|
||||
Expanded(child: _categoriesList()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _categoriesList() {
|
||||
return GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2, mainAxisSpacing: 6.r, crossAxisSpacing: 6.r),
|
||||
itemCount: _subcategories.length,
|
||||
itemBuilder: (_, index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
_onSubcategoryCardTap(_subcategories[index]);
|
||||
},
|
||||
child: Card(
|
||||
elevation: 2,
|
||||
shadowColor: CustomAppColors.kLightGreyColor,
|
||||
surfaceTintColor: Colors.white,
|
||||
color: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4).r),
|
||||
child: Padding(
|
||||
padding: REdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: _subcategories[index].iconPath ?? "",
|
||||
height: 24.r,
|
||||
width: 24.r,
|
||||
),
|
||||
12.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: _subcategories[index].name ?? "",
|
||||
alignment: Alignment.center,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
fontSize: 14.sp)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _onSubcategoryCardTap(Subcategories subcategory) {
|
||||
final args = CommonCareNoteFormArgs(
|
||||
serviceUserId: widget.args.serviceUserId,
|
||||
noteType: subcategory.apiValue!);
|
||||
switch (CareNotesFormType.fromText(subcategory.formType ?? "")) {
|
||||
case CareNotesFormType.injuryHealthIssueForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kInjuryHealthIssueFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.weightHeightForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kWeightHeightFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.healthAppointmentForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kHealthAppointmentsFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.observationsForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kObservationsFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.safeguardingForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kSafeguardingFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.showeringBathForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kShoweringBathFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.toiletingNoteForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kToiletingNoteFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.moodRatingForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kMoodRatingFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.ABCForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kABCFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.physicalInterventionForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kPhysicalInterventionFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.consentCapacityForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kConsentCapacityFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
case CareNotesFormType.nutritionHydrationForm:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kNutritionHydrationFormScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kFreeTextEntriesScreenRoute,
|
||||
arguments: args,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
227
lib/view/screens/clients/care_plan_menu_screen.dart
Normal file
227
lib/view/screens/clients/care_plan_menu_screen.dart
Normal file
@@ -0,0 +1,227 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import '../../../models/profileData/user_data.dart';
|
||||
import '../../custom_widgets/my_circle_image.dart';
|
||||
|
||||
class CarePlanMenuScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const CarePlanMenuScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<CarePlanMenuScreen> createState() => _CarePlanMenuScreenState();
|
||||
}
|
||||
|
||||
class _CarePlanMenuScreenState extends State<CarePlanMenuScreen> {
|
||||
late final CarePlanMenuScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(CarePlanMenuScreenController(data: widget.userData));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: "Care Plan Menu",
|
||||
),
|
||||
body: Obx(() {
|
||||
if (controller.serviceUser() == null) {
|
||||
return FrequentFunctions.centerText(text: "User detail not found");
|
||||
}
|
||||
|
||||
final detail = controller.serviceUser()!;
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
UnconstrainedBox(
|
||||
child: MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url: "${WebUrls.baseUrl}${detail.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 80.r,
|
||||
width: 80.r,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
CustomTextWidget(
|
||||
text: detail.displayName,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
16.verticalSpace,
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20.w),
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
isExpanded: false,
|
||||
text: "Care Plans",
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
// 5.verticalSpace,
|
||||
// const LineWidget(
|
||||
// text: "Key Contacts",
|
||||
// ),
|
||||
5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "Care Notes",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
controller.screenKey.currentContext!,
|
||||
CustomRouteNames.kCareNotesScreenRoute,
|
||||
arguments: CareNotesScreenArgs(
|
||||
serviceUserId: controller.serviceUser()!.id!),
|
||||
);
|
||||
},
|
||||
),
|
||||
5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "Risk Assesments",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kRiskAssessmentsTemplateScreenRoute,
|
||||
arguments: controller.serviceUser(),
|
||||
);
|
||||
}),
|
||||
5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "Consent and capacity",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames
|
||||
.kConsentAndCapacityQuestionnaireScreenRoute,
|
||||
arguments: controller.serviceUser()!,
|
||||
);
|
||||
}),
|
||||
5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "Current Health Issues",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kCurrentHealthIssuesScreenRoute,
|
||||
arguments: controller.serviceUser()!,
|
||||
);
|
||||
}),
|
||||
5.verticalSpace,
|
||||
// LineWidget(
|
||||
// text: "Life History & Goals",
|
||||
// onItemTap: () {
|
||||
// Navigator.pushNamed(
|
||||
// context,
|
||||
// CustomRouteNames.kLifeHistoryAndGoalsScreenRoute,
|
||||
// arguments: controller.serviceUser.value,
|
||||
// );
|
||||
// }),
|
||||
// 5.verticalSpace,
|
||||
// LineWidget(
|
||||
// text: "Support Plan",
|
||||
// onItemTap: () {
|
||||
// Navigator.pushNamed(
|
||||
// context,
|
||||
// CustomRouteNames.kSupportPlanScreenRoute,
|
||||
// arguments: controller.serviceUser.value,
|
||||
// );
|
||||
// }),
|
||||
// 5.verticalSpace,
|
||||
// const LineWidget(
|
||||
// text: "Medication Profile",
|
||||
// ),
|
||||
// 5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "PBS Plan",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kPBSPlanScreenRoute,
|
||||
arguments: controller.serviceUser.value,
|
||||
);
|
||||
}),
|
||||
5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "Recent Incidents",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
context, CustomRouteNames.kRecentIncidentsScreenRoute,
|
||||
arguments: controller.serviceUser.value);
|
||||
}),
|
||||
5.verticalSpace,
|
||||
LineWidget(
|
||||
text: "Documents",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kDocumentsListScreenRoute,
|
||||
arguments: controller.serviceUser.value,
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class LineWidget extends StatelessWidget {
|
||||
const LineWidget({
|
||||
super.key,
|
||||
required this.text,
|
||||
this.onItemTap,
|
||||
});
|
||||
|
||||
final Function? onItemTap;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (onItemTap != null) {
|
||||
onItemTap!();
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 15.w, vertical: 2.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.r, vertical: 12.r),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor)),
|
||||
child: Row(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: text,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16.sp),
|
||||
const Spacer(),
|
||||
Icon(
|
||||
Icons.keyboard_arrow_right_rounded,
|
||||
color: CustomAppColors.kSecondaryColor,
|
||||
size: 18.r,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
321
lib/view/screens/clients/client_profile_screen.dart
Normal file
321
lib/view/screens/clients/client_profile_screen.dart
Normal file
@@ -0,0 +1,321 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../models/profileData/user_data.dart';
|
||||
import 'all_care_notes_screen.dart';
|
||||
|
||||
class ClientProfileScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const ClientProfileScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ClientProfileScreen> createState() => _ClientProfileScreenState();
|
||||
}
|
||||
|
||||
class _ClientProfileScreenState extends State<ClientProfileScreen> {
|
||||
late final ClientProfileScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(ClientProfileScreenController(data: widget.userData));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => controller.backButtonPressed(context),
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Client: ${controller.serviceUser()?.displayName ?? ""}',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Obx(() {
|
||||
if (controller.serviceUser() == null) {
|
||||
return FrequentFunctions.centerText(text: "User detail not found");
|
||||
}
|
||||
|
||||
final detail = controller.serviceUser()!;
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(height: 16.h),
|
||||
MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url: "${WebUrls.baseUrl}${detail.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 53.h,
|
||||
width: 53.w,
|
||||
),
|
||||
),
|
||||
16.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: detail.displayName,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
16.verticalSpace,
|
||||
BuildDetailRow(
|
||||
title: 'Contact Number',
|
||||
value: detail.modelId?.phoneNo ?? "",
|
||||
),
|
||||
BuildDetailRow(
|
||||
title: 'Home Address',
|
||||
value: detail.modelId?.homeAddress ?? ""),
|
||||
BuildDetailRow(
|
||||
title: 'Next of Kin',
|
||||
value: detail.modelId?.suFamilyHead ?? ""),
|
||||
const BuildDetailRow(title: 'Diagnosis History', value: ''),
|
||||
BuildRoundOutlinedBox(
|
||||
context: context,
|
||||
child: BuildDiagnosisHistoryList(
|
||||
history:
|
||||
(detail.modelId?.diagnosises.isNotNullOrEmpty() == true)
|
||||
? detail.modelId!.diagnosises.first.diagnosisText
|
||||
: "",
|
||||
date: (detail.modelId?.aboutPatient.aboutDate
|
||||
.isNotNullOrEmpty() ==
|
||||
true)
|
||||
? DateFormatter().getAppointmentTime(
|
||||
detail.modelId!.aboutPatient.aboutDate)
|
||||
: "",
|
||||
),
|
||||
),
|
||||
const BuildDetailRow(title: 'About the Patient', value: ''),
|
||||
BuildRoundOutlinedBox(
|
||||
context: context,
|
||||
child: BuildDiagnosisHistoryList(
|
||||
history: detail.modelId?.aboutPatient.aboutText ?? "",
|
||||
date: (detail.modelId?.aboutPatient.aboutDate
|
||||
.isNotNullOrEmpty() ==
|
||||
true)
|
||||
? DateFormatter().getAppointmentTime(
|
||||
detail.modelId!.aboutPatient.aboutDate)
|
||||
: "",
|
||||
),
|
||||
),
|
||||
16.verticalSpace,
|
||||
BuildIconButton(
|
||||
iconPath: AssetsManager.kNotesIcon,
|
||||
text: 'Notes',
|
||||
route: CustomRouteNames.kAllCareNotesScreenRoute,
|
||||
arguments: AllCareNotesScreenArgs(
|
||||
serviceUserId: controller.serviceUser()!.id!),
|
||||
),
|
||||
BuildIconButton(
|
||||
iconPath: AssetsManager.kCarePlanIcon,
|
||||
text: 'Care Plan',
|
||||
route: CustomRouteNames.kCarePlanMenuScreenRoute,
|
||||
arguments: controller.serviceUser()!,
|
||||
),
|
||||
BuildIconButton(
|
||||
iconPath: AssetsManager.kCalendarAppointmentIcon,
|
||||
text: 'Appointments',
|
||||
route: CustomRouteNames.kAppointmentsScreenRoute,
|
||||
arguments: controller.serviceUser()!,
|
||||
),
|
||||
BuildIconButton(
|
||||
iconPath: AssetsManager.kPhotoGalleryIcon,
|
||||
text: 'Photo Gallery',
|
||||
route: CustomRouteNames.kPhotoGalleryScreenRoute,
|
||||
arguments: controller.serviceUser()!,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildIconButton extends StatelessWidget {
|
||||
const BuildIconButton({
|
||||
super.key,
|
||||
required this.iconPath,
|
||||
required this.text,
|
||||
required this.route,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
final String iconPath;
|
||||
final String text;
|
||||
final String route;
|
||||
final dynamic arguments;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
if (route.isNotEmpty) {
|
||||
Navigator.pushNamed(context, route, arguments: arguments);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 25.w),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.r, vertical: 8.r),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor.withOpacity(0.5))),
|
||||
child: Row(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: iconPath,
|
||||
height: 20.r,
|
||||
width: 20.r,
|
||||
),
|
||||
12.horizontalSpace,
|
||||
CustomTextWidget(
|
||||
text: text,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
fontSize: 14.sp),
|
||||
const Spacer(),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios_rounded,
|
||||
size: 12.sp,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildDiagnosisHistoryList extends StatelessWidget {
|
||||
const BuildDiagnosisHistoryList({
|
||||
super.key,
|
||||
required this.date,
|
||||
required this.history,
|
||||
});
|
||||
|
||||
final String date;
|
||||
final String history;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: date,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: history,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildRoundOutlinedBox extends StatelessWidget {
|
||||
const BuildRoundOutlinedBox({
|
||||
super.key,
|
||||
required this.context,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final BuildContext context;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
margin: EdgeInsets.symmetric(horizontal: 22.r),
|
||||
padding: EdgeInsets.all(10.sp),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kLightGreyColor),
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildDetailRow extends StatelessWidget {
|
||||
const BuildDetailRow({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 20.w),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: CustomTextWidget(
|
||||
isExpanded: false,
|
||||
text: '$title: ',
|
||||
fontWeight: FontWeight.w600,
|
||||
textAlign: TextAlign.left,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: CustomTextWidget(
|
||||
text: value,
|
||||
isExpanded: false,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.right,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
fontSize: 14.sp),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/new_client_module_controllers/add_new_pbs_plan_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/PBSPlanModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:quill_html_editor/quill_html_editor.dart';
|
||||
|
||||
class AddNewPBSPlanScreenArgs {
|
||||
final UserData userData;
|
||||
final PbsList? pbsData;
|
||||
final bool viewOnly;
|
||||
|
||||
AddNewPBSPlanScreenArgs({
|
||||
required this.userData,
|
||||
this.pbsData,
|
||||
this.viewOnly = false,
|
||||
});
|
||||
}
|
||||
|
||||
class AddNewPBSPlanScreen extends StatefulWidget {
|
||||
final AddNewPBSPlanScreenArgs args;
|
||||
|
||||
const AddNewPBSPlanScreen({Key? key, required this.args}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AddNewPBSPlanScreen> createState() => _AddNewPBSPlanScreenState();
|
||||
}
|
||||
|
||||
class _AddNewPBSPlanScreenState extends State<AddNewPBSPlanScreen> {
|
||||
late final AddNewPbsPlanScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(AddNewPbsPlanScreenController(widget.args));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context, null),
|
||||
screenKey: controller.screenKey,
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.backButtonPressed(context, null);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: (widget.args.viewOnly)
|
||||
? "View PBS Plan"
|
||||
: widget.args.pbsData == null
|
||||
? 'Add New PBS Plan'
|
||||
: 'Update PBS Plan',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Obx(
|
||||
() => Column(
|
||||
children: [
|
||||
//About Plan
|
||||
SeparateQuillEditorForFields(
|
||||
headingText: 'About Plan',
|
||||
headingBackGroundColor:
|
||||
CustomAppColors.kLightGreyColor.withAlpha(150),
|
||||
headingTextColor: CustomAppColors.kBlackColor,
|
||||
// noteHintText: "About Plan hint",
|
||||
noteText: controller.addPbsPlanModel.value.aboutPlan,
|
||||
quillEditorController: controller
|
||||
.addPbsPlanModel.value.aboutPlanQuillController,
|
||||
viewOnly: (widget.args.viewOnly),
|
||||
),
|
||||
Divider(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
|
||||
//Management of behavioural presentation
|
||||
10.verticalSpace,
|
||||
SeparateQuillEditorForFields(
|
||||
headingText: 'Management of behavioural presentation',
|
||||
headingBackGroundColor: CustomAppColors.kDarkestGreenColor,
|
||||
// noteHintText: "Management of behavioural presentation hint",
|
||||
noteText:
|
||||
controller.addPbsPlanModel().managementOfBehaviorPlan,
|
||||
quillEditorController: controller.addPbsPlanModel.value
|
||||
.managementOfBehaviouralPresentationQuillController,
|
||||
viewOnly: (widget.args.viewOnly),
|
||||
),
|
||||
Divider(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
|
||||
//Secondary Prevention
|
||||
10.verticalSpace,
|
||||
SeparateQuillEditorForFields(
|
||||
headingText: 'Secondary Prevention',
|
||||
headingBackGroundColor: CustomAppColors.kDarkYellowColor,
|
||||
// noteHintText: "Secondary Prevention hint",
|
||||
noteText:
|
||||
controller.addPbsPlanModel.value.secondaryPrevention,
|
||||
quillEditorController: controller.addPbsPlanModel.value
|
||||
.secondaryPreventionQuillController,
|
||||
viewOnly: (widget.args.viewOnly),
|
||||
),
|
||||
Divider(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
|
||||
//Reactive Strategies
|
||||
10.verticalSpace,
|
||||
SeparateQuillEditorForFields(
|
||||
headingText: 'Reactive Strategies',
|
||||
headingBackGroundColor: CustomAppColors.kDarkRedColor,
|
||||
// noteHintText: "Reactive Strategies hint",
|
||||
noteText:
|
||||
controller.addPbsPlanModel.value.reactiveStrategies,
|
||||
quillEditorController: controller.addPbsPlanModel.value
|
||||
.reactiveStrategiesQuillController,
|
||||
viewOnly: (widget.args.viewOnly),
|
||||
),
|
||||
Divider(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
|
||||
//Post Incident Support- Recovery
|
||||
10.verticalSpace,
|
||||
SeparateQuillEditorForFields(
|
||||
headingText: 'Post Incident Support- Recovery',
|
||||
headingBackGroundColor: const Color(0xff3c78d8),
|
||||
// noteHintText: "Post Incident Support- Recovery hint",
|
||||
noteText:
|
||||
controller.addPbsPlanModel.value.postIncidentSupport,
|
||||
quillEditorController: controller.addPbsPlanModel.value
|
||||
.postIncidentSupportRecoveryQuillController,
|
||||
viewOnly: (widget.args.viewOnly),
|
||||
),
|
||||
|
||||
//Submit Button
|
||||
(widget.args.viewOnly)
|
||||
? FrequentFunctions.noWidget
|
||||
: Obx(
|
||||
() => CustomAppButton(
|
||||
buttonText: widget.args.pbsData == null
|
||||
? "Submit"
|
||||
: "Update",
|
||||
buttonColor: controller.enableSubmitButton.isTrue
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: CustomAppColors.kLightGreyColor,
|
||||
borderColor: controller.enableSubmitButton.isTrue
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: CustomAppColors.kLightGreyColor,
|
||||
onTap: () {
|
||||
if (controller.enableSubmitButton.isTrue) {
|
||||
controller.submitButtonPressed();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SeparateQuillEditorForFields extends StatefulWidget {
|
||||
const SeparateQuillEditorForFields({
|
||||
super.key,
|
||||
required this.headingText,
|
||||
this.headingTextColor = CustomAppColors.kWhiteColor,
|
||||
required this.headingBackGroundColor,
|
||||
this.headingBorderColor = CustomAppColors.kLightTextColor,
|
||||
required this.noteText,
|
||||
required this.quillEditorController,
|
||||
// required this.noteHintText,
|
||||
required this.viewOnly,
|
||||
});
|
||||
|
||||
final String headingText;
|
||||
final Color headingTextColor;
|
||||
final Color headingBackGroundColor;
|
||||
final Color headingBorderColor;
|
||||
final String noteText;
|
||||
|
||||
// final String noteHintText;
|
||||
final bool viewOnly;
|
||||
final QuillEditorController quillEditorController;
|
||||
|
||||
@override
|
||||
State<SeparateQuillEditorForFields> createState() =>
|
||||
_SeparateQuillEditorForFieldsState();
|
||||
}
|
||||
|
||||
class _SeparateQuillEditorForFieldsState
|
||||
extends State<SeparateQuillEditorForFields> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: widget.headingBackGroundColor,
|
||||
border: Border.all(color: widget.headingBorderColor)),
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: CustomTextWidget(
|
||||
text: widget.headingText,
|
||||
fontColor: widget.headingTextColor,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
(widget.viewOnly)
|
||||
? FrequentFunctions.noWidget
|
||||
: ToolBar(
|
||||
toolBarColor: Colors.cyan.shade50,
|
||||
activeIconColor: Colors.green,
|
||||
padding: const EdgeInsets.all(8),
|
||||
iconSize: 20,
|
||||
controller: widget.quillEditorController,
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(bottom: 10.h),
|
||||
child: QuillHtmlEditor(
|
||||
hintText: "Type here...",
|
||||
controller: widget.quillEditorController,
|
||||
isEnabled: !widget.viewOnly,
|
||||
minHeight: 250,
|
||||
text: widget.noteText,
|
||||
hintTextAlign: TextAlign.start,
|
||||
hintTextStyle: TextStyle(fontSize: 14.sp, color: Colors.black54),
|
||||
padding: const EdgeInsets.only(left: 10, top: 5, right: 5),
|
||||
hintTextPadding: const EdgeInsets.only(left: 10, top: 5, right: 5),
|
||||
backgroundColor: widget.headingBackGroundColor.withAlpha(25),
|
||||
onFocusChanged: (hasFocus) {
|
||||
// if (hasFocus && FocusScope.of(context).hasFocus) {
|
||||
// controller.removeFocus();
|
||||
// }
|
||||
},
|
||||
onTextChanged: (text) {
|
||||
// controller.enableDisableSubmitButton();
|
||||
},
|
||||
// onEditorCreated: () => debugPrint('Editor has been loaded'),
|
||||
onEditingComplete: (s) {
|
||||
// controller.enableDisableSubmitButton();
|
||||
},
|
||||
onEditorResized: (height) => debugPrint('Editor resized $height'),
|
||||
onSelectionChanged: (sel) =>
|
||||
debugPrint('${sel.index},${sel.length}'),
|
||||
loadingBuilder: (context) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 0.4,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Get.delete<AddNewPbsPlanScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class CrisisManagementScreen extends StatefulWidget {
|
||||
const CrisisManagementScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<CrisisManagementScreen> createState() => _CrisisManagementScreenState();
|
||||
}
|
||||
|
||||
class _CrisisManagementScreenState extends State<CrisisManagementScreen> {
|
||||
final CrisisManagementScreenController controller =
|
||||
Get.put(CrisisManagementScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Crisis management',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "What crisis looks like to me",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "How can I effectively be supported?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export 'crisis_management_screen.dart';
|
||||
export 'future_plans_screen.dart';
|
||||
export 'health_full_body_map_screen.dart';
|
||||
export 'health_screen.dart';
|
||||
export 'introduction_screen.dart';
|
||||
export 'medication_screen.dart';
|
||||
export 'my_current_plan_screen.dart';
|
||||
export 'mental_health_screen.dart';
|
||||
export 'my_interests_screen.dart';
|
||||
export 'support_plan_screen.dart';
|
||||
export 'overview_screen.dart';
|
||||
export 'things_i_want_you_to_help_me_screen.dart';
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class FuturePlansScreen extends StatefulWidget {
|
||||
const FuturePlansScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<FuturePlansScreen> createState() => _FuturePlansScreenState();
|
||||
}
|
||||
|
||||
class _FuturePlansScreenState extends State<FuturePlansScreen> {
|
||||
final FuturePlansScreenController controller = Get.put(FuturePlansScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Future Plans',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "What are my future plans?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "How am I going to achieve them?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,566 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class HealthFullBodyMapScreen extends StatefulWidget {
|
||||
const HealthFullBodyMapScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HealthFullBodyMapScreen> createState() => _HealthFullBodyMapState();
|
||||
}
|
||||
|
||||
class _HealthFullBodyMapState extends State<HealthFullBodyMapScreen> {
|
||||
HealthFullBodyMapScreenController controller =
|
||||
Get.put(HealthFullBodyMapScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Health Full Body Map',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 8.h),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
listHeading(),
|
||||
SizedBox(
|
||||
height: 15.h,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.firstPointVisible.value = false;
|
||||
controller.secondPointVisible.value = false;
|
||||
controller.thirdPointVisible.value = false;
|
||||
controller.fourthPointVisible.value = false;
|
||||
controller.fifthPointVisible.value = false;
|
||||
controller.sixthPointVisible.value = false;
|
||||
},
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 1.22,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Positioned(
|
||||
// left: 60,
|
||||
bottom: 0,
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kEclipseIcon),
|
||||
),
|
||||
const Positioned(
|
||||
left: 100,
|
||||
top: 5,
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kManBodyImage),
|
||||
),
|
||||
pointWidgets(
|
||||
leftPosition: 162,
|
||||
topPosition: 10,
|
||||
colorOfPoint: CustomAppColors.kRedColor,
|
||||
onPointTap: () {
|
||||
controller.firstPointVisible.toggle();
|
||||
controller.secondPointVisible.value = false;
|
||||
controller.thirdPointVisible.value = false;
|
||||
controller.fourthPointVisible.value = false;
|
||||
controller.fifthPointVisible.value = false;
|
||||
controller.sixthPointVisible.value = false;
|
||||
},
|
||||
),
|
||||
pointWidgets(
|
||||
leftPosition: 218,
|
||||
topPosition: 90,
|
||||
colorOfPoint: CustomAppColors.kSecondaryColor,
|
||||
onPointTap: () {
|
||||
controller.secondPointVisible.toggle();
|
||||
controller.firstPointVisible.value = false;
|
||||
controller.thirdPointVisible.value = false;
|
||||
controller.fourthPointVisible.value = false;
|
||||
controller.fifthPointVisible.value = false;
|
||||
controller.sixthPointVisible.value = false;
|
||||
},
|
||||
),
|
||||
pointWidgets(
|
||||
leftPosition: 118,
|
||||
topPosition: 140,
|
||||
colorOfPoint:
|
||||
CustomAppColors.kRedColor.withAlpha(250),
|
||||
onPointTap: () {
|
||||
controller.firstPointVisible.value = false;
|
||||
controller.secondPointVisible.value = false;
|
||||
controller.fourthPointVisible.value = false;
|
||||
controller.fifthPointVisible.value = false;
|
||||
controller.sixthPointVisible.value = false;
|
||||
controller.thirdPointVisible.toggle();
|
||||
},
|
||||
),
|
||||
pointWidgets(
|
||||
leftPosition: 150,
|
||||
topPosition: 155,
|
||||
colorOfPoint:
|
||||
CustomAppColors.kRedColor.withAlpha(250),
|
||||
onPointTap: () {
|
||||
controller.firstPointVisible.value = false;
|
||||
controller.secondPointVisible.value = false;
|
||||
controller.thirdPointVisible.value = false;
|
||||
controller.fifthPointVisible.value = false;
|
||||
controller.sixthPointVisible.value = false;
|
||||
controller.fourthPointVisible.toggle();
|
||||
},
|
||||
),
|
||||
pointWidgets(
|
||||
leftPosition: 145,
|
||||
topPosition: 320,
|
||||
colorOfPoint:
|
||||
CustomAppColors.kRedColor.withAlpha(250),
|
||||
onPointTap: () {
|
||||
controller.firstPointVisible.value = false;
|
||||
controller.secondPointVisible.value = false;
|
||||
controller.thirdPointVisible.value = false;
|
||||
controller.fourthPointVisible.value = false;
|
||||
controller.sixthPointVisible.value = false;
|
||||
controller.fifthPointVisible.toggle();
|
||||
},
|
||||
),
|
||||
pointWidgets(
|
||||
leftPosition: 190,
|
||||
bottomPosition: 105,
|
||||
colorOfPoint:
|
||||
CustomAppColors.kRedColor.withAlpha(250),
|
||||
onPointTap: () {
|
||||
controller.firstPointVisible.value = false;
|
||||
controller.secondPointVisible.value = false;
|
||||
controller.thirdPointVisible.value = false;
|
||||
controller.fourthPointVisible.value = false;
|
||||
controller.fifthPointVisible.value = false;
|
||||
controller.sixthPointVisible.toggle();
|
||||
},
|
||||
),
|
||||
triangleView(
|
||||
leftPosition: 158,
|
||||
topPosition: 22,
|
||||
visibility: controller.firstPointVisible,
|
||||
),
|
||||
issueDetailsDialog(
|
||||
topPosition: 28,
|
||||
leftPosition: 15,
|
||||
showTriangle: false,
|
||||
visibility: controller.firstPointVisible,
|
||||
healthNote: "Headache",
|
||||
selectedDropDownValue:
|
||||
controller.firstPointSelectedDropdownValue,
|
||||
complaint: "Issue No. 01, Issue No. 02",
|
||||
lastUpdate: "Jul/0/2023",
|
||||
),
|
||||
triangleView(
|
||||
leftPosition: 213,
|
||||
topPosition: 102,
|
||||
visibility: controller.secondPointVisible,
|
||||
),
|
||||
issueDetailsDialog(
|
||||
topPosition: 108,
|
||||
leftPosition: 35,
|
||||
showTriangle: false,
|
||||
visibility: controller.secondPointVisible,
|
||||
healthNote: "Shoulders Muscle Pain",
|
||||
selectedDropDownValue:
|
||||
controller.secondPointSelectedDropdownValue,
|
||||
complaint: "Issue No. 01, Issue No. 02",
|
||||
lastUpdate: "Jul/0/2023",
|
||||
),
|
||||
triangleView(
|
||||
leftPosition: 114,
|
||||
topPosition: 152,
|
||||
visibility: controller.thirdPointVisible,
|
||||
),
|
||||
issueDetailsDialog(
|
||||
topPosition: 158,
|
||||
leftPosition: 10,
|
||||
showTriangle: false,
|
||||
visibility: controller.thirdPointVisible,
|
||||
healthNote: "Elbow Pain",
|
||||
selectedDropDownValue:
|
||||
controller.thirdPointSelectedDropdownValue,
|
||||
complaint: "Issue No. 01, Issue No. 02",
|
||||
lastUpdate: "Jul/0/2023",
|
||||
),
|
||||
triangleView(
|
||||
leftPosition: 146,
|
||||
topPosition: 168,
|
||||
visibility: controller.fourthPointVisible,
|
||||
),
|
||||
issueDetailsDialog(
|
||||
topPosition: 175,
|
||||
leftPosition: 10,
|
||||
showTriangle: false,
|
||||
visibility: controller.fourthPointVisible,
|
||||
healthNote: "Stomach Pain",
|
||||
selectedDropDownValue:
|
||||
controller.fourthPointSelectedDropdownValue,
|
||||
complaint: "Issue No. 01, Issue No. 02",
|
||||
lastUpdate: "Jul/0/2023",
|
||||
),
|
||||
triangleView(
|
||||
leftPosition: 140,
|
||||
topPosition: 333,
|
||||
visibility: controller.fifthPointVisible,
|
||||
),
|
||||
issueDetailsDialog(
|
||||
topPosition: 340,
|
||||
leftPosition: 10,
|
||||
showTriangle: false,
|
||||
visibility: controller.fifthPointVisible,
|
||||
healthNote: "Knee Pain",
|
||||
selectedDropDownValue:
|
||||
controller.fifthPointSelectedDropdownValue,
|
||||
complaint: "Issue No. 01, Issue No. 02",
|
||||
lastUpdate: "Jul/0/2023",
|
||||
),
|
||||
triangleView(
|
||||
leftPosition: 185,
|
||||
bottomPosition: 95,
|
||||
visibility: controller.sixthPointVisible,
|
||||
),
|
||||
issueDetailsDialog(
|
||||
topPosition: 430,
|
||||
leftPosition: 10,
|
||||
showTriangle: false,
|
||||
visibility: controller.sixthPointVisible,
|
||||
healthNote: "Foot Pain",
|
||||
selectedDropDownValue:
|
||||
controller.sixthPointSelectedDropdownValue,
|
||||
complaint: "Issue No. 01, Issue No. 02",
|
||||
lastUpdate: "Jul/0/2023",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 15.h,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Positioned triangleView({
|
||||
double? topPosition,
|
||||
double? bottomPosition,
|
||||
double? rightPosition,
|
||||
double? leftPosition,
|
||||
required RxBool visibility,
|
||||
bool colorShow = false,
|
||||
}) {
|
||||
return Positioned(
|
||||
top: topPosition,
|
||||
left: leftPosition,
|
||||
right: rightPosition,
|
||||
bottom: bottomPosition,
|
||||
child: Obx(
|
||||
() => Container(
|
||||
color: colorShow ? CustomAppColors.kGreenColor : null,
|
||||
child: Visibility(
|
||||
visible: visibility.value,
|
||||
child: const CustomImageWidget(
|
||||
imagePath: AssetsManager.kTriangleIcon,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Positioned pointWidgets({
|
||||
double? topPosition,
|
||||
double? bottomPosition,
|
||||
double? rightPosition,
|
||||
double? leftPosition,
|
||||
required Color colorOfPoint,
|
||||
required VoidCallback onPointTap,
|
||||
}) {
|
||||
return Positioned(
|
||||
top: topPosition,
|
||||
left: leftPosition,
|
||||
right: rightPosition,
|
||||
bottom: bottomPosition,
|
||||
child: InkWell(
|
||||
onTap: onPointTap,
|
||||
child: CircleAvatar(
|
||||
radius: 5,
|
||||
backgroundColor: colorOfPoint,
|
||||
child: const CustomTextWidget(
|
||||
text: "",
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget issueDetailsDialog({
|
||||
double? topPosition,
|
||||
double? bottomPosition,
|
||||
double? rightPosition,
|
||||
double? leftPosition,
|
||||
bool showTriangle = true,
|
||||
required RxBool visibility,
|
||||
required String healthNote,
|
||||
required String complaint,
|
||||
required String lastUpdate,
|
||||
required RxString selectedDropDownValue,
|
||||
}) {
|
||||
return Obx(
|
||||
() => Positioned(
|
||||
top: topPosition,
|
||||
left: leftPosition,
|
||||
right: rightPosition,
|
||||
bottom: bottomPosition,
|
||||
child: Visibility(
|
||||
visible: visibility.value,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Visibility(
|
||||
visible: showTriangle,
|
||||
child: const CustomImageWidget(
|
||||
imagePath: AssetsManager.kTriangleIcon,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 300,
|
||||
height: 90,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kLightGreyColor),
|
||||
color: CustomAppColors.kWhiteColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: CustomAppColors.kLightGreyColor.withOpacity(0.5),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 3),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10.sp),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: 'Health Note',
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: healthNote,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.bold,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Container(
|
||||
alignment: Alignment.topRight,
|
||||
margin: EdgeInsets.only(right: 5.w, top: 5.h),
|
||||
height: 30.h,
|
||||
width: 60.w,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.r),
|
||||
color: selectedDropDownValue.value
|
||||
.contains("Expired")
|
||||
? CustomAppColors.kRedColor.withAlpha(80)
|
||||
: CustomAppColors.kGreenColor.withAlpha(80),
|
||||
),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
borderRadius: BorderRadius.circular(5.r),
|
||||
isExpanded: false,
|
||||
items: controller.activeList
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e,
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.center,
|
||||
fontColor: selectedDropDownValue
|
||||
.value
|
||||
.contains("Expired")
|
||||
? CustomAppColors.kRedColor
|
||||
: CustomAppColors.kGreenColor,
|
||||
text: e.toString(),
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
value: selectedDropDownValue.value,
|
||||
onChanged: (value) {
|
||||
selectedDropDownValue.value =
|
||||
value.toString();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
Divider(color: CustomAppColors.kLightGreyColor, height: 5),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 17.sp, top: 3.sp),
|
||||
child: Text.rich(
|
||||
textAlign: TextAlign.left,
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Complaint: ",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextSpan(
|
||||
text: complaint,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 17.sp, top: 3.sp),
|
||||
child: Text.rich(
|
||||
textAlign: TextAlign.left,
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Last Update: ",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextSpan(
|
||||
text: lastUpdate,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget listHeading() {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
bottom: BorderSide(color: CustomAppColors.kSmokeColor),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kBlueColor.withAlpha(150),
|
||||
border: Border.all(color: CustomAppColors.kBlueColor),
|
||||
borderRadius: BorderRadius.circular(50.r),
|
||||
),
|
||||
padding:
|
||||
const EdgeInsets.only(right: 5, left: 5, top: 5, bottom: 5),
|
||||
child: CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: "All Issues",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(right: 0, top: 10, bottom: 10),
|
||||
child: const CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: "Head Pain",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(right: 0, top: 10, bottom: 10),
|
||||
child: CustomTextWidget(
|
||||
text: "Nose Bone fracture",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class HealthScreen extends StatefulWidget {
|
||||
const HealthScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<HealthScreen> createState() => _HealthScreenState();
|
||||
}
|
||||
|
||||
class _HealthScreenState extends State<HealthScreen> {
|
||||
final HealthScreenController controller = Get.put(HealthScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Health',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "What are we worried about and why?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "What can we do to support?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 140.h),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.zero,
|
||||
child: CustomAppButton(
|
||||
buttonText: ConstantText.kViewFullBodyMap,
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kHealthFullBodyMapScreenRoute);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class ClientIntroductionScreen extends StatefulWidget {
|
||||
const ClientIntroductionScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ClientIntroductionScreen> createState() => _ClientIntroductionScreenState();
|
||||
}
|
||||
|
||||
class _ClientIntroductionScreenState extends State<ClientIntroductionScreen> {
|
||||
ClientsIntroductionScreenController controller = ClientsIntroductionScreenController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 15.w,),
|
||||
CustomTextWidget(
|
||||
text: "Introduction",
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(50.r),
|
||||
// child: CustomImageWidget(
|
||||
// imagePath: FrequentFunctions
|
||||
// .userModel.value.profilePictureUrl.isNotEmpty
|
||||
// ? "${WebUrls.baseUrl}${FrequentFunctions.userModel.value.profilePictureUrl}"
|
||||
// : AssetsManager.kPersonMainIcon,
|
||||
// imageColor: FrequentFunctions
|
||||
// .userModel.value.profilePictureUrl.isNotEmpty
|
||||
// ? null
|
||||
// : CustomAppColors.kLightTextColor,
|
||||
// height: 80.h,
|
||||
// width: 80.w,
|
||||
// ),
|
||||
// ),
|
||||
SizedBox(height: 16.h),
|
||||
CustomTextWidget(
|
||||
text: 'user',
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
SizedBox(height: 16.h),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(child: BuildDetailSingleItem(title: 'Email', value: "jaylon.n@ftcservices.com",)),
|
||||
Expanded(child: BuildDetailSingleItem(title: 'Contact Number', value: "+44 (0) 00 0000 0000",)),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(child: BuildDetailSingleItem(title: 'NI Number', value: "QQ 123456 C",)),
|
||||
Expanded(child: BuildDetailSingleItem(title: 'DOB', value:"15/11/1996")),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(child: BuildDetailSingleItem(title: 'Post Code', value: "GL55 8PN",)),
|
||||
Expanded(child: BuildDetailSingleItem(title: 'Kin', value:"12PO025")),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
BuildDetailSingleItem(title: 'Address', value: "Gloucester, 1-2 Street Name",),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class MedicationScreen extends StatefulWidget {
|
||||
const MedicationScreen({super.key});
|
||||
|
||||
@override
|
||||
State<MedicationScreen> createState() => _MedicationScreenState();
|
||||
}
|
||||
|
||||
class _MedicationScreenState extends State<MedicationScreen> {
|
||||
final MedicationScreenController controller =
|
||||
Get.put(MedicationScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton:()=> controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap:()=> controller.backButtonPressed(context),
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Medication',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
totalMedicinesNameRowField(
|
||||
normalText: "Total medicines:", boldText: "2"),
|
||||
SizedBox(height: 4.h),
|
||||
|
||||
SizedBox(height: 24.h),
|
||||
medicationHeading(headingText: "Pregabalin 50mg"),
|
||||
SizedBox(height: 24.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
Divider(),
|
||||
SizedBox(height: 8.h),
|
||||
medicationHeading(headingText: "Lamotrigene"),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ListTile medicationHeading({required String headingText}) {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 12.w, right: 0.w),
|
||||
title: CustomTextWidget(
|
||||
text: headingText,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
// tileColor: Colors.black.withOpacity(0.2),
|
||||
trailing: SizedBox(
|
||||
width: 60.w,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(1.sp),
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kYellowColor.withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(50.r),
|
||||
),
|
||||
child: const Icon(Icons.edit,color: CustomAppColors.kDarkYellowColor,)),
|
||||
),
|
||||
SizedBox(width: 3.w,),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(1.sp),
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kRedColor.withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(50.r),
|
||||
),
|
||||
child: const Icon(Icons.delete,color: CustomAppColors.kRedColor,)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Row totalMedicinesNameRowField({required String boldText, required String normalText}) {
|
||||
return Row(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: normalText,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
|
||||
CustomTextWidget(
|
||||
text: boldText,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class MentalHealthScreen extends StatefulWidget {
|
||||
const MentalHealthScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MentalHealthScreen> createState() => _MentalHealthScreenState();
|
||||
}
|
||||
|
||||
class _MentalHealthScreenState extends State<MentalHealthScreen> {
|
||||
final MentalHealthScreenController controller = Get.put(MentalHealthScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Mental Health',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "the current presentation of mental health",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "Need Support to my current mental health",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class MyCurrentPlanScreen extends StatefulWidget {
|
||||
const MyCurrentPlanScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyCurrentPlanScreen> createState() => _MyCurrentPlanScreenState();
|
||||
}
|
||||
|
||||
class _MyCurrentPlanScreenState extends State<MyCurrentPlanScreen> {
|
||||
final MyCurrentPlanScreenController controller = Get.put(MyCurrentPlanScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'My current plan',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "My current plan",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "Current support that I need",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class MyInterestsScreen extends StatefulWidget {
|
||||
const MyInterestsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyInterestsScreen> createState() => _MyInterestsScreenState();
|
||||
}
|
||||
|
||||
class _MyInterestsScreenState extends State<MyInterestsScreen> {
|
||||
final MyInterestsScreenController controller = Get.put(MyInterestsScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'My Interests',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Things I like doing",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "How I can support these activities?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class OverviewScreen extends StatefulWidget {
|
||||
const OverviewScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<OverviewScreen> createState() => _OverviewScreenState();
|
||||
}
|
||||
|
||||
class _OverviewScreenState extends State<OverviewScreen> {
|
||||
final OverViewScreenController controller =
|
||||
Get.put(OverViewScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Overview (What I want you to know about me)',
|
||||
isExpanded: false,
|
||||
fontSize: 13.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "What I want you to know about me",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "Current support that I need",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class SupportPlanScreen extends StatefulWidget {
|
||||
const SupportPlanScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SupportPlanScreen> createState() => _SupportPlanScreenState();
|
||||
}
|
||||
|
||||
class _SupportPlanScreenState extends State<SupportPlanScreen> {
|
||||
SupportPlanScreenController controller =
|
||||
Get.put(SupportPlanScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 15.w,),
|
||||
CustomTextWidget(
|
||||
text: 'Support Plan Menu',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(height: 16.h),
|
||||
LineWidget(
|
||||
text: "Medications",
|
||||
onItemTap: () {
|
||||
Navigator.pushNamed(context,
|
||||
CustomRouteNames.kMedicationScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Mental Health",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kMentalHealthScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Future Plans",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kFuturePlansScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Introduction",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kClientsIntroductionScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Overview",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kOverViewScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "My Current Plan",onItemTap:(){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kMyCurrentPlanScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Things I want you to help me with",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kThingsIWantYouToHelpScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "My interests",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kMyInterestsScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Health",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kHealthScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
LineWidget(text: "Crisis Management",onItemTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kCrisisManagementScreenRoute);
|
||||
}),
|
||||
SizedBox(height: 5.h,),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../../ftc_mobile_app.dart';
|
||||
|
||||
class ThingsIWantYouToHelpScreen extends StatefulWidget {
|
||||
const ThingsIWantYouToHelpScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ThingsIWantYouToHelpScreen> createState() => _ThingsIWantYouToHelpScreenState();
|
||||
}
|
||||
|
||||
class _ThingsIWantYouToHelpScreenState extends State<ThingsIWantYouToHelpScreen> {
|
||||
final ThingsIWantYouToHelpMeWithScreenController controller =
|
||||
Get.put(ThingsIWantYouToHelpMeWithScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Things I want you to help me with',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Things I want you to help me with",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took"),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
text: "How I can help?",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text:
|
||||
"It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus."),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import '../../../models/clients/consent_details_model.dart';
|
||||
import '../../../models/profileData/user_data.dart';
|
||||
|
||||
class ConsentAndCapacityAddNewFormScreenArgs {
|
||||
final UserData userData;
|
||||
final ConsentDetailsModel? consentData;
|
||||
|
||||
ConsentAndCapacityAddNewFormScreenArgs({
|
||||
required this.userData,
|
||||
this.consentData,
|
||||
});
|
||||
}
|
||||
|
||||
class ConsentAndCapacityAddNewFormScreen extends StatefulWidget {
|
||||
final ConsentAndCapacityAddNewFormScreenArgs args;
|
||||
|
||||
const ConsentAndCapacityAddNewFormScreen({Key? key, required this.args})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ConsentAndCapacityAddNewFormScreen> createState() =>
|
||||
_ConsentAndCapacityAddNewFormScreenState();
|
||||
}
|
||||
|
||||
class _ConsentAndCapacityAddNewFormScreenState
|
||||
extends State<ConsentAndCapacityAddNewFormScreen> {
|
||||
final controller = Get.put(ConsentAndCapacityAddNewFormScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.isForUpdate.value = (widget.args.consentData != null);
|
||||
|
||||
controller.firstNameController.text =
|
||||
widget.args.userData.modelId?.suFirstMiddleName ?? "";
|
||||
controller.lastNameController.text =
|
||||
widget.args.userData.modelId?.suLastName ?? "";
|
||||
controller.phoneController.text =
|
||||
widget.args.userData.modelId?.phoneNo ?? "";
|
||||
controller.emailController.text =
|
||||
widget.args.userData.modelId?.suEmailWork ?? "";
|
||||
controller.genderController.text =
|
||||
widget.args.userData.modelId?.suSex ?? "";
|
||||
controller.dobController.text = (widget.args.userData.modelId?.suDob ==
|
||||
null)
|
||||
? ""
|
||||
: DateFormat("MMM/dd/yyyy").format(widget.args.userData.modelId!.suDob);
|
||||
controller.ageController.text = widget.args.userData.modelId?.suAge ?? "";
|
||||
controller.descriptionController.text =
|
||||
widget.args.consentData?.description ?? "";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => controller.backButtonPressed(context),
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
15.horizontalSpace,
|
||||
Obx(
|
||||
() => CustomTextWidget(
|
||||
text: controller.isForUpdate.value
|
||||
? 'Update Consent And Capacity'
|
||||
: 'Consent And Capacity',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.topLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: ' Add New Form',
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Young Information",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
20.verticalSpace,
|
||||
_textField(
|
||||
controller: controller.firstNameController,
|
||||
enabled: false,
|
||||
headingText: "First & Middle Name",
|
||||
hintText: "First & Middle Name",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_textField(
|
||||
controller: controller.lastNameController,
|
||||
enabled: false,
|
||||
headingText: "Last Name",
|
||||
hintText: "Last Name",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_textField(
|
||||
controller: controller.phoneController,
|
||||
enabled: false,
|
||||
headingText: "Phone No.",
|
||||
hintText: "Phone No.",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_textField(
|
||||
controller: controller.emailController,
|
||||
enabled: false,
|
||||
headingText: "Email",
|
||||
hintText: "Email",
|
||||
),
|
||||
20.verticalSpace,
|
||||
_textField(
|
||||
controller: controller.genderController,
|
||||
enabled: false,
|
||||
headingText: "Sex",
|
||||
hintText: "Sex",
|
||||
),
|
||||
20.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _textField(
|
||||
controller: controller.dobController,
|
||||
enabled: false,
|
||||
headingText: "Date Of Birth",
|
||||
hintText: "Date Of Birth",
|
||||
),
|
||||
),
|
||||
10.horizontalSpace,
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: _textField(
|
||||
controller: controller.ageController,
|
||||
enabled: false,
|
||||
headingText: "Age",
|
||||
hintText: "Age",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
controller: controller.descriptionController,
|
||||
heading: "Description",
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
),
|
||||
20.verticalSpace,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5.r),
|
||||
),
|
||||
backgroundColor: CustomAppColors.kSecondaryColor),
|
||||
onPressed: () async {
|
||||
controller.isForUpdate.value
|
||||
? controller.updateButtonPressed(
|
||||
widget.args.consentData!.id)
|
||||
: await controller
|
||||
.saveButtonPressed(widget.args.userData.id!);
|
||||
|
||||
Navigator.of(context).pop(controller.isForUpdate.value
|
||||
? controller.descriptionController.text
|
||||
: controller.saveResult);
|
||||
},
|
||||
child: Obx(
|
||||
() => CustomTextWidget(
|
||||
text: controller.isForUpdate.value
|
||||
? "Update"
|
||||
: 'Save',
|
||||
fontColor: CustomAppColors.kPrimaryColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
5.horizontalSpace,
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: const BorderSide(
|
||||
color: CustomAppColors.kSecondaryColor),
|
||||
borderRadius: BorderRadius.circular(5.r),
|
||||
),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: CustomTextWidget(
|
||||
text: 'Cancel',
|
||||
fontColor: CustomAppColors.kSecondaryColor,
|
||||
fontSize: 15.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
20.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TextField _textField({
|
||||
required String headingText,
|
||||
required String hintText,
|
||||
int minLines = 1,
|
||||
int maxLines = 1,
|
||||
TextEditingController? controller,
|
||||
bool enabled = true,
|
||||
TextInputType? inputType,
|
||||
}) {
|
||||
return TextField(
|
||||
enabled: enabled,
|
||||
maxLines: maxLines,
|
||||
minLines: minLines,
|
||||
controller: controller,
|
||||
textAlign: TextAlign.left,
|
||||
keyboardType: inputType,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: hintText,
|
||||
labelText: headingText,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<ConsentAndCapacityAddNewFormScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class ConsentScreenTextField extends StatelessWidget {
|
||||
const ConsentScreenTextField({
|
||||
super.key,
|
||||
required this.headingText,
|
||||
required this.hintText,
|
||||
this.minLines,
|
||||
this.maxLines,
|
||||
this.fieldIcon,
|
||||
this.fieldController,
|
||||
this.viewOnly,
|
||||
});
|
||||
|
||||
final String headingText;
|
||||
|
||||
final String hintText;
|
||||
|
||||
final int? minLines;
|
||||
final int? maxLines;
|
||||
final IconData? fieldIcon;
|
||||
final bool? viewOnly;
|
||||
final TextEditingController? fieldController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
enabled: !(viewOnly != null ? viewOnly == true : fieldController == null),
|
||||
maxLines: maxLines,
|
||||
minLines: minLines,
|
||||
textAlign: TextAlign.left,
|
||||
controller: fieldController ?? (TextEditingController()..text = hintText),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: Icon(fieldIcon),
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: hintText,
|
||||
labelText: headingText,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import '../../../models/clients/consent_details_model.dart';
|
||||
import '../../../models/profileData/user_data.dart';
|
||||
|
||||
class ConsentAndCapacityQuestionnaireScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const ConsentAndCapacityQuestionnaireScreen(
|
||||
{Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ConsentAndCapacityQuestionnaireScreen> createState() =>
|
||||
_ConsentAndCapacityQuestionnaireScreenState();
|
||||
}
|
||||
|
||||
class _ConsentAndCapacityQuestionnaireScreenState
|
||||
extends State<ConsentAndCapacityQuestionnaireScreen> {
|
||||
late final ConsentAndCapacityQuestionnaireScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(
|
||||
ConsentAndCapacityQuestionnaireScreenController(data: widget.userData));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
// onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
// sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: _appBar(context),
|
||||
body: SafeArea(
|
||||
child: Obx(() {
|
||||
if (controller.serviceUser() == null) {
|
||||
return FrequentFunctions.centerText(text: "User detail not found");
|
||||
}
|
||||
|
||||
final detail = controller.serviceUser()!;
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Questionnaire",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
16.verticalSpace,
|
||||
nameRowField(boldText: "Name:", normalText: detail.displayName),
|
||||
4.verticalSpace,
|
||||
nameRowField(
|
||||
boldText: "DOB:",
|
||||
normalText: detail.modelId?.suDob == null
|
||||
? ""
|
||||
: DateFormatter()
|
||||
.getHolidayDate(detail.modelId!.suDob)),
|
||||
4.verticalSpace,
|
||||
nameRowField(
|
||||
boldText: "Sex:",
|
||||
normalText: detail.modelId?.suSex ?? ""),
|
||||
4.verticalSpace,
|
||||
nameRowField(
|
||||
boldText: "Contact No:",
|
||||
normalText: detail.modelId?.phoneNo ?? ""),
|
||||
4.verticalSpace,
|
||||
nameRowField(
|
||||
boldText: "Email:",
|
||||
normalText: detail.modelId?.suEmailWork ?? ""),
|
||||
24.verticalSpace,
|
||||
Obx(
|
||||
() => ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (context, index) => 8.verticalSpace,
|
||||
itemCount: controller.consentDetailsList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return _listItem(
|
||||
index, controller.consentDetailsList[index]);
|
||||
},
|
||||
),
|
||||
),
|
||||
24.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: "Consent And Capacity",
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () async {
|
||||
final result = await Navigator.pushNamed(
|
||||
context, CustomRouteNames.kConsentAndCapacityAddNewFormScreenRoute,
|
||||
arguments: ConsentAndCapacityAddNewFormScreenArgs(
|
||||
userData: widget.userData,
|
||||
));
|
||||
if (result is ConsentDetailsModel) {
|
||||
controller.consentDetailsList.insert(0, result);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _listItem(int index, ConsentDetailsModel data) {
|
||||
return Container(
|
||||
key: ObjectKey(data),
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kLightGreyColor.withOpacity(0.2),
|
||||
),
|
||||
padding: REdgeInsets.all(8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: data.description,
|
||||
isExpanded: false,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16,
|
||||
).paddingSymmetric(horizontal: 8.r),
|
||||
6.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextWidget(
|
||||
text: DateFormat("dd/MM/yyyy / hh:mm:ss aa")
|
||||
.format(data.updatedAt)
|
||||
.toUpperCase(),
|
||||
isExpanded: false,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 14,
|
||||
).paddingSymmetric(horizontal: 8.r),
|
||||
),
|
||||
// InkWell(
|
||||
// borderRadius: 24.toRadius(),
|
||||
// onTap: () {
|
||||
// _onEditClick(index, data);
|
||||
// },
|
||||
// child:
|
||||
// Icon(Icons.mode_edit_outlined, size: 22.r).addPaddingAll(4),
|
||||
// ),
|
||||
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Row nameRowField({required String boldText, required String normalText}) {
|
||||
return Row(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: boldText,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: CustomTextWidget(
|
||||
text: normalText,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
textAlign: TextAlign.left,
|
||||
alignment: Alignment.topLeft),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
_onEditClick(int index, ConsentDetailsModel data) async {
|
||||
final result = await Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kConsentAndCapacityAddNewFormScreenRoute,
|
||||
arguments: ConsentAndCapacityAddNewFormScreenArgs(
|
||||
userData: widget.userData,
|
||||
consentData: data,
|
||||
),
|
||||
);
|
||||
|
||||
if (result is String) {
|
||||
controller.consentDetailsList[index].description = result;
|
||||
controller.consentDetailsList.refresh();
|
||||
}
|
||||
// MultilineTextFieldSheet(
|
||||
// buttonLabel: 'Submit',
|
||||
// appBarTitle: '',
|
||||
// textFieldHint: 'Type here...',
|
||||
// prevValueForField: data.description,
|
||||
// wantLeadingIcon: false,
|
||||
// onButtonClick: (String text) {
|
||||
// controller.updateButtonPressed(text, data.id, index);
|
||||
// },
|
||||
// ).show();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/HealthIssuesDetailsModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/enums/body_parts.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/human_body_mapper_widget.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import '../add_details_to_new_body_point_screen.dart';
|
||||
import 'widget/IssueDetailPopupWidget.dart';
|
||||
|
||||
class CurrentHealthIssuesScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const CurrentHealthIssuesScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<CurrentHealthIssuesScreen> createState() =>
|
||||
_CurrentHealthIssuesScreenState();
|
||||
}
|
||||
|
||||
class _CurrentHealthIssuesScreenState extends State<CurrentHealthIssuesScreen> {
|
||||
final CurrentHealthIssuesScreenController controller =
|
||||
Get.put(CurrentHealthIssuesScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUserId = widget.userData.id!;
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
length: controller.tabs.length,
|
||||
child: CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
onBackButton: () => controller.onBackPress(context),
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: _appBar(context),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
//User details
|
||||
serviceUserDetailWidget(),
|
||||
|
||||
Divider(
|
||||
height: 1,
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
TabBar(
|
||||
onTap: (i) {
|
||||
controller.onTabChange(controller.tabs[i]);
|
||||
},
|
||||
tabs: controller.tabs
|
||||
.map((e) => Tab(
|
||||
text: e,
|
||||
))
|
||||
.toList()),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
8.verticalSpace,
|
||||
Obx(() {
|
||||
final entries = controller.issueBodyParts.entries;
|
||||
|
||||
if (entries.isEmpty) {
|
||||
return FrequentFunctions.noWidget;
|
||||
}
|
||||
|
||||
final map = <BodyPart, Color?>{};
|
||||
for (var e in entries) {
|
||||
map[e.key] = e.value.color;
|
||||
}
|
||||
|
||||
return HumanBodyWidget(
|
||||
visibleBodyPoints: map,
|
||||
width: Get.width * 0.9,
|
||||
onPointTap: (b, p) {
|
||||
RenderBox? overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox?;
|
||||
|
||||
showMenu(
|
||||
context: context,
|
||||
surfaceTintColor: Colors.white,
|
||||
position: RelativeRect.fromRect(
|
||||
p & const Size(40, 40),
|
||||
// Smaller rect, the touch area
|
||||
Offset.zero &
|
||||
(overlay?.size ??
|
||||
Get.mediaQuery
|
||||
.size), // Bigger rect, the entire screen
|
||||
),
|
||||
items: [
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: IssueDetailPopupWidget(
|
||||
userData: widget.userData,
|
||||
data: controller.issueBodyParts[b]!.data,
|
||||
onActionChange: (status, data) {
|
||||
if (data.status != status) {
|
||||
controller.updateHealthIssueStatus(
|
||||
bodyPoint: b, data: data, status: status);
|
||||
}
|
||||
},
|
||||
onUpdateButtonTap: (data) async {
|
||||
Get.back();
|
||||
onAddOrUpdateButtonTap(context, data);
|
||||
},
|
||||
),
|
||||
),
|
||||
]);
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: "Current Health Issues",
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () => onAddOrUpdateButtonTap(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget serviceUserDetailWidget() {
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url:
|
||||
"${WebUrls.baseUrl}${widget.userData.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 53.r,
|
||||
width: 53.r,
|
||||
),
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: widget.userData.displayName,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
32.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _labelValueWidgets(
|
||||
'Email:',
|
||||
widget.userData.email ?? "",
|
||||
),
|
||||
)),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _labelValueWidgets(
|
||||
'Contact Number:',
|
||||
widget.userData.modelId?.phoneNo ?? "",
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
..._labelValueWidgets(
|
||||
'Address 1:',
|
||||
widget.userData.modelId?.suAddress1 ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
..._labelValueWidgets(
|
||||
'Address 2:',
|
||||
widget.userData.modelId?.suAddress2 ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _labelValueWidgets(String label, String value) {
|
||||
return [
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text: label,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
fontSize: 12.sp),
|
||||
4.verticalSpace,
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: value,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
fontSize: 13.sp),
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> onAddOrUpdateButtonTap(BuildContext context,
|
||||
[HealthIssueDetailsModel? data]) async {
|
||||
dynamic result = await Navigator.of(context)
|
||||
.pushNamed(CustomRouteNames.kAddDetailsToNewPointScreenRoute,
|
||||
arguments: AddDetailsToNewBodyPointScreenArgs(
|
||||
userData: widget.userData,
|
||||
issueData: data,
|
||||
));
|
||||
if (result == true) {
|
||||
controller.getPointsDataFromService();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/HealthIssuesDetailsModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class IssueDetailPopupWidget extends StatefulWidget {
|
||||
const IssueDetailPopupWidget({
|
||||
super.key,
|
||||
required this.userData,
|
||||
required this.data,
|
||||
required this.onActionChange,
|
||||
required this.onUpdateButtonTap,
|
||||
});
|
||||
|
||||
final UserData userData;
|
||||
final HealthIssueDetailsModel data;
|
||||
final Function(bool status, HealthIssueDetailsModel data) onActionChange;
|
||||
final Function(HealthIssueDetailsModel data) onUpdateButtonTap;
|
||||
|
||||
static const actionActive = "Active";
|
||||
static const actionResolved = "Resolved";
|
||||
|
||||
@override
|
||||
State<IssueDetailPopupWidget> createState() => _IssueDetailPopupWidgetState();
|
||||
}
|
||||
|
||||
class _IssueDetailPopupWidgetState extends State<IssueDetailPopupWidget> {
|
||||
final Map<String, bool> actionsMap = {
|
||||
IssueDetailPopupWidget.actionActive: true,
|
||||
IssueDetailPopupWidget.actionResolved: false
|
||||
};
|
||||
|
||||
String selectedValue = IssueDetailPopupWidget.actionActive;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
selectedValue = widget.data.status
|
||||
? IssueDetailPopupWidget.actionActive
|
||||
: IssueDetailPopupWidget.actionResolved;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: Get.width,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: double.maxFinite,
|
||||
padding: REdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Health Note',
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: widget.data.healthNote,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.bold,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 90.r,
|
||||
height: 32.r,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: 24.toRadius(),
|
||||
color: (selectedValue ==
|
||||
IssueDetailPopupWidget.actionActive)
|
||||
? Colors.red.withOpacity(0.3)
|
||||
: Colors.green.withOpacity(0.3),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButtonFormField(
|
||||
onTap: () {
|
||||
FocusScopeNode().unfocus();
|
||||
},
|
||||
value: selectedValue,
|
||||
dropdownColor: Colors.white,
|
||||
borderRadius: 4.toRadius(),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
suffixIcon: Icon(Icons.arrow_drop_down_sharp,
|
||||
size: 18,
|
||||
color: (selectedValue ==
|
||||
IssueDetailPopupWidget.actionActive)
|
||||
? Colors.red
|
||||
: Colors.green)
|
||||
.paddingOnly(right: 12.r),
|
||||
suffixIconConstraints: BoxConstraints.tightFor(
|
||||
width: 24.r, height: 32.r),
|
||||
// contentPadding: REdgeInsets.only(left: 0),
|
||||
),
|
||||
elevation: 4,
|
||||
icon: FrequentFunctions.noWidget,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10.sp,
|
||||
color: Colors.black),
|
||||
hint: Text(
|
||||
"Select...",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12.sp,
|
||||
color: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
selectedItemBuilder: (_) {
|
||||
return actionsMap.keys.map(
|
||||
(e) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: e,
|
||||
child: Container(
|
||||
// color: (selectedValue == e)
|
||||
// ? (selectedValue ==
|
||||
// IssueDetailPopupWidget
|
||||
// .actionActive)
|
||||
// ? Colors.red.withOpacity(0.3)
|
||||
// : Colors.green.withOpacity(0.3)
|
||||
// : Colors.white,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
e,
|
||||
style: TextStyle(
|
||||
color: (selectedValue == e)
|
||||
? (selectedValue ==
|
||||
IssueDetailPopupWidget
|
||||
.actionActive)
|
||||
? Colors.red
|
||||
: Colors.green
|
||||
: Colors.black),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
},
|
||||
items: actionsMap.keys
|
||||
.map(
|
||||
(e) => DropdownMenuItem<String>(
|
||||
value: e,
|
||||
child: Text(e),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
// padding: EdgeInsets.zero,
|
||||
isExpanded: true,
|
||||
// iconSize: 20.h,
|
||||
// icon: Padding(
|
||||
// padding: REdgeInsets.only(right: 0.0),
|
||||
// child: Icon(Icons.arrow_drop_down_sharp,
|
||||
// size: 18,
|
||||
// color: Colors.black),
|
||||
// ),
|
||||
onChanged: (v) {
|
||||
if (v != null) {
|
||||
setState(() {
|
||||
selectedValue = v;
|
||||
widget.onActionChange(
|
||||
actionsMap[v]!, widget.data);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
8.verticalSpace,
|
||||
Divider(
|
||||
height: 1,
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
),
|
||||
Container(
|
||||
width: double.maxFinite,
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text.rich(
|
||||
textAlign: TextAlign.left,
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Complaint: ",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextSpan(
|
||||
text: widget.data.complaint,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
4.verticalSpace,
|
||||
Text.rich(
|
||||
textAlign: TextAlign.left,
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Last Update: ",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextSpan(
|
||||
text: DateFormat("MMM/dd/yyyy").format(
|
||||
DateTime.parse(widget.data.updatedAt)
|
||||
.toLocal()),
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, fontWeight: FontWeight.w400),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
16.verticalSpace,
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 120.r,
|
||||
height: 32.r,
|
||||
child: CustomAppButton(
|
||||
onTap: () => widget.onUpdateButtonTap(widget.data),
|
||||
buttonText: "Update",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
363
lib/view/screens/clients/document_details_screen.dart
Normal file
363
lib/view/screens/clients/document_details_screen.dart
Normal file
@@ -0,0 +1,363 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DocumentDetailsScreen extends StatefulWidget {
|
||||
const DocumentDetailsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<DocumentDetailsScreen> createState() => _DocumentDetailsScreenState();
|
||||
}
|
||||
|
||||
class _DocumentDetailsScreenState extends State<DocumentDetailsScreen> {
|
||||
final DocumentDetailsScreenController controller =
|
||||
Get.put(DocumentDetailsScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Documents',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
// await Navigator.pushNamed(
|
||||
// controller.screenKey.currentContext!,
|
||||
// CustomRouteNames.kNewNoteScreenRoute,
|
||||
// );
|
||||
},
|
||||
child: CustomTextWidget(
|
||||
text: '+ Add New',
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(50.r),
|
||||
// child: CustomImageWidget(
|
||||
// imagePath: FrequentFunctions
|
||||
// .userModel.value.profilePictureUrl.isNotEmpty
|
||||
// ? "${WebUrls.baseUrl}${FrequentFunctions.userModel.value.profilePictureUrl}"
|
||||
// : AssetsManager.kPersonMainIcon,
|
||||
// imageColor: FrequentFunctions
|
||||
// .userModel.value.profilePictureUrl.isNotEmpty
|
||||
// ? null
|
||||
// : CustomAppColors.kLightTextColor,
|
||||
// height: 80.h,
|
||||
// width: 80.w,
|
||||
// ),
|
||||
// ),
|
||||
SizedBox(height: 16.h),
|
||||
CustomTextWidget(
|
||||
text: 'user', fontSize: 14.sp, fontWeight: FontWeight.w600),
|
||||
SizedBox(height: 16.h),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BuildDetailSingleItem(
|
||||
title: 'Email',
|
||||
value: "jaylon.n@ftcservices.com",
|
||||
)),
|
||||
Expanded(
|
||||
child: BuildDetailSingleItem(
|
||||
title: 'Contact Number',
|
||||
value: "+44 (0) 00 0000 0000",
|
||||
)),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BuildDetailSingleItem(
|
||||
title: 'NI Number',
|
||||
value: "QQ 123456 C",
|
||||
)),
|
||||
Expanded(
|
||||
child: BuildDetailSingleItem(
|
||||
title: 'DOB', value: "15/11/1996")),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BuildDetailSingleItem(
|
||||
title: 'Post Code',
|
||||
value: "GL55 8PN",
|
||||
)),
|
||||
Expanded(
|
||||
child: BuildDetailSingleItem(
|
||||
title: 'Kin', value: "12PO025")),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
BuildDetailSingleItem(
|
||||
title: 'Address',
|
||||
value: "Gloucester, 1-2 Street Name",
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
Container(
|
||||
height: 30,
|
||||
margin: EdgeInsets.symmetric(horizontal: 5.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(5.r),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(left: 5, right: 10),
|
||||
child: const Center(
|
||||
child: Icon(Icons.search),
|
||||
),
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Search...",
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
isExpanded: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
listHeading(),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Aug/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Sept/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Aug/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Sept/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Aug/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Sept/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Aug/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Sept/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Aug/01/2024",
|
||||
color: false),
|
||||
listItemWidget(
|
||||
text1: "Health Report and data",
|
||||
text3: "Sept/01/2024",
|
||||
color: false),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget listHeading() {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
bottom: BorderSide(color: CustomAppColors.kSmokeColor),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(right: 0, top: 10, bottom: 10),
|
||||
child: const CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: "All Documents",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(right: 0, top: 10, bottom: 10),
|
||||
child: CustomTextWidget(
|
||||
text: "+ Add New",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightGreyColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget listItemWidget(
|
||||
{required String text1, required String text3, required bool color}) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color ? CustomAppColors.kBlueColor.withAlpha(20) : null,
|
||||
border: const Border(
|
||||
top: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
bottom: BorderSide(color: CustomAppColors.kSmokeColor),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
const CustomImageWidget(imagePath: AssetsManager.kFolderIcon),
|
||||
SizedBox(
|
||||
width: 5.sp,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5,
|
||||
),
|
||||
child: CustomTextWidget(
|
||||
text: text1,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 11.sp,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10, left: 3),
|
||||
child: CustomTextWidget(
|
||||
text: text3,
|
||||
fontSize: 11.sp,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildDetailSingleItem extends StatelessWidget {
|
||||
const BuildDetailSingleItem({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 52.h,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 5.w),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text: '$title: ',
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
fontSize: 12.sp),
|
||||
const Spacer(),
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: value,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
fontSize:
|
||||
title.toLowerCase().contains("email") ? 11.sp : 13.sp),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/documents_list_model.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/edit_icon.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/clientsListing/widgets/search_bar_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DocumentsListScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const DocumentsListScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<DocumentsListScreen> createState() => _DocumentsListScreenState();
|
||||
}
|
||||
|
||||
class _DocumentsListScreenState extends State<DocumentsListScreen> {
|
||||
late final DocumentsListScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(DocumentsListScreenController(widget.userData));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
appBar: _appBar(context),
|
||||
body: Column(
|
||||
children: [
|
||||
SearchBarWidget(
|
||||
controller: controller.searchTEC,
|
||||
onSearchTextChange: controller.onSearch,
|
||||
),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() {
|
||||
return controller.documentsList.isEmpty
|
||||
? FrequentFunctions.centerText(text: "No data found")
|
||||
: listView();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: "Documents",
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () async {
|
||||
dynamic response = await Navigator.pushNamed(
|
||||
context, CustomRouteNames.kAddNewDocumentScreenRoute,
|
||||
arguments: controller.serviceUser.value);
|
||||
if (response is DocumentModel) {
|
||||
controller.documentsList.insert(0, response);
|
||||
controller.documentsList.refresh();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _tableHeading(String text) {
|
||||
return TableCell(
|
||||
child: Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget listView() {
|
||||
return InteractiveViewer(
|
||||
constrained: false,
|
||||
scaleEnabled: false,
|
||||
child: SizedBox(
|
||||
width: Get.width + 100.r,
|
||||
child: Table(
|
||||
border: TableBorder.all(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
columnWidths: const <int, TableColumnWidth>{
|
||||
0: FlexColumnWidth(30.2),
|
||||
1: FlexColumnWidth(35.0),
|
||||
2: FlexColumnWidth(25.0),
|
||||
// 3: FlexColumnWidth(15.0),
|
||||
},
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
_tableHeading("Document Name"),
|
||||
_tableHeading("Details"),
|
||||
_tableHeading("Date"),
|
||||
// _tableHeading("Actions"),
|
||||
],
|
||||
),
|
||||
...controller.documentsList
|
||||
.map((e) => tableRow(controller.documentsList.indexOf(e), e))
|
||||
.toList()
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TableRow tableRow(index, DocumentModel e) {
|
||||
return TableRow(
|
||||
decoration: BoxDecoration(
|
||||
color: controller.documentsList.indexOf(e) % 2 == 0
|
||||
? CustomAppColors.kLightGreyColor.withOpacity(0.25)
|
||||
: Colors.white),
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: REdgeInsets.symmetric(vertical: 8.0, horizontal: 12),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const CustomImageWidget(imagePath: AssetsManager.kFolderIcon),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: CustomTextWidget(
|
||||
text: e.title,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 11.sp,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: REdgeInsets.symmetric(vertical: 8.0, horizontal: 12),
|
||||
child: CustomTextWidget(
|
||||
text: e.details,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 11.sp,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: REdgeInsets.symmetric(vertical: 8.0, horizontal: 12),
|
||||
child: CustomTextWidget(
|
||||
text: DateFormat("MMM/dd/yyyy").format(
|
||||
DateTime.tryParse(e.createdAt)?.toLocal() ?? DateTime.now()),
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 11.sp,
|
||||
isExpanded: false,
|
||||
),
|
||||
),
|
||||
// Padding(
|
||||
// padding: REdgeInsets.symmetric(vertical: 8.0, horizontal: 12),
|
||||
// child: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// EditIcon(
|
||||
// onTap: () => _onEditTap(index, e),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// )
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// _onEditTap(int index, documentModel) async {
|
||||
// var response = await Navigator.pushNamed(
|
||||
// context, CustomRouteNames.kAddNewDocumentScreenRoute,
|
||||
// arguments: [documentModel, controller.serviceUser()]);
|
||||
// if (response is DocumentModel) {
|
||||
// // int index = controller.documentsList.value.documentList.indexWhere((item) => item == documentModel);
|
||||
// controller.documentsList[index]
|
||||
// ..title = response.title
|
||||
// ..details = response.details
|
||||
// ..docPath = response.docPath;
|
||||
// controller.documentsList.refresh();
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
22
lib/view/screens/clients/export_clients_module.dart
Normal file
22
lib/view/screens/clients/export_clients_module.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
export '../clientsListing/clients_list_screen.dart';
|
||||
export 'client_profile_screen.dart';
|
||||
export 'appointments_screen.dart';
|
||||
export 'notes_screen.dart';
|
||||
export 'select_note_screen.dart';
|
||||
export 'new_note_screen.dart';
|
||||
export 'care_plan_menu_screen.dart';
|
||||
export 'documentsList/documents_list_screen.dart';
|
||||
export 'document_details_screen.dart';
|
||||
export 'recent_incidents_screen.dart';
|
||||
export 'currentHealthIssues/current_health_issues_screen.dart';
|
||||
export 'consent_and_capacity_add_new_form_screen.dart';
|
||||
export 'consent_and_capacity_questionnaire_screen.dart';
|
||||
export 'life_history_and_goals_screen.dart';
|
||||
export 'risk_assessments_screen.dart';
|
||||
export 'pbs_plan_screen.dart';
|
||||
export 'photo_gallery_screen.dart';
|
||||
export 'risk_assessments_template_screen.dart';
|
||||
export 'clients_new_view_module/export_client_new_view.dart';
|
||||
export 'care_notes_screen.dart';
|
||||
export 'care_notes_subcategories_screen.dart';
|
||||
export 'careNoteForms/export_care_note_forms.dart';
|
||||
151
lib/view/screens/clients/life_history_and_goals_screen.dart
Normal file
151
lib/view/screens/clients/life_history_and_goals_screen.dart
Normal file
@@ -0,0 +1,151 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/clients/export_clients_controllers.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class LifeHistoryAndGoalsScreen extends StatefulWidget {
|
||||
const LifeHistoryAndGoalsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LifeHistoryAndGoalsScreen> createState() => _LifeHistoryAndGoalsScreenState();
|
||||
}
|
||||
|
||||
class _LifeHistoryAndGoalsScreenState extends State<LifeHistoryAndGoalsScreen> {
|
||||
|
||||
LifeHistoryAndGoalsScreenController controller = Get.put(LifeHistoryAndGoalsScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'Life History & Goals ',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(text: "Questionnaire",isExpanded: false,fontWeight: FontWeight.w600,fontSize: 14.sp,textAlign: TextAlign.left,alignment: Alignment.topLeft),
|
||||
SizedBox(height: 22.h),
|
||||
LifeHistoryQuestionCard(imagePath: AssetsManager.kManImagePng,name: "Leo Hurwitz",question: "Q: If there was one thing you could change about your health, what would it be?",date: "Aug/02/2023/7:30pm"),
|
||||
LifeHistoryAnswerCard(imagePath: AssetsManager.kPersonMainIcon,name: "Leo Hurwitz",answer: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",date: "Aug/02/2023/7:30pm"),
|
||||
LifeHistoryQuestionCard(imagePath: AssetsManager.kManImagePng,name: "Leo Hurwitz",question: "Q: If there was one thing you could change about your health, what would it be?",date: "Aug/02/2023/7:30pm"),
|
||||
LifeHistoryAnswerCard(imagePath: AssetsManager.kPersonMainIcon,name: "Leo Hurwitz",answer: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",date: "Aug/02/2023/7:30pm"),
|
||||
LifeHistoryQuestionCard(imagePath: AssetsManager.kManImagePng,name: "Leo Hurwitz",question: "Q: If there was one thing you could change about your health, what would it be?",date: "Aug/02/2023/7:30pm"),
|
||||
LifeHistoryAnswerCard(imagePath: AssetsManager.kPersonMainIcon,name: "Leo Hurwitz",answer: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",date: "Aug/02/2023/7:30pm"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LifeHistoryQuestionCard extends StatelessWidget {
|
||||
const LifeHistoryQuestionCard({
|
||||
super.key, required this.imagePath, required this.name, required this.question, required this.date,
|
||||
});
|
||||
|
||||
final String imagePath;
|
||||
final String name;
|
||||
final String question;
|
||||
final String date;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomImageWidget(imagePath: imagePath,width: 32.w,height: 32.h,),
|
||||
SizedBox(width: 12.w,),
|
||||
CustomTextWidget(text: name,isExpanded: false),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(text: question,isExpanded: false,fontWeight: FontWeight.bold,textAlign: TextAlign.left,alignment: Alignment.centerLeft,fontSize: 14.sp),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(text: date,isExpanded: false,textAlign: TextAlign.left,alignment: Alignment.centerLeft,fontSize: 12.sp),
|
||||
SizedBox(height: 24.h),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LifeHistoryAnswerCard extends StatelessWidget {
|
||||
const LifeHistoryAnswerCard({
|
||||
super.key, required this.imagePath, required this.name, required this.answer, required this.date,
|
||||
});
|
||||
|
||||
final String imagePath;
|
||||
final String name;
|
||||
final String answer;
|
||||
final String date;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomImageWidget(imagePath: imagePath,width: 32.w,height: 32.h,),
|
||||
SizedBox(width: 12.w,),
|
||||
CustomTextWidget(text: name,isExpanded: false),
|
||||
const Spacer(),
|
||||
CustomImageWidget(imagePath: AssetsManager.kPencilOutlineIcon,width: 14.w,height: 14.h,),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
const TextSpan(
|
||||
text: 'A: ',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextSpan(style: TextStyle(fontSize: 14.sp,color: CustomAppColors.kBlackColor.withAlpha(180),),text: answer),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
CustomTextWidget(text: date,isExpanded: false,textAlign: TextAlign.left,alignment: Alignment.centerLeft,fontSize: 12.sp),
|
||||
SizedBox(height: 24.h),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
364
lib/view/screens/clients/new_note_screen.dart
Normal file
364
lib/view/screens/clients/new_note_screen.dart
Normal file
@@ -0,0 +1,364 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class NewNoteScreen extends StatefulWidget {
|
||||
const NewNoteScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<NewNoteScreen> createState() => _NewNoteScreenState();
|
||||
}
|
||||
|
||||
class _NewNoteScreenState extends State<NewNoteScreen> {
|
||||
NewNoteScreenController controller = Get.put(NewNoteScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: 'New Note for ${controller.user.name}',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18.w),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20.h,bottom: 15.h),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
minLines: 1,
|
||||
maxLines: 1,
|
||||
controller: controller.titleController,
|
||||
hintText: ConstantText.kTypeTitle,
|
||||
heading: ConstantText.kTitle,
|
||||
onChange: (_){},
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 15.0.h),
|
||||
child: const UploadWidget(),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(right: 7.5.w),
|
||||
child: const FlagWidget(text1: "Flag",text2: "Choose Flag",flagIcon: AssetsManager.kFlagIcon),
|
||||
)),
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(left: 7.5.w),
|
||||
child: const FlagWidget(text1: "Red Flag: How long?",text2: "Choose",chooseIcon: AssetsManager.kClockIcon),
|
||||
)),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20.h,bottom: 15.h),
|
||||
child: CustomTextFieldWidget(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderColor: CustomAppColors.kLightGreyColor,
|
||||
borderWidth: 1.0.sp,
|
||||
maxLines: 6,
|
||||
minLines: 6,
|
||||
controller: controller.titleController,
|
||||
hintText: ConstantText.kTypeTitle,
|
||||
heading: ConstantText.kTitle,
|
||||
onChange: (_){},
|
||||
bottomChild: Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 10.0.w,bottom: 10.h),
|
||||
child: InkWell(
|
||||
onTap: () {},
|
||||
child: const CustomImageWidget(
|
||||
imagePath:AssetsManager.kMicIcon,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const TitleWidget(
|
||||
text1: "Link Note (Optional)",
|
||||
text2: "Choose",
|
||||
showDropDownButton: true,
|
||||
showSwitchButton: false),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 15.0.h),
|
||||
child: const TitleWidget(
|
||||
text1: "Handover To (Optional)",
|
||||
text2: "Choose",
|
||||
showDropDownButton: true,
|
||||
showSwitchButton: false),
|
||||
),
|
||||
const TitleWidget(
|
||||
text1: "Notify Management?",
|
||||
text2: "No",
|
||||
showDropDownButton: false,
|
||||
showSwitchButton: true),
|
||||
// const SubmitButtonWidget(
|
||||
// text: "Submit",
|
||||
// buttonColor: CustomAppColors.kSecondaryColor,
|
||||
// textColor: CustomAppColors.kPrimaryColor,
|
||||
// ),
|
||||
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 15.h,
|
||||
bottom: Platform.isIOS ? 30.0.h : 20.0.h,
|
||||
),
|
||||
child: CustomAppButton(
|
||||
buttonText: ConstantText.kSubmit.toUpperCase(),
|
||||
buttonColor: CustomAppColors.kSecondaryColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: (){},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UploadWidget extends StatelessWidget {
|
||||
const UploadWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
// height: 50,
|
||||
padding: EdgeInsets.symmetric(vertical: 12.h,),
|
||||
// margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.r)),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kUploadIcon,
|
||||
height: 24.h,
|
||||
width: 24.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Upload Image",
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TitleWidget extends StatelessWidget {
|
||||
const TitleWidget({
|
||||
super.key,
|
||||
required this.text1,
|
||||
required this.text2,
|
||||
required this.showDropDownButton,
|
||||
required this.showSwitchButton,
|
||||
});
|
||||
|
||||
final String text1;
|
||||
final String text2;
|
||||
final bool showDropDownButton;
|
||||
final bool showSwitchButton;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
padding: EdgeInsets.all(10.sp,),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.r)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: text1,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
isExpanded: false),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: text2,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
isExpanded: false),
|
||||
showDropDownButton
|
||||
? const Icon(Icons.arrow_drop_down_outlined)
|
||||
: showSwitchButton
|
||||
? SizedBox(
|
||||
height: 20.h,
|
||||
width: 48.w,
|
||||
child: Switch(
|
||||
inactiveTrackColor: CustomAppColors.kPrimaryColor,
|
||||
activeTrackColor: CustomAppColors.kSecondaryColor,
|
||||
value: false,
|
||||
onChanged: (val) {}),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SubmitButtonWidget extends StatelessWidget {
|
||||
const SubmitButtonWidget({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.textColor,
|
||||
required this.buttonColor,
|
||||
this.borderColor,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final Color textColor;
|
||||
final Color buttonColor;
|
||||
final Color? borderColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
border: borderColor != null ? Border.all(color: borderColor!) : null,
|
||||
color: buttonColor,
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
),
|
||||
child: CustomTextWidget(
|
||||
text: text,
|
||||
fontColor: textColor,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FlagWidget extends StatelessWidget {
|
||||
const FlagWidget({
|
||||
super.key,
|
||||
required this.text1,
|
||||
required this.text2,
|
||||
this.flagIcon,
|
||||
this.chooseIcon,
|
||||
});
|
||||
|
||||
final String text1;
|
||||
final String text2;
|
||||
final String? flagIcon;
|
||||
final String? chooseIcon;
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 10.w,right: 10.w,top: 5.h,bottom: 5.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10.r)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 6.0.h),
|
||||
child: CustomTextWidget(
|
||||
text: text1,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
isExpanded: false),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
flagIcon!=null?
|
||||
CustomImageWidget(
|
||||
imagePath: flagIcon!,
|
||||
height: 18.66.h,
|
||||
width: 18.w,
|
||||
): Container(),
|
||||
|
||||
Expanded(
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
text: text2,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
isExpanded: false),
|
||||
),
|
||||
|
||||
chooseIcon!=null?
|
||||
CustomImageWidget(
|
||||
imagePath: chooseIcon!,
|
||||
height: 18.66.h,
|
||||
width: 18.w,
|
||||
): Container(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
209
lib/view/screens/clients/notes_screen.dart
Normal file
209
lib/view/screens/clients/notes_screen.dart
Normal file
@@ -0,0 +1,209 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class NotesScreen extends StatefulWidget {
|
||||
const NotesScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<NotesScreen> createState() => _NotesScreenState();
|
||||
}
|
||||
|
||||
class _NotesScreenState extends State<NotesScreen> {
|
||||
NotesScreenController controller =
|
||||
Get.put(NotesScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
controller.screenKey.currentContext!,
|
||||
CustomRouteNames.kNewNoteScreenRoute,
|
||||
);
|
||||
},
|
||||
shape: const CircleBorder(),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPlusIcon,
|
||||
height: 35.h,
|
||||
width: 35.w,
|
||||
imageColor: CustomAppColors.kSecondaryColor,
|
||||
),
|
||||
),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 15.w,),
|
||||
CustomTextWidget(
|
||||
text: 'Notes for ${controller.user.name}',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
height: 40,
|
||||
margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(40.r)),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, CustomRouteNames.kSelectNoteScreenRoute);
|
||||
}, icon: const Icon(Icons.search)),
|
||||
CustomTextWidget(
|
||||
text: "Search...",
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 1.2,
|
||||
child: ListView.builder(
|
||||
itemCount: controller.users.length + 1,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return index < controller.users.length
|
||||
? NotesRoundOutlinedBox(
|
||||
context: context,
|
||||
child: BuildNotesList(
|
||||
history: controller.user.aboutPatient,
|
||||
date: controller.user.diagnosisDate,
|
||||
userName: controller.users[index],
|
||||
),
|
||||
)
|
||||
: SizedBox(height: 60.h,);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotesRoundOutlinedBox extends StatelessWidget {
|
||||
const NotesRoundOutlinedBox({
|
||||
super.key,
|
||||
required this.context,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final BuildContext context;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
|
||||
alignment: Alignment.centerLeft,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
margin: EdgeInsets.symmetric(horizontal: 25.w,vertical: 5.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 13.sp,vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor),
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildNotesList extends StatelessWidget {
|
||||
const BuildNotesList({
|
||||
super.key,
|
||||
required this.date,
|
||||
required this.history, required this.userName,
|
||||
});
|
||||
|
||||
final String date;
|
||||
final String history;
|
||||
final String userName;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: 'Note Title',
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: date,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: history,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8.0.h),
|
||||
child: Row(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 18.h,
|
||||
width: 18.w,
|
||||
),
|
||||
SizedBox(width: 8.w,),
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
text: userName,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
192
lib/view/screens/clients/pbs_plan_screen.dart
Normal file
192
lib/view/screens/clients/pbs_plan_screen.dart
Normal file
@@ -0,0 +1,192 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/PBSPlanModel.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/clients/clients_new_view_module/add_new_pbs_plan_screen.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class PBSPlanScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const PBSPlanScreen({Key? key, required this.userData}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<PBSPlanScreen> createState() => _PBSPlanScreenState();
|
||||
}
|
||||
|
||||
class _PBSPlanScreenState extends State<PBSPlanScreen> {
|
||||
final controller = Get.put(PBSPlanScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUser.value = widget.userData;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
// onBackButton: () => controller.onBackPress(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
// sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: _appBar(context),
|
||||
body: Column(
|
||||
children: [
|
||||
// SearchBarWidget(onSearchTextChange: (_) {}),
|
||||
Expanded(child: Obx(() {
|
||||
if (controller.pbsList.isEmpty) {
|
||||
return FrequentFunctions.centerText(text: "No data found");
|
||||
}
|
||||
|
||||
return listView(controller.pbsList());
|
||||
})),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: "PBS Plan",
|
||||
actionText: '+ Add Form',
|
||||
onActionTap: _onAddNewTap,
|
||||
);
|
||||
}
|
||||
|
||||
Widget listView(List<PbsList> list) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kLightGreyColor)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 16.0, vertical: 12),
|
||||
child: Text(
|
||||
"Staff Member",
|
||||
style: TextStyle(
|
||||
color: CustomAppColors.kBlackColor,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.separated(
|
||||
itemCount: list.length,
|
||||
separatorBuilder: (_, index) => Divider(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
height: 1,
|
||||
),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
// listItemTap(index, list[index]);
|
||||
},
|
||||
child: listItem(index: index, data: list[index]),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget listItem({required int index, required PbsList data}) {
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kAddNewPBSPlanScreenRoute,
|
||||
arguments: AddNewPBSPlanScreenArgs(
|
||||
userData: widget.userData, pbsData: data, viewOnly: true),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: REdgeInsets.symmetric(vertical: 9, horizontal: 16),
|
||||
color: index % 2 == 0
|
||||
? CustomAppColors.kLightGreyColor.withOpacity(0.1)
|
||||
: Colors.white,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
MyCircleImage(
|
||||
imageSize: 53.r,
|
||||
url: "${WebUrls.baseUrl}${data.staffId?.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
imageColor: CustomAppColors.kDarkBlueTextColor,
|
||||
height: 53.r,
|
||||
width: 53.r,
|
||||
),
|
||||
),
|
||||
12.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
data.staffId?.name ?? "",
|
||||
style: TextStyle(
|
||||
color: CustomAppColors.kDarkBlueTextColor,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
(data.createdAt.isNullOrEmpty())
|
||||
? FrequentFunctions.noWidget
|
||||
: Text(
|
||||
DateFormatter.ddMMyyyyhhmmFormat(
|
||||
DateTime.parse(data.createdAt).toLocal()),
|
||||
style: TextStyle(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// EditIcon(onTap: () async {
|
||||
// dynamic res = await Navigator.pushNamed(
|
||||
// context, CustomRouteNames.kAddNewPBSPlanScreenRoute,
|
||||
// arguments: AddNewPBSPlanScreenArgs(
|
||||
// userData: widget.userData, pbsData: data));
|
||||
// if (res == true) {
|
||||
// controller.fetchPBSPlanList();
|
||||
// }
|
||||
// }),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_onAddNewTap() async {
|
||||
dynamic res = await Navigator.pushNamed(
|
||||
controller.screenKey.currentContext!,
|
||||
CustomRouteNames.kAddNewPBSPlanScreenRoute,
|
||||
arguments: AddNewPBSPlanScreenArgs(
|
||||
userData: widget.userData,
|
||||
));
|
||||
if (res == true) {
|
||||
controller.fetchPBSPlanList();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
234
lib/view/screens/clients/photo_gallery_screen.dart
Normal file
234
lib/view/screens/clients/photo_gallery_screen.dart
Normal file
@@ -0,0 +1,234 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/memoryListResponse/MemoryListData.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_network_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:video_thumbnail/video_thumbnail.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import 'addEditMemoryBox/add_edit_memory_box_screen.dart';
|
||||
|
||||
class PhotoGalleryScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const PhotoGalleryScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<PhotoGalleryScreen> createState() => _PhotoGalleryScreenState();
|
||||
}
|
||||
|
||||
class _PhotoGalleryScreenState extends State<PhotoGalleryScreen> {
|
||||
final controller = Get.put(PhotoGalleryScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller.serviceUserId = widget.userData.id!;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
// sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: _appBar(context),
|
||||
body: SafeArea(child: Obx(() {
|
||||
if (controller.memoryList.isEmpty) {
|
||||
return FrequentFunctions.centerText(text: "No data found");
|
||||
}
|
||||
|
||||
return listView(controller.memoryList());
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: 'Photo Gallery',
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () async {
|
||||
final result = await _gotoAddEditMemoryBoxScreen();
|
||||
|
||||
if (result == true) {
|
||||
controller.getMemoryList();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
listView(List<MemoryListData> list) {
|
||||
return ListView.separated(
|
||||
itemCount: list.length,
|
||||
padding: REdgeInsets.symmetric(horizontal: 16),
|
||||
separatorBuilder: (_, index) => 12.verticalSpace,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return listItem(index: index, data: list[index]);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget listItem({required int index, required MemoryListData data}) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
_gotoAddEditMemoryBoxScreen(data, true);
|
||||
},
|
||||
child: Container(
|
||||
height: 130.h,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor),
|
||||
borderRadius: 16.toRadius(),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
borderRadius:
|
||||
const BorderRadius.horizontal(left: Radius.circular(16)),
|
||||
),
|
||||
child: (data.filePath.isNullOrEmpty())
|
||||
? const Center(
|
||||
child: Icon(Icons.image_not_supported_outlined),
|
||||
)
|
||||
: (data.filePath!.isImageFileName)
|
||||
? MyNetworkImage(
|
||||
url: WebUrls.baseUrl + data.filePath!,
|
||||
fit: BoxFit.cover,
|
||||
errorWidget: const Icon(
|
||||
Icons.image_not_supported_outlined,
|
||||
color: Colors.black,
|
||||
),
|
||||
)
|
||||
: FutureBuilder(
|
||||
future: VideoThumbnail.thumbnailFile(
|
||||
video: WebUrls.baseUrl + data.filePath!,
|
||||
imageFormat: ImageFormat.WEBP,
|
||||
maxHeight: 150,
|
||||
quality: 75,
|
||||
),
|
||||
builder: (_, snap) {
|
||||
if (snap.connectionState ==
|
||||
ConnectionState.waiting) {
|
||||
return Center(
|
||||
child: SizedBox.square(
|
||||
dimension: 32.r,
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (snap.connectionState ==
|
||||
ConnectionState.done) {
|
||||
if (snap.data != null) {
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Image.file(
|
||||
File(snap.data!),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 2,
|
||||
spreadRadius: 2,
|
||||
color: Colors.black
|
||||
.withOpacity(0.2)),
|
||||
],
|
||||
),
|
||||
child: Icon(
|
||||
Icons.play_circle_outline_rounded,
|
||||
color: Colors.white,
|
||||
size: 32.r,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return FrequentFunctions.noWidget;
|
||||
}),
|
||||
),
|
||||
),
|
||||
12.horizontalSpace,
|
||||
Expanded(
|
||||
flex: 8,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: data.note ?? "",
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
8.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: "Staff Member: ${data.addedBy?.name ?? ""}",
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
],
|
||||
).addPaddingVertical(12),
|
||||
),
|
||||
// EditIcon(
|
||||
// onTap: () async {
|
||||
// final result = await _gotoAddEditMemoryBoxScreen(data);
|
||||
//
|
||||
// if (result == true) {
|
||||
// controller.getMemoryList();
|
||||
// }
|
||||
// },
|
||||
// ).addPaddingVertical(12),
|
||||
// 12.horizontalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future _gotoAddEditMemoryBoxScreen([data, bool viewOnly = false]) async {
|
||||
final res = await Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kAddEditMemoryBoxScreen,
|
||||
arguments: AddEditMemoryBoxScreenArgs(
|
||||
userData: widget.userData,
|
||||
data: data,
|
||||
viewOnly: viewOnly,
|
||||
),
|
||||
);
|
||||
|
||||
if (res == true) {
|
||||
controller.getMemoryList();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
185
lib/view/screens/clients/recent_incidents_screen.dart
Normal file
185
lib/view/screens/clients/recent_incidents_screen.dart
Normal file
@@ -0,0 +1,185 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/app_dialogs.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/recent_incidents_model.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/edit_icon.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/clientsListing/widgets/search_bar_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import 'add_new_recent_incident_screen.dart';
|
||||
|
||||
class RecentIncidentsScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const RecentIncidentsScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<RecentIncidentsScreen> createState() => _RecentIncidentsScreenState();
|
||||
}
|
||||
|
||||
class _RecentIncidentsScreenState extends State<RecentIncidentsScreen> {
|
||||
late final RecentIncidentsScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller = Get.put(RecentIncidentsScreenController(widget.userData));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
// onBackButton: () => controller.onBackPress(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
// sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: _appBar(context),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
8.verticalSpace,
|
||||
SearchBarWidget(
|
||||
controller: controller.searchTEC,
|
||||
onSearchTextChange: controller.onSearch,
|
||||
),
|
||||
8.verticalSpace,
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => controller.recentIncidentsList.isEmpty
|
||||
? FrequentFunctions.centerText(text: "No data found")
|
||||
: ListView.separated(
|
||||
itemCount: controller.recentIncidentsList.length,
|
||||
separatorBuilder: (_, index) => 12.verticalSpace,
|
||||
padding: REdgeInsets.symmetric(horizontal: 20.r),
|
||||
itemBuilder: (_, int index) {
|
||||
return RecentIncidentTile(
|
||||
data: controller.recentIncidentsList[index],
|
||||
onTap: () {
|
||||
AppDialog.showRecentIncidentDetailDialog(
|
||||
data: controller.recentIncidentsList[index]);
|
||||
},
|
||||
onEdit: () async {
|
||||
dynamic result = await Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames
|
||||
.kAddNewRecentIncidentsScreenRoute,
|
||||
arguments: AddNewRecentIncidentsScreenArgs(
|
||||
incidentsModel: controller
|
||||
.recentIncidentsList[index]));
|
||||
|
||||
if (result is RecentIncidentsModel) {
|
||||
controller.recentIncidentsList
|
||||
.replaceRange(index, index + 1, [result]);
|
||||
controller.recentIncidentsList.refresh();
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: "Recent Incidents",
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () async {
|
||||
dynamic result = await Navigator.pushNamed(
|
||||
context, CustomRouteNames.kAddNewRecentIncidentsScreenRoute,
|
||||
arguments: AddNewRecentIncidentsScreenArgs(
|
||||
userId: controller.serviceUser()!.id!));
|
||||
if (result is RecentIncidentsModel) {
|
||||
controller.recentIncidentsList.insert(0, result);
|
||||
controller.recentIncidentsList = controller.recentIncidentsList;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class RecentIncidentTile extends StatelessWidget {
|
||||
final RecentIncidentsModel data;
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback onEdit;
|
||||
|
||||
const RecentIncidentTile({
|
||||
super.key,
|
||||
required this.data,
|
||||
required this.onTap,
|
||||
required this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
padding: EdgeInsets.symmetric(horizontal: 13.sp, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor),
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextWidget(
|
||||
text: data.incidentTitle.isNotEmpty
|
||||
? data.incidentTitle
|
||||
: "Untitled Incident",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.left,
|
||||
fontColor: CustomAppColors.kSecondaryColor,
|
||||
),
|
||||
),
|
||||
// 8.horizontalSpace,
|
||||
// EditIcon(onTap: onEdit),
|
||||
],
|
||||
),
|
||||
Text.rich(TextSpan(children: [
|
||||
TextSpan(
|
||||
text: "Incident Date - Time : ",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12.sp,
|
||||
color: Colors.black,
|
||||
)),
|
||||
TextSpan(
|
||||
text: DateFormatter.ddMMyyyyhhmmFormat(
|
||||
DateTime.fromMillisecondsSinceEpoch(data.incidentDate)
|
||||
.toLocal()),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12.sp,
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
)),
|
||||
])),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
258
lib/view/screens/clients/risk_assessments_screen.dart
Normal file
258
lib/view/screens/clients/risk_assessments_screen.dart
Normal file
@@ -0,0 +1,258 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class RiskAssessmentsScreen extends StatefulWidget {
|
||||
const RiskAssessmentsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<RiskAssessmentsScreen> createState() => _RiskAssessmentsScreenState();
|
||||
}
|
||||
|
||||
class _RiskAssessmentsScreenState extends State<RiskAssessmentsScreen> {
|
||||
RiskAssessmentsScreenController controller = Get.put(RiskAssessmentsScreenController());
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
// sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 15.w,),
|
||||
CustomTextWidget(
|
||||
text: 'Risk Assessments',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
// await Navigator.pushNamed(
|
||||
// controller.screenKey.currentContext!,
|
||||
// CustomRouteNames.kNewNoteScreenRoute,
|
||||
// );
|
||||
},
|
||||
child: CustomTextWidget(
|
||||
text: '+ Add New',
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
body: Container(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
height: 40,
|
||||
margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(5.r)),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {}, icon: const Icon(Icons.search)),
|
||||
CustomTextWidget(
|
||||
text: "Search...",
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
// onTap: () {
|
||||
// Navigator.pushNamed(
|
||||
// controller.screenKey.currentContext!,
|
||||
// CustomRouteNames.kDocumentDetailsScreenRoute,
|
||||
// );
|
||||
// },
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
raListHeading(),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "High",text3: "Aug/01/2024",color: true),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "Low",text3: "Sept/01/2024",color: false),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "Medium",text3: "Aug/01/2024",color: true),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "High",text3: "Sept/01/2024",color: false),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "Low",text3: "Aug/01/2024",color: true),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "High",text3: "Sept/01/2024",color: false),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "Low",text3: "Aug/01/2024",color: true),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "Medium",text3: "Sept/01/2024",color: false),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "High",text3: "Aug/01/2024",color: true),
|
||||
raListItemWidget(text1: "Jaylon George",text2: "Low",text3: "Sept/01/2024",color: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
Widget raListHeading() {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
bottom: BorderSide(color: CustomAppColors.kSmokeColor),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
// decoration: const BoxDecoration(
|
||||
// border: Border(
|
||||
// right: BorderSide(
|
||||
// color: CustomAppColors.kSmokeColor,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
padding: const EdgeInsets.only(right: 0, top: 10, bottom: 10),
|
||||
child: CustomTextWidget(
|
||||
text: "Service User",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 2.w,
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
width: 2.w
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(right: 0, top: 10, bottom: 10),
|
||||
child: CustomTextWidget(
|
||||
text: "Risk",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget raListItemWidget({required String text1,required String text2,required String text3,required bool color, Color? centerBorderColor}) {
|
||||
return InkWell(
|
||||
onTap: (){
|
||||
Navigator.pushNamed(context, CustomRouteNames.kRiskAssessmentsTemplateScreenRoute);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 3.w,left: 10.w),
|
||||
height: 50.h,
|
||||
decoration: BoxDecoration(
|
||||
color: color ? CustomAppColors.kBlueColor.withAlpha(20) : null,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
bottom: BorderSide(color: CustomAppColors.kSmokeColor),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
CustomImageWidget(imagePath: AssetsManager.kManImagePng,width: 24.w,height: 24.h),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(left: 5,),
|
||||
child: CustomTextWidget(
|
||||
text: text1,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 11.sp,
|
||||
isExpanded: false,),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 2.w,
|
||||
color: text2.toLowerCase() == "low"
|
||||
? CustomAppColors.kDarkGreenColor
|
||||
: text2.toLowerCase() == "medium"
|
||||
? CustomAppColors.kYellowColor
|
||||
: text2.toLowerCase() == "high"
|
||||
? CustomAppColors.kDarkRedColor
|
||||
: centerBorderColor ?? CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 10.h, bottom: 10.h,left: 12.w,right: 19.w),
|
||||
child: CustomTextWidget(
|
||||
text: text2,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
isExpanded: false,),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
383
lib/view/screens/clients/risk_assessments_template_screen.dart
Normal file
383
lib/view/screens/clients/risk_assessments_template_screen.dart
Normal file
@@ -0,0 +1,383 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/clients/riskAssessmentResponse/RiskAssessmentData.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/custom_app_bar_with_action.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import 'addEditRiskAssessment/add_edit_risk_assessment_screen.dart';
|
||||
|
||||
class RiskAssessmentsTemplateScreen extends StatefulWidget {
|
||||
final UserData userData;
|
||||
|
||||
const RiskAssessmentsTemplateScreen({Key? key, required this.userData})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<RiskAssessmentsTemplateScreen> createState() =>
|
||||
_RiskAssessmentsTemplateScreenState();
|
||||
}
|
||||
|
||||
class _RiskAssessmentsTemplateScreenState
|
||||
extends State<RiskAssessmentsTemplateScreen> {
|
||||
late final RiskAssessmentsTemplateScreenController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
controller =
|
||||
Get.put(RiskAssessmentsTemplateScreenController(widget.userData.id!));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
appBar: _appBar(context),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: Column(
|
||||
children: [
|
||||
serviceUserDetailWidget(),
|
||||
16.verticalSpace,
|
||||
Expanded(child: Obx(() {
|
||||
return controller.list.isEmpty
|
||||
? FrequentFunctions.centerText(text: "No data found")
|
||||
: listView();
|
||||
})),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
AppBar _appBar(BuildContext context) {
|
||||
return CustomAppBarWithAction(
|
||||
context,
|
||||
titleText: 'Risk Assessments Template',
|
||||
actionText: '+ Add New',
|
||||
onActionTap: () async {
|
||||
final result = await Navigator.pushNamed(
|
||||
context, CustomRouteNames.kAddEditRiskAssessmentScreen,
|
||||
arguments: AddEditRiskAssessmentScreenArgs(
|
||||
userData: widget.userData,
|
||||
));
|
||||
if (result == true) {
|
||||
controller.getRiskAssessments();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget serviceUserDetailWidget() {
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 10),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url:
|
||||
"${WebUrls.baseUrl}${widget.userData.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 53.r,
|
||||
width: 53.r,
|
||||
),
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: widget.userData.displayName,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
32.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _labelValueWidgets(
|
||||
'Email:',
|
||||
widget.userData.email ?? "",
|
||||
),
|
||||
)),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _labelValueWidgets(
|
||||
'Contact Number:',
|
||||
widget.userData.modelId?.phoneNo ?? "",
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
..._labelValueWidgets(
|
||||
'Address 1:',
|
||||
widget.userData.modelId?.suAddress1 ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
..._labelValueWidgets(
|
||||
'Address 2:',
|
||||
widget.userData.modelId?.suAddress2 ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _labelValueWidgets(String label, String value) {
|
||||
return [
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
text: label,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
fontSize: 12.sp),
|
||||
4.verticalSpace,
|
||||
CustomTextWidget(
|
||||
textAlign: TextAlign.left,
|
||||
text: value,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
fontSize: 13.sp),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _tableHeading(String text) {
|
||||
return TableCell(
|
||||
child: Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget listView() {
|
||||
return InteractiveViewer(
|
||||
constrained: false,
|
||||
scaleEnabled: false,
|
||||
child: Table(
|
||||
border: TableBorder.all(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
columnWidths: <int, TableColumnWidth>{
|
||||
0: FixedColumnWidth(200.r),
|
||||
1: FixedColumnWidth(300.r),
|
||||
2: FixedColumnWidth(300.r),
|
||||
3: FixedColumnWidth(250.r),
|
||||
4: FixedColumnWidth(400.r),
|
||||
5: FixedColumnWidth(250.r),
|
||||
6: FixedColumnWidth(250.r),
|
||||
},
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
_tableHeading("Hazard"),
|
||||
_tableHeading("Person (s) exposed to Hazard"),
|
||||
_tableHeading("Risk Identified"),
|
||||
_splitColumn("Pure Risk Rating", splitCells: [
|
||||
_splitCellExpanded("C", borderRight: true),
|
||||
_splitCellExpanded("L", borderRight: true),
|
||||
_splitCellExpanded("R"),
|
||||
]),
|
||||
_tableHeading("Control Measures Required"),
|
||||
_splitColumn("In Place", splitCells: [
|
||||
_splitCellExpanded("Y", borderRight: true),
|
||||
_splitCellExpanded("N"),
|
||||
]),
|
||||
_splitColumn("Residual Risk Rating", splitCells: [
|
||||
_splitCellExpanded("C", borderRight: true),
|
||||
_splitCellExpanded("L", borderRight: true),
|
||||
_splitCellExpanded("R"),
|
||||
]),
|
||||
],
|
||||
),
|
||||
...controller.list
|
||||
.map((e) => tableRow(controller.list.indexOf(e), e))
|
||||
.toList()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _splitColumn(String heading, {List<Widget> splitCells = const []}) {
|
||||
return TableCell(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: REdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
heading,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
Row(children: splitCells)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Expanded _splitCellExpanded(String text, {bool borderRight = false}) =>
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: REdgeInsets.all(8.0),
|
||||
alignment: Alignment.center,
|
||||
decoration: !borderRight
|
||||
? null
|
||||
: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
))),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
TableRow tableRow(index, RiskAssessmentData e) {
|
||||
return TableRow(
|
||||
decoration: BoxDecoration(
|
||||
color: controller.list.indexOf(e) % 2 == 0
|
||||
? CustomAppColors.kLightGreyColor.withOpacity(0.25)
|
||||
: Colors.white),
|
||||
children: <Widget>[
|
||||
_dataCell(e.hazard ?? ""),
|
||||
_dataCell(e.personsExposedToHazard ?? ""),
|
||||
_dataCell(e.riskIdentified ?? ""),
|
||||
|
||||
//Pure risk rating
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.pureRiskRating?.c ?? 0).toString(),
|
||||
borderRight: true,
|
||||
)),
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.pureRiskRating?.l ?? 0).toString(),
|
||||
borderRight: true,
|
||||
)),
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.pureRiskRating?.r ?? 0).toString(),
|
||||
borderLeft: true,
|
||||
borderColorLeft: getRatingColor(e.pureRiskRating?.r ?? 0),
|
||||
),
|
||||
),
|
||||
]),
|
||||
|
||||
_dataCell(e.coldMeasureRequired ?? ""),
|
||||
|
||||
//In Place
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.inPlace?.y ?? 0).toString(),
|
||||
borderRight: true,
|
||||
),
|
||||
),
|
||||
Expanded(child: _dataCell((e.inPlace?.n ?? 0).toString())),
|
||||
]),
|
||||
|
||||
//Residual Risk Rating
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.residualRiskRating?.c ?? 0).toString(),
|
||||
borderRight: true,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.residualRiskRating?.l ?? 0).toString(),
|
||||
borderRight: true,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _dataCell(
|
||||
(e.residualRiskRating?.r ?? 0).toString(),
|
||||
borderLeft: true,
|
||||
borderColorLeft: getRatingColor(e.residualRiskRating?.r ?? 0),
|
||||
),
|
||||
),
|
||||
]),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
//1-3 Green
|
||||
// 4-6 Yellow
|
||||
// 7-9 Red
|
||||
Color getRatingColor(int r) {
|
||||
if (r >= 0 && r <= 3) return Colors.green;
|
||||
if (r >= 4 && r <= 6) return Colors.amberAccent;
|
||||
if (r >= 7) return Colors.red;
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
Widget _dataCell(String text,
|
||||
{bool borderRight = false,
|
||||
bool borderLeft = false,
|
||||
Color borderColorLeft = Colors.transparent}) {
|
||||
return Container(
|
||||
height: 80.h,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
width: borderLeft ? 3.r : 0,
|
||||
color: borderColorLeft,
|
||||
),
|
||||
right: BorderSide(
|
||||
width: borderRight ? 1 : 0,
|
||||
color: CustomAppColors.kSmokeColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: REdgeInsets.symmetric(vertical: 8.0, horizontal: 12),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 11.sp,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
265
lib/view/screens/clients/select_note_screen.dart
Normal file
265
lib/view/screens/clients/select_note_screen.dart
Normal file
@@ -0,0 +1,265 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
|
||||
class SelectNoteScreen extends StatefulWidget {
|
||||
const SelectNoteScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SelectNoteScreen> createState() => _SelectNoteScreenState();
|
||||
}
|
||||
|
||||
class _SelectNoteScreenState extends State<SelectNoteScreen> {
|
||||
|
||||
SelectNoteScreenController controller = Get.put(SelectNoteScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
leadingButton: Container(),
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 15.w,),
|
||||
CustomTextWidget(
|
||||
text: 'Select Note',
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
await Navigator.pushNamed(
|
||||
controller.screenKey.currentContext!,
|
||||
CustomRouteNames.kNewNoteScreenRoute,
|
||||
);
|
||||
},
|
||||
child: CustomTextWidget(
|
||||
text: '+ Add New',
|
||||
isExpanded: false,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
height: 40,
|
||||
margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(40.r)),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {}, icon: const Icon(Icons.search)),
|
||||
CustomTextWidget(
|
||||
text: "Search...",
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
isExpanded: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20.w,right: 20.w),
|
||||
alignment: Alignment.topLeft,
|
||||
height: 60.h,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Choose Categories",
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
isExpanded: false),
|
||||
const SizedBox(height: 10,),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
const SelectCategoryWidget(selected: true),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 2"),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 3"),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 4"),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 5"),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 6"),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 7"),
|
||||
SizedBox(width: 5.w,),
|
||||
const SelectCategoryWidget(textOfButton: "Category 8"),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 25.w,top: 10),
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.topLeft,
|
||||
text: "Notes",
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
isExpanded: false),
|
||||
),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height/1.45,
|
||||
child: ListView.builder(
|
||||
itemCount: controller.users.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return NotesRoundOutlinedBox2(
|
||||
context: context,
|
||||
child: BuildNotesList2(
|
||||
history: controller.user.aboutPatient,
|
||||
date: controller.user.diagnosisDate,
|
||||
userName: controller.users[index],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SelectCategoryWidget extends StatelessWidget {
|
||||
const SelectCategoryWidget({
|
||||
super.key,this.selected,this.textOfButton
|
||||
});
|
||||
|
||||
final String? textOfButton;
|
||||
final bool? selected;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 5.w, right: 5.w, bottom: 3.h, top: 3.h),
|
||||
decoration: BoxDecoration(
|
||||
color: selected!=null? CustomAppColors.kSecondaryColor:CustomAppColors.kPrimaryColor,
|
||||
borderRadius: BorderRadius.circular(20.r),
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor),
|
||||
),
|
||||
child: CustomTextWidget(
|
||||
text: textOfButton??"Category 1",
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: selected!=null?CustomAppColors.kWhiteColor : CustomAppColors.kSecondaryColor,
|
||||
isExpanded: false),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotesRoundOutlinedBox2 extends StatelessWidget {
|
||||
const NotesRoundOutlinedBox2({
|
||||
super.key,
|
||||
required this.context,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final BuildContext context;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
|
||||
alignment: Alignment.centerLeft,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
margin: EdgeInsets.symmetric(horizontal: 25.w,vertical: 5.h),
|
||||
padding: EdgeInsets.all(16.sp),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor),
|
||||
borderRadius: BorderRadius.circular(18.r),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildNotesList2 extends StatelessWidget {
|
||||
const BuildNotesList2({
|
||||
super.key,
|
||||
required this.date,
|
||||
required this.history, required this.userName,
|
||||
});
|
||||
|
||||
final String date;
|
||||
final String history;
|
||||
final String userName;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: 'Note Title',
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
const Spacer(),
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kGoToArrowIcon,
|
||||
height: 18.66.h,
|
||||
width: 18.w,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5.h),
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: history,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
62
lib/view/screens/clientsListing/clients_list_screen.dart
Normal file
62
lib/view/screens/clientsListing/clients_list_screen.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../models/profileData/user_data.dart';
|
||||
import 'widgets/clients_list_view.dart';
|
||||
import 'widgets/search_bar_widget.dart';
|
||||
|
||||
class ClientsListScreen extends StatefulWidget {
|
||||
const ClientsListScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ClientsListScreen> createState() => _ClientsListScreenState();
|
||||
}
|
||||
|
||||
class _ClientsListScreenState extends State<ClientsListScreen> {
|
||||
final controller = Get.put(ClientsListScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
SearchBarWidget(
|
||||
controller: controller.searchController,
|
||||
onSearchTextChange: controller.searchText,
|
||||
),
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
final list = controller.serviceUsersList();
|
||||
final canLoadMore = controller.canLoadMore.value;
|
||||
|
||||
return UsersListView(
|
||||
refreshController: controller.listRC,
|
||||
scrollController: controller.listSC,
|
||||
canLoadMore: canLoadMore,
|
||||
list: list,
|
||||
onRefresh: controller.onRefresh,
|
||||
onLoading: controller.onLoading,
|
||||
listItemTap: (int index, UserData userData) {
|
||||
Navigator.pushNamed(
|
||||
context, CustomRouteNames.kClientsProfileScreenRoute,
|
||||
arguments: controller.serviceUsersList[index]);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<ClientsListScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
|
||||
class UserCardWidget extends StatelessWidget {
|
||||
const UserCardWidget({
|
||||
super.key,
|
||||
required this.index,
|
||||
required this.userData,
|
||||
});
|
||||
|
||||
final UserData userData;
|
||||
final int index;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20.w, top: 10.h, bottom: 10.h),
|
||||
child: Row(
|
||||
children: [
|
||||
MyCircleImage(
|
||||
imageSize: 53.r,
|
||||
url: "${WebUrls.baseUrl}${userData.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
height: 53.h,
|
||||
width: 53.w,
|
||||
),
|
||||
),
|
||||
10.horizontalSpace,
|
||||
CustomTextWidget(
|
||||
text: userData.displayName,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
isExpanded: false,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/profileData/user_data.dart';
|
||||
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
||||
import 'client_card_widget.dart';
|
||||
|
||||
class UsersListView extends StatelessWidget {
|
||||
final RefreshController refreshController;
|
||||
final ScrollController scrollController;
|
||||
final bool canLoadMore;
|
||||
final List<UserData> list;
|
||||
final VoidCallback onRefresh;
|
||||
final VoidCallback onLoading;
|
||||
final Function(int index, UserData userData) listItemTap;
|
||||
|
||||
const UsersListView({
|
||||
super.key,
|
||||
required this.listItemTap,
|
||||
required this.refreshController,
|
||||
required this.scrollController,
|
||||
required this.canLoadMore,
|
||||
required this.onRefresh,
|
||||
required this.onLoading,
|
||||
required this.list,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SmartRefresher(
|
||||
key: const ValueKey("clients_list"),
|
||||
controller: refreshController,
|
||||
scrollController: scrollController,
|
||||
header: FrequentFunctions.waterDropHeader,
|
||||
enablePullUp: canLoadMore,
|
||||
onRefresh: onRefresh,
|
||||
onLoading: onLoading,
|
||||
child: (list.isEmpty)
|
||||
? Container(
|
||||
color: Colors.white,
|
||||
child: const Center(
|
||||
child: Text("No users found"),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
listItemTap(index, list[index]);
|
||||
},
|
||||
child: UserCardWidget(index: index, userData: list[index]),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SearchBarWidget extends StatelessWidget {
|
||||
final TextEditingController? controller;
|
||||
final ValueChanged<String> onSearchTextChange;
|
||||
|
||||
const SearchBarWidget(
|
||||
{super.key, required this.onSearchTextChange, this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 48.h,
|
||||
margin: REdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kLightGreyColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(40.r)),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(onPressed: () {}, icon: const Icon(Icons.search)),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
onChanged: onSearchTextChange,
|
||||
autofocus: false,
|
||||
style: TextStyle(
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
hintText: "Search...",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
6
lib/view/screens/export_screens.dart
Normal file
6
lib/view/screens/export_screens.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
export 'auth_module/export_auth_module.dart';
|
||||
export 'clients/export_clients_module.dart';
|
||||
export 'home/export_home.dart';
|
||||
export 'notifications/export_notifications.dart';
|
||||
export 'profile/export_profile.dart';
|
||||
export 'rota/export_rota_screens.dart';
|
||||
198
lib/view/screens/home/dashboard_screen.dart
Normal file
198
lib/view/screens/home/dashboard_screen.dart
Normal file
@@ -0,0 +1,198 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'home_screen.dart';
|
||||
|
||||
class DashboardScreen extends StatefulWidget {
|
||||
const DashboardScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<DashboardScreen> createState() => _DashboardScreenState();
|
||||
}
|
||||
|
||||
class _DashboardScreenState extends State<DashboardScreen> {
|
||||
final controller = Get.put(DashboardScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
appBar: appBar,
|
||||
sideDrawer: const CustomDrawer(),
|
||||
bottomMenu: Obx(
|
||||
() => BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
currentIndex: controller.selectedIndex.value,
|
||||
onTap: (value) {
|
||||
if (value == 0) {
|
||||
Navigator.pushNamed(
|
||||
context, CustomRouteNames.kRotaDashboardScreenRoute);
|
||||
return;
|
||||
}
|
||||
controller.selectedIndex.value = value;
|
||||
},
|
||||
items: [
|
||||
BottomNavigationBarItem(
|
||||
label: "",
|
||||
icon: Column(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kCalendarIcon,
|
||||
height: 26.h,
|
||||
width: 26.w,
|
||||
imageColor: controller.selectedIndex.value == 0
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Rota",
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontColor: controller.selectedIndex.value == 0
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null),
|
||||
],
|
||||
),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
label: "",
|
||||
icon: Column(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kHomeIcon,
|
||||
height: 26.h,
|
||||
width: 26.w,
|
||||
imageColor: controller.selectedIndex.value == 1
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Dashboard",
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontColor: controller.selectedIndex.value == 1
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
label: "",
|
||||
icon: Column(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kMessageIcon,
|
||||
height: 26.h,
|
||||
width: 26.w,
|
||||
imageColor: controller.selectedIndex.value == 2
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Inbox",
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontColor: controller.selectedIndex.value == 2
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
label: "",
|
||||
icon: Column(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: AssetsManager.kPeopleUnselectedIcon,
|
||||
height: 26.h,
|
||||
width: 26.w,
|
||||
imageColor: controller.selectedIndex.value == 3
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Clients",
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontColor: controller.selectedIndex.value == 3
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
body: SafeArea(
|
||||
child: Obx(() => selectedScreen()[controller.selectedIndex.value])),
|
||||
);
|
||||
}
|
||||
|
||||
PreferredSizeWidget get appBar => CustomAppBar(
|
||||
showBoxShadow: false,
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => controller.screenKey.currentState!.openDrawer(),
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kDrawerIcon,
|
||||
height: 27.h,
|
||||
width: 27.w,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 15.0.w),
|
||||
child: Obx(() {
|
||||
return CustomTextWidget(
|
||||
text: controller.selectedIndex.value == 0
|
||||
? 'Home'
|
||||
: controller.selectedIndex.value == 1
|
||||
? 'Home'
|
||||
: controller.selectedIndex.value == 2
|
||||
? 'Inbox'
|
||||
: controller.selectedIndex.value == 3
|
||||
? 'Clients'
|
||||
: "",
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
);
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
Obx(() {
|
||||
return Visibility(
|
||||
visible: controller.selectedIndex.value == 0,
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBellIcon,
|
||||
height: 23.h,
|
||||
width: 22.w,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
List<Widget> selectedScreen() {
|
||||
return <Widget>[
|
||||
const RotaDashboardScreen(),
|
||||
const HomeScreen(),
|
||||
const InboxScreen(),
|
||||
const ClientsListScreen(),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
3
lib/view/screens/home/export_home.dart
Normal file
3
lib/view/screens/home/export_home.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'dashboard_screen.dart';
|
||||
export '../chat/chat_screen.dart';
|
||||
export 'inbox_screen.dart';
|
||||
214
lib/view/screens/home/home_screen.dart
Normal file
214
lib/view/screens/home/home_screen.dart
Normal file
@@ -0,0 +1,214 @@
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/rota/new_rota_list_widget.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/webview/webview_screen.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'widgets/home_row_items.dart';
|
||||
import 'widgets/line_row_widget.dart';
|
||||
|
||||
class HomeScreen extends StatelessWidget {
|
||||
const HomeScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = Get.find<DashboardScreenController>();
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
60.verticalSpace,
|
||||
Container(
|
||||
height: 400.h,
|
||||
padding: EdgeInsets.only(top: 100.h),
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kSecondaryColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20.r),
|
||||
topRight: Radius.circular(20.r),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
|
||||
//profile picture
|
||||
Obx(() {
|
||||
return MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url:
|
||||
"${WebUrls.baseUrl}${DashboardScreenController.instance.myProfileData()?.user?.profilePictureUrl ?? ""}",
|
||||
errorWidget: CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
imageColor: CustomAppColors.kDarkBlueTextColor,
|
||||
height: 80.r,
|
||||
width: 80.r,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
3.verticalSpace,
|
||||
|
||||
//Name
|
||||
Obx(
|
||||
() => CustomTextWidget(
|
||||
text: DashboardScreenController.instance
|
||||
.myProfileData()
|
||||
?.staffMemberName ??
|
||||
"",
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kPrimaryColor,
|
||||
),
|
||||
),
|
||||
|
||||
//designation
|
||||
Obx(
|
||||
() => CustomTextWidget(
|
||||
text: DashboardScreenController.instance
|
||||
.myProfileData()
|
||||
?.staffDesignation ??
|
||||
"",
|
||||
fontSize: 14.sp,
|
||||
fontColor: CustomAppColors.kPrimaryColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
16.verticalSpace,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
HomeRowItems(
|
||||
iconUrl: AssetsManager.kCalendarIcon,
|
||||
textOfItem: "Rota",
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kRotaDashboardScreenRoute,
|
||||
);
|
||||
},
|
||||
),
|
||||
HomeRowItems(
|
||||
iconUrl: AssetsManager.kPeopleUnselectedIcon,
|
||||
textOfItem: "Clients",
|
||||
color: CustomAppColors.kLightTextColor,
|
||||
onTap: () {
|
||||
Get.find<DashboardScreenController>()
|
||||
.selectedIndex
|
||||
.value = 3;
|
||||
},
|
||||
),
|
||||
HomeRowItems(
|
||||
iconUrl: AssetsManager.kMessageIcon,
|
||||
textOfItem: "Message",
|
||||
onTap: () {
|
||||
Get.find<DashboardScreenController>()
|
||||
.selectedIndex
|
||||
.value = 2;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
10.verticalSpace,
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height / 1.5,
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kWhiteColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20.r),
|
||||
topRight: Radius.circular(20.r),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Obx(() {
|
||||
return (controller.myShiftsList.isEmpty)
|
||||
? FrequentFunctions.noWidget
|
||||
: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20.r, vertical: 10.r),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Your next Shifts",
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16.sp),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames
|
||||
.kYourRotaScreenRoute);
|
||||
},
|
||||
child: CustomTextWidget(
|
||||
text: "See all",
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
Obx(
|
||||
() => (controller.myShiftsList.isEmpty)
|
||||
? FrequentFunctions.noWidget
|
||||
: NewRotaListWidget(
|
||||
shifts: controller.myShiftsList,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kWebviewScreen,
|
||||
arguments: WebviewScreenArgument(
|
||||
title: 'Policies and Procedures',
|
||||
url: ConstantText.privacyUrl),
|
||||
);
|
||||
},
|
||||
child: const LineRowWidget(
|
||||
text: "Policies & Procedures",
|
||||
icon: AssetsManager.kPoliciesIcon),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
//Todo: uncomment when start working
|
||||
// Navigator.pushNamed(
|
||||
// context,
|
||||
// CustomRouteNames.kSettingsScreen,
|
||||
// );
|
||||
},
|
||||
child: const LineRowWidget(
|
||||
text: "Settings",
|
||||
icon: AssetsManager.kSettingsIcon),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
202
lib/view/screens/home/inbox_screen.dart
Normal file
202
lib/view/screens/home/inbox_screen.dart
Normal file
@@ -0,0 +1,202 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/chat/ChatModel.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/chat/arguments/chat_screen_args.dart';
|
||||
import 'package:ftc_mobile_app/web_services/chat_services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
||||
import '../../custom_widgets/my_circle_image.dart';
|
||||
|
||||
class InboxScreen extends StatefulWidget {
|
||||
const InboxScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<InboxScreen> createState() => _InboxScreenState();
|
||||
}
|
||||
|
||||
class _InboxScreenState extends State<InboxScreen> {
|
||||
final InboxScreenController controller = Get.put(InboxScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
// onBackButton: controller.onBackButtonPressed,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: false,
|
||||
body: Obx(() {
|
||||
final list = controller.chatsAndGroups();
|
||||
list.sort((a, b) => b.date.compareTo(a.date));
|
||||
|
||||
final canLoadMore = controller.canLoadMore.value;
|
||||
|
||||
return SmartRefresher(
|
||||
key: const ValueKey("clients_list"),
|
||||
controller: controller.listRC,
|
||||
scrollController: controller.listSC,
|
||||
header: FrequentFunctions.waterDropHeader,
|
||||
enablePullUp: canLoadMore,
|
||||
onRefresh: controller.onRefresh,
|
||||
onLoading: controller.onLoading,
|
||||
child: (list.isEmpty)
|
||||
? Container(
|
||||
color: Colors.white,
|
||||
child: const Center(
|
||||
child: Text("Your inbox is empty"),
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: list.length,
|
||||
padding: REdgeInsets.symmetric(horizontal: 20),
|
||||
separatorBuilder: (_, int index) => 8.verticalSpace,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return SenderListWidget(
|
||||
messagesListModel: controller.chatsAndGroups[index],
|
||||
onTap: (messagesListModel) async {
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kChatScreenRoute,
|
||||
arguments: ChatScreenArgs(
|
||||
name: messagesListModel.title,
|
||||
profilePicPath: messagesListModel.image,
|
||||
otherUserId: messagesListModel.otherUserId,
|
||||
groupData: messagesListModel.groupData,
|
||||
onLastMessageUpdate: (m) =>
|
||||
_onLastMessageUpdate(index, m),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context, CustomRouteNames.kSelectUserForChatScreenRoute);
|
||||
},
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_onLastMessageUpdate(int index, ChatModel model) {
|
||||
if (mounted) {
|
||||
controller.chatsAndGroups[index].previewOfLastMessage =
|
||||
model.message ?? "";
|
||||
controller.chatsAndGroups[index].date =
|
||||
model.date ?? DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
controller.chatsAndGroups.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SenderListWidget extends StatefulWidget {
|
||||
const SenderListWidget({
|
||||
super.key,
|
||||
required this.messagesListModel,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final MessagesListModel messagesListModel;
|
||||
final ValueChanged<MessagesListModel> onTap;
|
||||
|
||||
@override
|
||||
State<SenderListWidget> createState() => _SenderListWidgetState();
|
||||
}
|
||||
|
||||
class _SenderListWidgetState extends State<SenderListWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => widget.onTap(widget.messagesListModel),
|
||||
child: Container(
|
||||
padding: REdgeInsets.symmetric(vertical: 9),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyCircleImage(
|
||||
imageSize: 53.r,
|
||||
url: "${WebUrls.baseUrl}${widget.messagesListModel.image}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
imageColor: CustomAppColors.kDarkBlueTextColor,
|
||||
height: 53.r,
|
||||
width: 53.r,
|
||||
),
|
||||
),
|
||||
12.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: widget.messagesListModel.title,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
isExpanded: false,
|
||||
),
|
||||
4.verticalSpace,
|
||||
(widget.messagesListModel.messageType ==
|
||||
MessageType.message.name)
|
||||
? CustomTextWidget(
|
||||
text: widget.messagesListModel.previewOfLastMessage,
|
||||
fontColor: widget.messagesListModel.isRecent == true
|
||||
? CustomAppColors.kDarkBlueTextColor
|
||||
: CustomAppColors.kLightGreyColor,
|
||||
fontSize: 12.sp,
|
||||
maxLines: 1,
|
||||
fontWeight: FontWeight.w600,
|
||||
textAlign: TextAlign.left,
|
||||
isExpanded: false,
|
||||
)
|
||||
: FrequentFunctions.noWidget,
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: REdgeInsets.only(right: 2),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: FrequentFunctions.toTimesAgo(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
widget.messagesListModel.date)
|
||||
.toIso8601String()),
|
||||
fontColor: CustomAppColors.kLightGreyColor,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
isExpanded: false,
|
||||
),
|
||||
widget.messagesListModel.noOfMessages != 0
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 8.0.h),
|
||||
child: CircleAvatar(
|
||||
minRadius: 8.sp,
|
||||
maxRadius: 8.sp,
|
||||
backgroundColor: CustomAppColors.kBlackColor,
|
||||
child: CustomTextWidget(
|
||||
text: "${widget.messagesListModel.noOfMessages}",
|
||||
isExpanded: false,
|
||||
fontSize: 8.sp,
|
||||
fontColor: CustomAppColors.kPrimaryColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
123
lib/view/screens/home/select_user_for_chat_screen.dart
Normal file
123
lib/view/screens/home/select_user_for_chat_screen.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/controllers/home/select_user_for_chat_screen_controller.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/view/screens/chat/arguments/chat_screen_args.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../models/profileData/user_data.dart';
|
||||
import '../clientsListing/widgets/clients_list_view.dart';
|
||||
import '../clientsListing/widgets/search_bar_widget.dart';
|
||||
|
||||
class SelectUserForChatScreen extends StatefulWidget {
|
||||
const SelectUserForChatScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SelectUserForChatScreen> createState() =>
|
||||
_SelectUserForChatScreenState();
|
||||
}
|
||||
|
||||
class _SelectUserForChatScreenState extends State<SelectUserForChatScreen> {
|
||||
final controller = Get.put(SelectUserForChatScreenController());
|
||||
|
||||
// final controller =
|
||||
// Get.put(ClientsListScreenController(), tag: "select_clients");
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
// onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
appBar: CustomAppBarTitleOnly(context, titleText: 'Select Contact'),
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
SearchBarWidget(
|
||||
onSearchTextChange: controller.onSearch,
|
||||
),
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
final list = controller.staffUsersList();
|
||||
final canLoadMore = controller.canLoadMore.value;
|
||||
|
||||
return UsersListView(
|
||||
refreshController: controller.listRC,
|
||||
scrollController: controller.listSC,
|
||||
canLoadMore: canLoadMore,
|
||||
list: list,
|
||||
onRefresh: controller.onRefresh,
|
||||
onLoading: controller.onLoading,
|
||||
listItemTap: (int index, UserData userData) {
|
||||
Navigator.popAndPushNamed(
|
||||
controller.screenKey.currentContext!,
|
||||
CustomRouteNames.kChatScreenRoute,
|
||||
arguments: ChatScreenArgs(
|
||||
otherUserId: userData.id!,
|
||||
name: userData.displayName,
|
||||
profilePicPath: userData.profilePictureUrl ?? "",
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// class UserListWidgetItem extends StatelessWidget {
|
||||
// final SelectUserForChatScreenController controller =
|
||||
// Get.find<SelectUserForChatScreenController>();
|
||||
//
|
||||
// UserListWidgetItem({
|
||||
// super.key,
|
||||
// required this.nameOfPerson,
|
||||
// required this.index,
|
||||
// });
|
||||
//
|
||||
// final String nameOfPerson;
|
||||
// final int index;
|
||||
//
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return InkWell(
|
||||
// onTap: () {
|
||||
// // Navigator.pop(controller.screenKey.currentContext!, controller.serviceUsersList[index]);
|
||||
// Navigator.pushNamed(controller.screenKey.currentContext!,
|
||||
// CustomRouteNames.kGroupChatScreenRoute,
|
||||
// arguments: controller.serviceUsersList[index]);
|
||||
// },
|
||||
// child: Container(
|
||||
// padding: EdgeInsets.only(left: 20.w, top: 20.h),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// CustomImageWidget(
|
||||
// imagePath: AssetsManager.kPersonMainIcon,
|
||||
// height: 53.h,
|
||||
// width: 53.w,
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: 10.w,
|
||||
// ),
|
||||
// CustomTextWidget(
|
||||
// text: nameOfPerson,
|
||||
// fontSize: 16.sp,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// isExpanded: false,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
52
lib/view/screens/home/widgets/home_row_items.dart
Normal file
52
lib/view/screens/home/widgets/home_row_items.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HomeRowItems extends StatelessWidget {
|
||||
const HomeRowItems({
|
||||
super.key,
|
||||
required this.iconUrl,
|
||||
required this.textOfItem,
|
||||
this.color,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final String iconUrl;
|
||||
final String textOfItem;
|
||||
final Color? color;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.w, horizontal: 10.h),
|
||||
height: 80.h,
|
||||
width: 80.h,
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kPrimaryColor,
|
||||
borderRadius: BorderRadius.circular(15.r),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
width: 33.w,
|
||||
height: 38.h,
|
||||
imagePath: iconUrl,
|
||||
imageColor: CustomAppColors.kBlackColor,
|
||||
),
|
||||
SizedBox(
|
||||
height: 5.h,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: textOfItem,
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
42
lib/view/screens/home/widgets/line_row_widget.dart
Normal file
42
lib/view/screens/home/widgets/line_row_widget.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LineRowWidget extends StatelessWidget {
|
||||
const LineRowWidget({super.key, required this.text, required this.icon});
|
||||
|
||||
final String text;
|
||||
final String icon;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 20.w, vertical: 5.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kLightGreyColor)),
|
||||
child: Row(
|
||||
children: [
|
||||
CustomImageWidget(
|
||||
imagePath: icon,
|
||||
width: 19,
|
||||
height: 22,
|
||||
),
|
||||
SizedBox(
|
||||
width: 25.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: text,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp),
|
||||
const Spacer(),
|
||||
CustomTextWidget(
|
||||
text: ">",
|
||||
isExpanded: false,
|
||||
fontSize: 15.sp,
|
||||
fontWeight: FontWeight.w500),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
1
lib/view/screens/notifications/export_notifications.dart
Normal file
1
lib/view/screens/notifications/export_notifications.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'notifications_list_screen.dart';
|
||||
239
lib/view/screens/notifications/notifications_list_screen.dart
Normal file
239
lib/view/screens/notifications/notifications_list_screen.dart
Normal file
@@ -0,0 +1,239 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app_badger/flutter_app_badger.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class NotificationListScreen extends StatefulWidget {
|
||||
const NotificationListScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<NotificationListScreen> createState() => _NotificationListScreenState();
|
||||
}
|
||||
|
||||
class _NotificationListScreenState extends State<NotificationListScreen> {
|
||||
final controller = Get.put(NotificationListScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
try {
|
||||
FlutterAppBadger.removeBadge();
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
// sideDrawer: const CustomDrawer(),
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(context, titleText: 'Notifications'),
|
||||
body: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 25.w),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const DateTextWidget(),
|
||||
NotificationListItemWidget(totalNotifications: "4"),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
NotificationListItemWidget(),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
const DateTextWidget(),
|
||||
NotificationListItemWidget(),
|
||||
const DateTextWidget(),
|
||||
NotificationListItemWidget(),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
NotificationListItemWidget(totalNotifications: "8"),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
const DateTextWidget(),
|
||||
NotificationListItemWidget(),
|
||||
const DateTextWidget(),
|
||||
NotificationListItemWidget(),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
NotificationListItemWidget(),
|
||||
SizedBox(
|
||||
height: 4.h,
|
||||
),
|
||||
const DateTextWidget(),
|
||||
NotificationListItemWidget(),
|
||||
SizedBox(height: 8.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class DateTextWidget extends StatelessWidget {
|
||||
const DateTextWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 5.h),
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: "21 Dec, 2022",
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationListItemWidget extends StatelessWidget {
|
||||
NotificationListItemWidget({
|
||||
super.key,
|
||||
this.totalNotifications = '0',
|
||||
});
|
||||
|
||||
final NotificationListScreenController controller = Get.find();
|
||||
final String totalNotifications;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
final rotaShift = RotaShift(
|
||||
name: 'Dr. John Doe',
|
||||
staffRequired: '2',
|
||||
workerType: 'Nurse',
|
||||
location: 'Hospital A',
|
||||
startTime: '8:00 AM',
|
||||
endTime: '4:00 PM',
|
||||
breakTime: '30 min',
|
||||
notes: 'NA',
|
||||
);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ShowDialogNotification(
|
||||
rotaShift: rotaShift,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onDoubleTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return const HolidayRequestAcceptDialog(
|
||||
startDate: "Dec 18, 2022",
|
||||
endDate: "Dec 19, 2022",
|
||||
noOfDays: "2 days (16 hours)",
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onLongPress: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return PrivacyPolicyDialog(
|
||||
privacyPolicy: controller.privacyPolicy,
|
||||
checkBoxOnChange: (value) {
|
||||
controller.privacyPolicyAccepted.value = value;
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kSecondaryColor),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: 'New Shift: Dec 21, 7AM - 7PM',
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
const Spacer(),
|
||||
CustomTextWidget(
|
||||
text: '07:30 PM',
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5.h),
|
||||
Row(
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: "You have been assigned a new shift.",
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
),
|
||||
const Spacer(),
|
||||
totalNotifications != '0'
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(80.r),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 22.h,
|
||||
width: 22.w,
|
||||
decoration: const BoxDecoration(
|
||||
color: CustomAppColors.kRedColor,
|
||||
),
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.center,
|
||||
textAlign: TextAlign.left,
|
||||
text: totalNotifications,
|
||||
isExpanded: false,
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: CustomAppColors.kWhiteColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
1
lib/view/screens/profile/export_profile.dart
Normal file
1
lib/view/screens/profile/export_profile.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'view_profile_screen.dart';
|
||||
494
lib/view/screens/profile/view_profile_screen.dart
Normal file
494
lib/view/screens/profile/view_profile_screen.dart
Normal file
@@ -0,0 +1,494 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/app_dialogs.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/widgets/holidays_data_dialog.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/view/custom_widgets/my_circle_image.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../models/staffWorkload/StaffWorkloadResponse.dart';
|
||||
|
||||
class ViewProfileScreen extends StatefulWidget {
|
||||
const ViewProfileScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ViewProfileScreen> createState() => _ViewProfileScreenState();
|
||||
}
|
||||
|
||||
class _ViewProfileScreenState extends State<ViewProfileScreen> {
|
||||
final controller = Get.put(ViewProfileScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ObxValue((RxBool isEditable) {
|
||||
final editable = isEditable();
|
||||
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar:
|
||||
// isEditable() ?
|
||||
CustomAppBarTitleOnly(context, titleText: "Your Profile"),
|
||||
// : CustomAppBarWithAction(
|
||||
// context,
|
||||
// titleText: 'Your Profile',
|
||||
// actionText: '\u270E Edit',
|
||||
// actionTextColor: Get.theme.primaryColor,
|
||||
// onActionTap: () {
|
||||
// isEditable.value = true;
|
||||
// },
|
||||
// ),
|
||||
body: SingleChildScrollView(
|
||||
child: Obx(() {
|
||||
if (controller.detail()?.user == null) {
|
||||
return FrequentFunctions.noWidget;
|
||||
}
|
||||
|
||||
final detail = controller.detail()!;
|
||||
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MyCircleImage(
|
||||
imageSize: 80.r,
|
||||
url:
|
||||
"${WebUrls.baseUrl}${detail.user!.profilePictureUrl ?? ""}",
|
||||
errorWidget: CustomImageWidget(
|
||||
imagePath: AssetsManager.kPersonMainIcon,
|
||||
imageColor: CustomAppColors.kDarkBlueTextColor,
|
||||
height: 80.r,
|
||||
width: 80.r,
|
||||
),
|
||||
),
|
||||
4.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text: detail.user!.displayName,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontColor: Colors.black,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
// Container(
|
||||
// padding: EdgeInsets.only(left: 18.w, top: 15.h),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// // Obx(
|
||||
// // () => TabBarWidget(
|
||||
// // title: "Profile (Client View)",
|
||||
// // selected: controller.viewProfileClient.value,
|
||||
// // onTapFunction: () {
|
||||
// // controller.viewProfileClient.value = true;
|
||||
// // },
|
||||
// // ),
|
||||
// // ),
|
||||
// // SizedBox(
|
||||
// // width: 12.w,
|
||||
// // ),
|
||||
// // Expanded(
|
||||
// // child: SizedBox(
|
||||
// // width: ,
|
||||
// // child: Obx(
|
||||
// // () => TabBarWidget(
|
||||
// // title: "Staff Profile",
|
||||
// // selected: controller.viewProfileClient.isFalse,
|
||||
// // onTapFunction: () =>
|
||||
// // controller.viewProfileClient.value = false,
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
//
|
||||
// Expanded(
|
||||
// child: SizedBox(
|
||||
// width: 12.w,
|
||||
// ),
|
||||
// ),
|
||||
// InkWell(
|
||||
// onTap: () {},
|
||||
// borderRadius: 20.toRadius(),
|
||||
// child: Padding(
|
||||
// padding: REdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
// child: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// CustomImageWidget(
|
||||
// imagePath: AssetsManager.kPencilIcon,
|
||||
// width: 10.w,
|
||||
// height: 10.h,
|
||||
// ),
|
||||
// 4.horizontalSpace,
|
||||
// CustomTextWidget(
|
||||
// text: "Edit",
|
||||
// isExpanded: false,
|
||||
// fontSize: 10.sp,
|
||||
// fontWeight: FontWeight.w700,
|
||||
// fontColor: CustomAppColors.kSecondaryColor),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// 12.horizontalSpace,
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
16.verticalSpace,
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 6.r,
|
||||
),
|
||||
child: CustomTextFieldWidget(
|
||||
controller: controller.nameTEC,
|
||||
heading: "Name",
|
||||
isEnabled: editable,
|
||||
),
|
||||
// child: isEditable()
|
||||
// ? CustomTextFieldWidget(
|
||||
// controller: controller.nameTEC,
|
||||
// heading: "Name",
|
||||
// )
|
||||
// : SingleItem(
|
||||
// heading: "Name", value: detail.user!.displayName),
|
||||
),
|
||||
16.verticalSpace,
|
||||
Obx(
|
||||
() => controller.viewProfileClient.isTrue
|
||||
? profileClientView
|
||||
: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextFieldWidget(
|
||||
controller: controller.emailTEC,
|
||||
heading: "Email",
|
||||
isEnabled: false,
|
||||
),
|
||||
// child: SingleItem(
|
||||
// heading: "Email",
|
||||
// value: detail.user!.email ?? ""),
|
||||
),
|
||||
8.horizontalSpace,
|
||||
Expanded(
|
||||
child: CustomTextFieldWidget(
|
||||
controller: controller.phoneTEC,
|
||||
heading: "Phone",
|
||||
isEnabled: editable,
|
||||
),
|
||||
// child: SingleItem(
|
||||
// heading: "Phone",
|
||||
// value:
|
||||
// (detail.user!.phoneNumber ?? "")),
|
||||
),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
// SingleItem(
|
||||
// heading: "Address",
|
||||
// value:
|
||||
// detail.user!.modelId?.homeAddress ?? ""),
|
||||
CustomTextFieldWidget(
|
||||
controller: controller.addressTEC,
|
||||
heading: "Address",
|
||||
isEnabled: false,
|
||||
),
|
||||
16.verticalSpace,
|
||||
CustomTextFieldWidget(
|
||||
controller: TextEditingController(
|
||||
text: detail.kin ?? ""),
|
||||
heading: "Next of kin",
|
||||
isEnabled: false,
|
||||
),
|
||||
16.verticalSpace,
|
||||
// SingleItem(
|
||||
// heading: "Next of kin",
|
||||
// value: detail.kin ?? ""),
|
||||
SingleItem(
|
||||
heading: "Total Holidays Left",
|
||||
value:
|
||||
"${detail.staffWorkLoads?.firstOrNull?.holidayAlwnNoOfDys ?? "0"} Days (${detail.staffWorkLoads?.firstOrNull?.holidayAlwnNoOfHours ?? "0"} hours)",
|
||||
onTap: () {
|
||||
if (detail.staffWorkLoads?.firstOrNull !=
|
||||
null) {}
|
||||
_onTotalHolidaysBoxTap(
|
||||
detail.staffWorkLoads!.first);
|
||||
},
|
||||
),
|
||||
SingleItem(
|
||||
heading: "",
|
||||
value: "Training",
|
||||
onTap: () {
|
||||
Get.toNamed(
|
||||
CustomRouteNames.kTrainingsScreen);
|
||||
}),
|
||||
// SingleItem(
|
||||
// heading: "",
|
||||
// value: "COVID Checks",
|
||||
// onTap: () {}),
|
||||
12.verticalSpace,
|
||||
Obx(() {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: IgnorePointer(
|
||||
ignoring: true,
|
||||
child: CustomCheckBox(
|
||||
checkBoxValue: controller.covidCheck(),
|
||||
titleText: "COVID Check",
|
||||
onTap: () {
|
||||
// controller.covidCheck.toggle();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
20.verticalSpace,
|
||||
editable
|
||||
? AppDialog.buttonsBar(
|
||||
onButton1Tap: () {
|
||||
isEditable(false);
|
||||
},
|
||||
onButton2Tap: () {},
|
||||
button1Text: "Cancel",
|
||||
button2Text: "Update")
|
||||
.paddingOnly(bottom: 12.r)
|
||||
: FrequentFunctions.noWidget,
|
||||
|
||||
CustomAppButton(
|
||||
buttonText: "LOGOUT",
|
||||
buttonColor: CustomAppColors.kRedColor,
|
||||
borderColor: CustomAppColors.kRedColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: () {
|
||||
controller.logoutPressed();
|
||||
},
|
||||
),
|
||||
|
||||
18.verticalSpace,
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}, controller.isEditable);
|
||||
}
|
||||
|
||||
Column get profileClientView {
|
||||
return const Column(
|
||||
children: [
|
||||
BuildDetailsWidget(
|
||||
title: "My Experience",
|
||||
details:
|
||||
"A quick preview of the text will be shown here. A quick preview of the text will be shown here. shown here. A quick preview of the text will be shown here. A quick preview of the text will be shown here. A quick preview of the text will be shown here.",
|
||||
),
|
||||
BuildDetailsWidget(
|
||||
title: "About Me",
|
||||
details:
|
||||
"A quick preview of the text will be shown here. A quick preview of the text will be shown here. shown here. A quick preview of the text will be shown here. A quick preview of the text will be shown here. A quick preview of the text will be shown here.",
|
||||
),
|
||||
BuildDetailsWidget(
|
||||
title: "Things I like to do in my spare time",
|
||||
details:
|
||||
"A quick preview of the text will be shown here. A quick preview of the text will be shown here. shown here. A quick preview of the text will be shown here. A quick preview of the text will be shown here. A quick preview of the text will be shown here.",
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
_onTotalHolidaysBoxTap(StaffWorkLoads? workLoads) {
|
||||
DateTime date = DateTime.now();
|
||||
if (workLoads?.endDate.isNotNullOrEmpty() == true) {
|
||||
date = DateTime.parse(workLoads!.endDate!);
|
||||
}
|
||||
|
||||
final holidayData = HolidayModel(
|
||||
carriedOver: "${workLoads?.carriedOverHours ?? 0} hours",
|
||||
holidayEntitlement:
|
||||
"${workLoads?.holidayEntitlement?.numberOfWeeks ?? 0} weeks (${workLoads?.holidayEntitlement?.numberOfDays ?? 0} days, ${workLoads?.holidayEntitlement?.numberOfHours ?? 0} hours)",
|
||||
holidayAllowance:
|
||||
"${workLoads?.holidayAlwnNoOfDys ?? 0} days (${workLoads?.holidayAlwnNoOfHours ?? 0} hours)",
|
||||
remainingHolidays:
|
||||
"${workLoads?.holidaysRemaining ?? 0} days (${workLoads?.holidayAlwnNoOfHours ?? 0} hours)",
|
||||
timeLeftBeforeYearEnd: "${date.difference(DateTime.now()).inDays} days",
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return HolidaysDataDialog(holidayModel: holidayData);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class SingleItem extends StatelessWidget {
|
||||
const SingleItem({
|
||||
super.key,
|
||||
required this.heading,
|
||||
required this.value,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final String heading;
|
||||
final String value;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: REdgeInsets.symmetric(vertical: 10.0),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kSmokeColor)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||
child: Row(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(heading.isEmpty)
|
||||
? FrequentFunctions.noWidget
|
||||
: CustomTextWidget(
|
||||
alignment: Alignment.topLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: heading,
|
||||
fontWeight: FontWeight.w500,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kLightTextColor,
|
||||
).paddingOnly(bottom: 4),
|
||||
CustomTextWidget(
|
||||
alignment: Alignment.topLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: value,
|
||||
fontWeight: FontWeight.w600,
|
||||
isExpanded: false,
|
||||
fontSize: 13.sp,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap != null ? const Spacer() : Container(),
|
||||
onTap != null
|
||||
? Transform.rotate(
|
||||
angle: 3.1415 * 3.5,
|
||||
child: const Icon(
|
||||
Icons.arrow_drop_down,
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TabBarWidget extends StatelessWidget {
|
||||
const TabBarWidget({
|
||||
super.key,
|
||||
required this.selected,
|
||||
required this.title,
|
||||
this.onTapFunction,
|
||||
});
|
||||
|
||||
final bool selected;
|
||||
final String title;
|
||||
final VoidCallback? onTapFunction;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTapFunction,
|
||||
child: Container(
|
||||
// width: 141.w,
|
||||
height: 22.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w),
|
||||
decoration: BoxDecoration(
|
||||
color: selected
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: CustomAppColors.kPrimaryColor,
|
||||
borderRadius: BorderRadius.circular(20.r),
|
||||
border: Border.all(
|
||||
color: selected
|
||||
? CustomAppColors.kSecondaryColor
|
||||
: CustomAppColors.kSmokeColor),
|
||||
),
|
||||
child: CustomTextWidget(
|
||||
text: title,
|
||||
isExpanded: false,
|
||||
fontColor: selected
|
||||
? CustomAppColors.kPrimaryColor
|
||||
: CustomAppColors.kBlackColor,
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildDetailsWidget extends StatelessWidget {
|
||||
const BuildDetailsWidget({
|
||||
super.key,
|
||||
required this.details,
|
||||
required this.title,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String details;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 20.w),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(bottom: 8.h),
|
||||
child: CustomTextWidget(
|
||||
isExpanded: false,
|
||||
text: title,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontColor: CustomAppColors.kDarkBlueTextColor,
|
||||
fontSize: 14.sp),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: CustomAppColors.kLightTextColor),
|
||||
borderRadius: BorderRadius.circular(10.r)),
|
||||
child: CustomTextWidget(
|
||||
alignment: Alignment.centerLeft,
|
||||
textAlign: TextAlign.left,
|
||||
text: details,
|
||||
isExpanded: false,
|
||||
fontSize: 10.sp,
|
||||
fontColor: CustomAppColors.kBlackColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
255
lib/view/screens/rota/book_holiday_screen.dart
Normal file
255
lib/view/screens/rota/book_holiday_screen.dart
Normal file
@@ -0,0 +1,255 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/widgets/holiday_request_sent_dialog.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/widgets/holidays_data_dialog.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/staffWorkload/StaffWorkloadResponse.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../custom_widgets/label_value_box_widget.dart';
|
||||
|
||||
class BookHolidayScreen extends StatefulWidget {
|
||||
const BookHolidayScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<BookHolidayScreen> createState() => _BookHolidayScreenState();
|
||||
}
|
||||
|
||||
class _BookHolidayScreenState extends State<BookHolidayScreen> {
|
||||
final controller = Get.put(BookHolidayScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: 'Book a Holiday',
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
Obx(() {
|
||||
return InkWell(
|
||||
onTap: () => _onTotalHolidaysBoxTap(controller.myWorkLoads()),
|
||||
child: LabelValueBoxWidget(
|
||||
label: 'Total Holidays Left',
|
||||
value:
|
||||
'${controller.myWorkLoads()?.holidaysRemaining ?? 0} days (${controller.myWorkLoads()?.holidayAlwnNoOfHours ?? 0} hours)',
|
||||
trailing: const Icon(
|
||||
Icons.arrow_right_rounded,
|
||||
color: Colors.black,
|
||||
),
|
||||
).addPaddingHorizontal(16),
|
||||
);
|
||||
}),
|
||||
10.verticalSpace,
|
||||
Obx(
|
||||
() => CalendarWidget(
|
||||
markedDatesMap: controller.markedDatesMap(),
|
||||
minDate: DateTime.now().subtract(10.days),
|
||||
targetDateTime: controller.targetDateTime.value,
|
||||
canSelectRange: true,
|
||||
rangeStart: controller.holidayStartDate(),
|
||||
rangeEnd: controller.holidayEndDate(),
|
||||
onRangeSelect: controller.onRangeSelect,
|
||||
onDayTap: (date, _) => controller.targetDateTime(date),
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
Padding(
|
||||
padding: REdgeInsets.symmetric(horizontal: 16.0, vertical: 10),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
//Start End date boxes
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => LabelValueBoxWidget(
|
||||
label: "Start Date",
|
||||
value: DateFormatter()
|
||||
.getHolidayDate(controller.holidayStartDate()),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 14.r),
|
||||
child: Icon(
|
||||
Icons.arrow_forward,
|
||||
size: 20.0.sp,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => LabelValueBoxWidget(
|
||||
label: "End Date",
|
||||
value: DateFormatter()
|
||||
.getHolidayDate(controller.holidayEndDate()),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
10.verticalSpace,
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Obx(() => LabelValueBoxWidget(
|
||||
label: "Holiday Request",
|
||||
value:
|
||||
"${controller.holidayDays()} Days (${controller.holidayHours()} Hours)",
|
||||
))),
|
||||
20.verticalSpace,
|
||||
AgreeToRulesWidget(
|
||||
agreeToRules: controller.agreeToRules,
|
||||
onTapViewBookingRules: () {},
|
||||
),
|
||||
25.verticalSpace,
|
||||
RequestHolidayButton(
|
||||
onTap: _onRequestHolidayButtonTap,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_onTotalHolidaysBoxTap(StaffWorkLoads? workLoads) {
|
||||
DateTime date = DateTime.now();
|
||||
if (workLoads?.endDate.isNotNullOrEmpty() == true) {
|
||||
date = DateTime.parse(workLoads!.endDate!);
|
||||
}
|
||||
|
||||
final holidayData = HolidayModel(
|
||||
carriedOver: "${workLoads?.carriedOverHours ?? 0} hours",
|
||||
holidayEntitlement:
|
||||
"${workLoads?.holidayEntitlement?.numberOfWeeks ?? 0} weeks (${workLoads?.holidayEntitlement?.numberOfDays ?? 0} days, ${workLoads?.holidayEntitlement?.numberOfHours ?? 0} hours)",
|
||||
holidayAllowance:
|
||||
"${workLoads?.holidayAlwnNoOfDys ?? 0} days (${workLoads?.holidayAlwnNoOfHours ?? 0} hours)",
|
||||
remainingHolidays:
|
||||
"${workLoads?.holidaysRemaining ?? 0} days (${workLoads?.holidayAlwnNoOfHours ?? 0} hours)",
|
||||
timeLeftBeforeYearEnd: "${date.difference(DateTime.now()).inDays} days",
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return HolidaysDataDialog(holidayModel: holidayData);
|
||||
});
|
||||
}
|
||||
|
||||
_onRequestHolidayButtonTap() async {
|
||||
final isSuccess = await controller.requestHoliday();
|
||||
|
||||
if (isSuccess) {
|
||||
Get.dialog(HolidayRequestSentDialog(
|
||||
holidayStartDate:
|
||||
DateFormatter().getHolidayDate(controller.holidayStartDate.value),
|
||||
holidayEndDate:
|
||||
DateFormatter().getHolidayDate(controller.holidayEndDate.value),
|
||||
holidayTotalTime:
|
||||
"${controller.holidayDays()} Days (${controller.holidayHours()} Hours)",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class AgreeToRulesWidget extends StatelessWidget {
|
||||
final RxBool agreeToRules;
|
||||
final VoidCallback onTapViewBookingRules;
|
||||
|
||||
const AgreeToRulesWidget({
|
||||
super.key,
|
||||
required this.agreeToRules,
|
||||
required this.onTapViewBookingRules,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: agreeToRules.toggle,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Obx(
|
||||
() => Ink(
|
||||
width: 24.r,
|
||||
height: 24.r,
|
||||
child: Checkbox(
|
||||
value: agreeToRules.value,
|
||||
activeColor: CustomAppColors.kSecondaryColor,
|
||||
onChanged: (value) {
|
||||
agreeToRules.value = value ?? false;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
10.horizontalSpace,
|
||||
CustomTextWidget(
|
||||
isExpanded: false,
|
||||
text: 'Agree to the booking rules',
|
||||
fontColor: Colors.black,
|
||||
fontSize: 10.0.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// const Spacer(),
|
||||
// InkWell(
|
||||
// onTap: () {},
|
||||
// child: Padding(
|
||||
// padding: REdgeInsets.only(left: 8.0, top: 4.r, bottom: 4.r),
|
||||
// child: CustomTextWidget(
|
||||
// isExpanded: false,
|
||||
// text: 'View Booking Rules',
|
||||
// fontColor: CustomAppColors.kBlackColor,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 10.sp,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RequestHolidayButton extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
|
||||
const RequestHolidayButton({super.key, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final BookHolidayScreenController controller =
|
||||
// Get.put(BookHolidayScreenController());
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 60.h,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: CustomAppColors.kSecondaryColor,
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
),
|
||||
child: const CustomTextWidget(
|
||||
text: "REQUEST HOLIDAY", fontColor: CustomAppColors.kPrimaryColor),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
82
lib/view/screens/rota/calendar_view_screen.dart
Normal file
82
lib/view/screens/rota/calendar_view_screen.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class CalendarScreen extends StatefulWidget {
|
||||
const CalendarScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<CalendarScreen> createState() => _CalendarScreenState();
|
||||
}
|
||||
|
||||
class _CalendarScreenState extends State<CalendarScreen> {
|
||||
final CalendarViewScreenController controller =
|
||||
Get.find<CalendarViewScreenController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.scaffoldKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
body: Obx(
|
||||
() => controller.isLoading.value
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
// Obx(
|
||||
// () => SetMonthAndYearWidget(
|
||||
// currentMonthName: controller.currentMonthName.value,
|
||||
// nextMonthTap: controller.onNextMonthTap,
|
||||
// previousMonthTap: controller.onPreviousMonthTap),
|
||||
// ),
|
||||
Obx(
|
||||
() => CalendarWidget(
|
||||
markedDatesMap: controller.events(),
|
||||
targetDateTime: controller.targetDateTime.value,
|
||||
onEventTap: (events) {
|
||||
if (events.isNotEmpty) {
|
||||
controller.selectedDate.value =
|
||||
MarkDatesModel.addDate(
|
||||
date: events.first.date,
|
||||
title: events.first.title ?? "");
|
||||
controller.datesToShowList.value = [
|
||||
RotaShift(
|
||||
name: "",
|
||||
staffRequired: "",
|
||||
workerType: "",
|
||||
location: "",
|
||||
startTime: controller.selectedDate.value.date
|
||||
.toIso8601String(),
|
||||
endTime: "",
|
||||
breakTime: "",
|
||||
notes: "")
|
||||
];
|
||||
}
|
||||
}),
|
||||
),
|
||||
10.verticalSpace,
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => ListView.builder(
|
||||
itemCount: controller.datesToShowList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
Rx<RotaShift> dateModel =
|
||||
controller.datesToShowList[index].obs;
|
||||
//Todo: RotaWidget need to reconfigure here
|
||||
return SizedBox.shrink();
|
||||
// return RotaWidget(
|
||||
// startDateTime: dateModel.value.shiftStartTime,
|
||||
// endDateTime: dateModel.value.shiftEndTime);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
5
lib/view/screens/rota/export_rota_screens.dart
Normal file
5
lib/view/screens/rota/export_rota_screens.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
export 'calendar_view_screen.dart';
|
||||
export 'rota_dashboard_screen.dart';
|
||||
export 'book_holiday_screen.dart';
|
||||
export 'pick_up_shifts_screen.dart';
|
||||
export 'your_rota_screen.dart';
|
||||
69
lib/view/screens/rota/new_rota_list_widget.dart
Normal file
69
lib/view/screens/rota/new_rota_list_widget.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/rota/WeekArrayData.dart';
|
||||
|
||||
class NewRotaListWidget extends StatelessWidget {
|
||||
final List<DaysArrayData> shifts;
|
||||
final Function(int index, DaysArrayData data)? onClaimShiftTap;
|
||||
final Function(int index, DaysArrayData data)? onCancelShiftTap;
|
||||
|
||||
final ScrollPhysics? physics;
|
||||
|
||||
const NewRotaListWidget({
|
||||
super.key,
|
||||
required this.shifts,
|
||||
this.onClaimShiftTap,
|
||||
this.onCancelShiftTap,
|
||||
this.physics,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return (shifts.isEmpty)
|
||||
? FrequentFunctions.centerText(text: "No shifts found")
|
||||
: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: shifts.length,
|
||||
physics: physics,
|
||||
padding: REdgeInsets.symmetric(horizontal: 20),
|
||||
separatorBuilder: (_, index) => 10.verticalSpace,
|
||||
itemBuilder: (_, index) {
|
||||
return RotaWidget(
|
||||
data: shifts[index],
|
||||
onViewShiftTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ShowRotaAlertDialog(
|
||||
data: shifts[index],
|
||||
onClaimShiftTap: () {
|
||||
if (onClaimShiftTap != null) {
|
||||
onClaimShiftTap!.call(index, shifts[index]);
|
||||
}
|
||||
},
|
||||
onCancelShiftTap: () {
|
||||
if (onCancelShiftTap != null) {
|
||||
onCancelShiftTap!.call(index, shifts[index]);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// onViewShiftTap(index, shifts[index])
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Container _upperTextWidget({required String text}) {
|
||||
// return Container(
|
||||
// padding: const EdgeInsets.only(left: 20),
|
||||
// child: Text(
|
||||
// text,
|
||||
// style: const TextStyle(
|
||||
// color: CustomAppColors.kLightTextColor, fontSize: 12),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
43
lib/view/screens/rota/pick_up_shifts_screen.dart
Normal file
43
lib/view/screens/rota/pick_up_shifts_screen.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'new_rota_list_widget.dart';
|
||||
|
||||
class PickUpShiftsScreen extends StatefulWidget {
|
||||
const PickUpShiftsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<PickUpShiftsScreen> createState() => _PickUpShiftsScreenState();
|
||||
}
|
||||
|
||||
class _PickUpShiftsScreenState extends State<PickUpShiftsScreen> {
|
||||
final _controller = Get.put(PickUpShiftsScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
screenKey: _controller.screenKey,
|
||||
onScreenTap: _controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(context, titleText: "Available Shifts"),
|
||||
body: _getBody(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getBody() {
|
||||
return Obx(
|
||||
() => _controller.loadingShifts()
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: NewRotaListWidget(
|
||||
shifts: _controller.myShiftsList(),
|
||||
onClaimShiftTap: _controller.claimShifts,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
206
lib/view/screens/rota/rota_dashboard_screen.dart
Normal file
206
lib/view/screens/rota/rota_dashboard_screen.dart
Normal file
@@ -0,0 +1,206 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/rota/WeekArrayData.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'new_rota_list_widget.dart';
|
||||
|
||||
class RotaDashboardScreen extends StatefulWidget {
|
||||
const RotaDashboardScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<RotaDashboardScreen> createState() => _RotaDashboardScreenState();
|
||||
}
|
||||
|
||||
class _RotaDashboardScreenState extends State<RotaDashboardScreen> {
|
||||
final _controller = Get.put(RotaDashboardScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
screenKey: _controller.screenKey,
|
||||
onScreenTap: _controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(context, titleText: 'Rota'),
|
||||
body: _tabWidget(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _tabWidget() {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 18.0.w,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buttons(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kPickUpShiftsScreenRoute,
|
||||
);
|
||||
},
|
||||
text: "Pick up Shifts")),
|
||||
24.horizontalSpace,
|
||||
Expanded(
|
||||
child: _buttons(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
CustomRouteNames.kBookHolidayScreenRoute,
|
||||
);
|
||||
},
|
||||
text: "Book a Holiday")),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: Get.width,
|
||||
alignment: Alignment.center,
|
||||
child: TabBar(
|
||||
controller: _controller.tabController,
|
||||
unselectedLabelColor: CustomAppColors.kLightGreyColor,
|
||||
labelColor: CustomAppColors.kSecondaryColor,
|
||||
labelPadding: const EdgeInsets.all(0),
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicatorColor: CustomAppColors.kSecondaryColor,
|
||||
tabs: const [
|
||||
Tab(
|
||||
child: Text(
|
||||
"List",
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Text(
|
||||
"Calendar",
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
//Change
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _controller.tabController,
|
||||
children: [_yourRotaListTabView, _calandarTabView()],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _calandarTabView() {
|
||||
return Column(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Obx(
|
||||
() {
|
||||
return CalendarWidget(
|
||||
key: UniqueKey(),
|
||||
markedDatesMap: _controller.markedDatesMap(),
|
||||
minDate: DateTime.now().subtract(40.days),
|
||||
targetDateTime: _controller.targetDateTime(),
|
||||
canSelectRange: false,
|
||||
onDayTap: _controller.onDateSelect,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => NewRotaListWidget(
|
||||
shifts: _controller.dateFilteredShiftsList(),
|
||||
onCancelShiftTap: (int index, DaysArrayData data) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _yourRotaListTabView {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_yourRotaHeader(),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => _controller.loadingShifts()
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: NewRotaListWidget(
|
||||
shifts: _controller.myShiftsList(),
|
||||
onCancelShiftTap: (int index, DaysArrayData data) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _yourRotaHeader() {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, CustomRouteNames.kYourRotaScreenRoute);
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: "Your Rota",
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
isExpanded: false,
|
||||
),
|
||||
const CustomImageWidget(
|
||||
imagePath: AssetsManager.kArrowNextIcon,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buttons({required VoidCallback onTap, required String text}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 42.r,
|
||||
width: double.maxFinite,
|
||||
padding: REdgeInsets.all(10).copyWith(right: 2.r),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: CustomAppColors.kSecondaryColor,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: text,
|
||||
isExpanded: false,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14.sp),
|
||||
Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
size: 20.r,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
92
lib/view/screens/rota/your_rota_screen.dart
Normal file
92
lib/view/screens/rota/your_rota_screen.dart
Normal file
@@ -0,0 +1,92 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/rota/WeekArrayData.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'new_rota_list_widget.dart';
|
||||
|
||||
class YourRotaScreen extends StatefulWidget {
|
||||
const YourRotaScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<YourRotaScreen> createState() => _YourRotaScreenState();
|
||||
}
|
||||
|
||||
class _YourRotaScreenState extends State<YourRotaScreen> {
|
||||
final controller = Get.put(YourRotaScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBar(
|
||||
showBoxShadow: false,
|
||||
leadingButton: Container(),
|
||||
titleWidget: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: CustomImageWidget(
|
||||
imagePath: AssetsManager.kBackIcon,
|
||||
height: 11.53.h,
|
||||
width: 8.66.w,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 15.w,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text: "Your Rota",
|
||||
isExpanded: false,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w700),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: _getBody(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getBody() {
|
||||
return Obx(
|
||||
() => controller.loadingShifts()
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: NewRotaListWidget(
|
||||
shifts: controller.myShiftsList(),
|
||||
onCancelShiftTap: (int index, DaysArrayData data) {},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// class UpperTextWidget extends StatelessWidget {
|
||||
// const UpperTextWidget({
|
||||
// super.key,
|
||||
// required this.text,
|
||||
// });
|
||||
//
|
||||
// final String text;
|
||||
//
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Container(
|
||||
// padding: const EdgeInsets.only(left: 20),
|
||||
// child: Text(
|
||||
// text,
|
||||
// style: const TextStyle(
|
||||
// color: CustomAppColors.kLightTextColor, fontSize: 12),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SettingsScreenController extends GetxController {
|
||||
final GlobalKey<ScaffoldState> screenKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void removeFocus() {
|
||||
FocusScope.of(screenKey.currentContext!).unfocus();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<SettingsScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
73
lib/view/screens/settings/settings_screen.dart
Normal file
73
lib/view/screens/settings/settings_screen.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/dialogs/app_dialogs.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../ftc_mobile_app.dart';
|
||||
import 'controller/settings_screen_controller.dart';
|
||||
|
||||
class SettingsScreen extends StatefulWidget {
|
||||
const SettingsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SettingsScreen> createState() => _SettingsScreenState();
|
||||
}
|
||||
|
||||
class _SettingsScreenState extends State<SettingsScreen> {
|
||||
final controller = Get.put(SettingsScreenController());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
// onBackButton: () => controller.backButtonPressed(context),
|
||||
backgroundColor: CustomAppColors.kPrimaryColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: "Settings",
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
const BuildIconButton(
|
||||
iconPath: AssetsManager.kBellIcon,
|
||||
text: 'Notification',
|
||||
route: CustomRouteNames.kAllCareNotesScreenRoute,
|
||||
arguments: null,
|
||||
),
|
||||
const BuildIconButton(
|
||||
iconPath: AssetsManager.kLockIcon,
|
||||
text: 'Change Password',
|
||||
route: CustomRouteNames.kCarePlanMenuScreenRoute,
|
||||
arguments: null,
|
||||
),
|
||||
20.verticalSpace,
|
||||
CustomAppButton(
|
||||
buttonText: "LOGOUT",
|
||||
buttonColor: CustomAppColors.kRedColor,
|
||||
borderColor: CustomAppColors.kRedColor,
|
||||
textColor: CustomAppColors.kPrimaryColor,
|
||||
onTap: () {
|
||||
AppDialog.alertAndLogout(() {
|
||||
FrequentFunctions().logoutButtonPressed(context);
|
||||
});
|
||||
},
|
||||
).addPaddingHorizontal(22),
|
||||
18.verticalSpace,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/training/TrainingResponseData.dart';
|
||||
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
|
||||
import 'package:ftc_mobile_app/utilities/frequent_functions.dart';
|
||||
import 'package:ftc_mobile_app/web_services/api_services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class TrainingsScreenController extends GetxController {
|
||||
final GlobalKey<ScaffoldState> screenKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
final trainings = <TrainingUsers>[].obs;
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
|
||||
getAllTrainings();
|
||||
}
|
||||
|
||||
void removeFocus() {
|
||||
FocusScope.of(screenKey.currentContext!).unfocus();
|
||||
}
|
||||
|
||||
getAllTrainings() async {
|
||||
final resp = await ApiService().allTrainingsList().showLoader();
|
||||
|
||||
if (resp is TrainingResponseData) {
|
||||
//Todo: change this static user id here
|
||||
trainings.value = resp.proposedTrainings ?? [];
|
||||
} else {
|
||||
if (resp.isNotNullOrEmpty()) {
|
||||
FrequentFunctions.showToast(message: resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.delete<TrainingsScreenController>();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
149
lib/view/screens/training/training_detail_screen.dart
Normal file
149
lib/view/screens/training/training_detail_screen.dart
Normal file
@@ -0,0 +1,149 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/models/training/TrainingResponseData.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class TrainingDetailScreenArgs {
|
||||
final TrainingUsers data;
|
||||
|
||||
TrainingDetailScreenArgs({required this.data});
|
||||
}
|
||||
|
||||
class TrainingDetailScreen extends StatefulWidget {
|
||||
final TrainingDetailScreenArgs args;
|
||||
|
||||
const TrainingDetailScreen({super.key, required this.args});
|
||||
|
||||
@override
|
||||
State<TrainingDetailScreen> createState() => _TrainingDetailScreenState();
|
||||
}
|
||||
|
||||
class _TrainingDetailScreenState extends State<TrainingDetailScreen> {
|
||||
ProposedTrainings? get _data => widget.args.data.trainingId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kWhiteColor,
|
||||
screenKey: GlobalKey(),
|
||||
onScreenTap: Get.focusScope?.unfocus,
|
||||
showAppBar: true,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: CustomTextWidget(
|
||||
text: "${_data?.prpsTrgType?.capitalizeFirst ?? ""} Training",
|
||||
fontColor: Colors.white,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
centerTitle: false,
|
||||
actions: const [
|
||||
CloseButton(color: Colors.white),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView(
|
||||
padding: REdgeInsets.symmetric(horizontal: 20),
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
_headerValueWidget(
|
||||
heading: 'Training Title',
|
||||
value: _data?.prpsName ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
_headerValueWidget(
|
||||
heading: 'Introduction',
|
||||
value: _data?.prpsDescription ?? "",
|
||||
),
|
||||
16.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _headerValueWidget(
|
||||
heading: 'Training Start Date',
|
||||
value: DateFormatter.dateFormatter2.format(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
_data?.prpsTrgStartDate ?? 0)),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _headerValueWidget(
|
||||
heading: 'Training End Date',
|
||||
value: DateFormatter.dateFormatter2.format(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
_data?.prpsTrgEndDate ?? 0)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
_headerValueWidget(
|
||||
heading: 'Training Registration Date',
|
||||
value: DateFormatter.dateFormatter2.format(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
_data?.prpsTrgRegisterationDate ?? 0)),
|
||||
),
|
||||
16.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _headerValueWidget(
|
||||
heading: 'Training Type',
|
||||
value: _data?.prpsTrgType?.capitalizeFirst ?? "",
|
||||
),
|
||||
),
|
||||
12.horizontalSpace,
|
||||
Expanded(
|
||||
child: _headerValueWidget(
|
||||
heading: 'Training Type',
|
||||
value: _data?.prpsTrgClass?.capitalizeFirst ?? "",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
16.verticalSpace,
|
||||
_headerValueWidget(
|
||||
heading: 'Training Status',
|
||||
value: _data?.prpsTrgStatus?.capitalizeFirst ?? "",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _headerValueWidget({required String heading, required String value}) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_heading(heading),
|
||||
3.verticalSpace,
|
||||
_subtext(value),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _heading(String text) {
|
||||
return Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.black,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _subtext(String text) {
|
||||
return Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
111
lib/view/screens/training/training_screen.dart
Normal file
111
lib/view/screens/training/training_screen.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:ftc_mobile_app/models/training/TrainingResponseData.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'controller/trainings_screen_controller.dart';
|
||||
import 'training_detail_screen.dart';
|
||||
|
||||
class TrainingsScreen extends StatefulWidget {
|
||||
const TrainingsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TrainingsScreen> createState() => _TrainingsScreenState();
|
||||
}
|
||||
|
||||
class _TrainingsScreenState extends State<TrainingsScreen> {
|
||||
final controller = Get.put(TrainingsScreenController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScaffold(
|
||||
backgroundColor: CustomAppColors.kSmokeColor,
|
||||
screenKey: controller.screenKey,
|
||||
onScreenTap: controller.removeFocus,
|
||||
showAppBar: true,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: "Training",
|
||||
),
|
||||
body: SafeArea(
|
||||
child: _listView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _listView() {
|
||||
return Obx(() {
|
||||
final list = controller.trainings();
|
||||
return (list.isEmpty)
|
||||
? Container(
|
||||
color: Colors.white,
|
||||
child: const Center(
|
||||
child: Text("No data found"),
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (_, index) {
|
||||
final item = list[index];
|
||||
return _listItem(item);
|
||||
},
|
||||
separatorBuilder: (_, i) => 8.verticalSpace,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _listItem(TrainingUsers item) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Get.toNamed(CustomRouteNames.kTrainingDetailScreen,
|
||||
arguments: TrainingDetailScreenArgs(data: item));
|
||||
},
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(color: Colors.white),
|
||||
padding: REdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CustomTextWidget(
|
||||
text: item.trainingId?.prpsName ?? "",
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
CustomTextWidget(
|
||||
text:
|
||||
"Start date: ${DateFormatter.dateFormatter2.format(DateTime.fromMillisecondsSinceEpoch(item.trainingId?.prpsTrgStartDate ?? 0).toLocal())}",
|
||||
fontColor: Colors.grey,
|
||||
textAlign: TextAlign.left,
|
||||
fontSize: 12.sp,
|
||||
),
|
||||
4.verticalSpace,
|
||||
CustomTextWidget(
|
||||
text:
|
||||
"Status: ${item.trainingId?.prpsTrgStatus?.capitalizeFirst ?? ""}",
|
||||
textAlign: TextAlign.left,
|
||||
fontColor: Colors.black,
|
||||
fontSize: 14.sp,
|
||||
maxLines: 3,
|
||||
fontWeight: FontWeight.w500,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(Icons.keyboard_arrow_right_rounded)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class WebviewScreenController extends GetxController {
|
||||
final isLoading = false.obs;
|
||||
}
|
||||
92
lib/view/screens/webview/webview_screen.dart
Normal file
92
lib/view/screens/webview/webview_screen.dart
Normal file
@@ -0,0 +1,92 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'controller/webview_screen_controller.dart';
|
||||
|
||||
class WebviewScreenArgument {
|
||||
final String title;
|
||||
final String url;
|
||||
final bool willPop;
|
||||
|
||||
WebviewScreenArgument(
|
||||
{Key? key, required this.title, required this.url, this.willPop = true});
|
||||
}
|
||||
|
||||
class WebviewScreen extends StatefulWidget {
|
||||
final WebviewScreenArgument args;
|
||||
|
||||
const WebviewScreen({Key? key, required this.args}) : super(key: key);
|
||||
|
||||
@override
|
||||
_WebviewScreenState createState() => _WebviewScreenState();
|
||||
}
|
||||
|
||||
class _WebviewScreenState extends State<WebviewScreen> {
|
||||
final controller =
|
||||
Get.put<WebviewScreenController>(WebviewScreenController());
|
||||
late final WebViewController webViewController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
webViewController = WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setBackgroundColor(const Color(0x00000000))
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
onProgress: (int progress) {},
|
||||
onPageStarted: (String url) {
|
||||
controller.isLoading.value = true;
|
||||
},
|
||||
onPageFinished: (String url) {
|
||||
controller.isLoading.value = false;
|
||||
},
|
||||
onHttpError: (HttpResponseError error) {},
|
||||
onWebResourceError: (WebResourceError error) {},
|
||||
onNavigationRequest: (NavigationRequest request) {
|
||||
if (request.url.startsWith('https://www.youtube.com/')) {
|
||||
return NavigationDecision.prevent;
|
||||
}
|
||||
return NavigationDecision.navigate;
|
||||
},
|
||||
),
|
||||
)
|
||||
..loadRequest(Uri.parse(widget.args.url));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: CustomAppBarTitleOnly(
|
||||
context,
|
||||
titleText: widget.args.title,
|
||||
),
|
||||
body: Obx(() {
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
// child: WebViewWidget(controller: webController),
|
||||
child: WebViewWidget(controller: webViewController),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: (controller.isLoading())
|
||||
? Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: Get.theme.primaryColor))
|
||||
: FrequentFunctions.noWidget,
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user