no message
parent
ca6ce85d7d
commit
9638d98b76
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 190 B |
Binary file not shown.
|
After Width: | Height: | Size: 778 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 778 KiB |
@ -0,0 +1,92 @@
|
||||
class GetMobileLoginInfoDependentModel {
|
||||
int? iD;
|
||||
String? dependentID;
|
||||
String? depedentName;
|
||||
String? dob;
|
||||
int? channelID;
|
||||
int? companyID;
|
||||
String? deviceType;
|
||||
String? deviceToken;
|
||||
int? language;
|
||||
int? gender;
|
||||
int? loginType;
|
||||
String? createdOn;
|
||||
String? editedOn;
|
||||
bool? businessCardPrivilege;
|
||||
|
||||
GetMobileLoginInfoDependentModel({
|
||||
this.iD,
|
||||
this.dependentID,
|
||||
this.depedentName,
|
||||
this.dob,
|
||||
this.channelID,
|
||||
this.companyID,
|
||||
this.deviceType,
|
||||
this.deviceToken,
|
||||
this.language,
|
||||
this.gender,
|
||||
this.loginType,
|
||||
this.createdOn,
|
||||
this.editedOn,
|
||||
this.businessCardPrivilege,
|
||||
});
|
||||
|
||||
// Convenience aliases for existing logic
|
||||
String? get nationalId => dependentID;
|
||||
String? get birthDate => dob;
|
||||
String? get employeeName => depedentName;
|
||||
String? get dependentName => depedentName;
|
||||
|
||||
GetMobileLoginInfoDependentModel.fromJson(Map<String, dynamic> json) {
|
||||
iD = json['ID'];
|
||||
dependentID = (json['DependentID'] ??
|
||||
json['DEPENDENT_ID'] ??
|
||||
json['P_DEP_NATIONAL_ID'] ??
|
||||
json['NationalID'] ??
|
||||
json['NationalId'] ??
|
||||
json['EmployeeID'] ??
|
||||
json['UserName'])
|
||||
?.toString();
|
||||
depedentName = (json['DepedentName'] ??
|
||||
json['DependentName'] ??
|
||||
json['P_DEPENDENT_NAME'] ??
|
||||
json['EmployeeName'])
|
||||
?.toString();
|
||||
dob = (json['DOB'] ??
|
||||
json['BirthDate'] ??
|
||||
json['DateOfBirth'] ??
|
||||
json['P_DEP_BIRTH_DATE'] ??
|
||||
json['P_BIRTH_DATE'] ??
|
||||
json['Birth_Date'])
|
||||
?.toString();
|
||||
channelID = json['ChannelID'] != null ? int.tryParse(json['ChannelID'].toString()) : null;
|
||||
companyID = json['CompanyID'] != null ? int.tryParse(json['CompanyID'].toString()) : null;
|
||||
deviceType = json['DeviceType']?.toString();
|
||||
deviceToken = json['DeviceToken']?.toString();
|
||||
language = json['Language'] != null ? int.tryParse(json['Language'].toString()) : null;
|
||||
gender = json['Gender'] != null ? int.tryParse(json['Gender'].toString()) : null;
|
||||
loginType = json['LoginType'] != null ? int.tryParse(json['LoginType'].toString()) : null;
|
||||
createdOn = json['CreatedOn']?.toString();
|
||||
editedOn = json['EditedOn']?.toString();
|
||||
businessCardPrivilege = json['BusinessCardPrivilege'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['ID'] = iD;
|
||||
data['DependentID'] = dependentID;
|
||||
data['DepedentName'] = depedentName;
|
||||
data['DOB'] = dob;
|
||||
data['ChannelID'] = channelID;
|
||||
data['CompanyID'] = companyID;
|
||||
data['DeviceType'] = deviceType;
|
||||
data['DeviceToken'] = deviceToken;
|
||||
data['Language'] = language;
|
||||
data['Gender'] = gender;
|
||||
data['LoginType'] = loginType;
|
||||
data['CreatedOn'] = createdOn;
|
||||
data['EditedOn'] = editedOn;
|
||||
data['BusinessCardPrivilege'] = businessCardPrivilege;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,139 @@
|
||||
class PatientInfoModel {
|
||||
int? age;
|
||||
String? dateOfBirth;
|
||||
String? firstNameAr;
|
||||
String? firstNameEn;
|
||||
String? secondNameAr;
|
||||
String? secondNameEn;
|
||||
String? thirdNameAr;
|
||||
String? thirdNameEn;
|
||||
String? lastNameAr;
|
||||
String? lastNameEn;
|
||||
String? gender;
|
||||
String? healthId;
|
||||
String? idNumber;
|
||||
String? idType;
|
||||
bool? isHijri;
|
||||
String? maritalStatus;
|
||||
String? maritalStatusCode;
|
||||
String? nationalDateOfBirth;
|
||||
String? nationality;
|
||||
String? nationalityCode;
|
||||
String? occupation;
|
||||
String? patientStatus;
|
||||
String? placeOfBirth;
|
||||
int? messageStatus;
|
||||
String? errorEndUserMessage;
|
||||
String? errorMessage;
|
||||
|
||||
PatientInfoModel({
|
||||
this.age,
|
||||
this.dateOfBirth,
|
||||
this.firstNameAr,
|
||||
this.firstNameEn,
|
||||
this.secondNameAr,
|
||||
this.secondNameEn,
|
||||
this.thirdNameAr,
|
||||
this.thirdNameEn,
|
||||
this.lastNameAr,
|
||||
this.lastNameEn,
|
||||
this.gender,
|
||||
this.healthId,
|
||||
this.idNumber,
|
||||
this.idType,
|
||||
this.isHijri,
|
||||
this.maritalStatus,
|
||||
this.maritalStatusCode,
|
||||
this.nationalDateOfBirth,
|
||||
this.nationality,
|
||||
this.nationalityCode,
|
||||
this.occupation,
|
||||
this.patientStatus,
|
||||
this.placeOfBirth,
|
||||
this.messageStatus,
|
||||
this.errorEndUserMessage,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
factory PatientInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
return PatientInfoModel(
|
||||
age: json['Age'],
|
||||
dateOfBirth: json['DateOfBirth'],
|
||||
firstNameAr: json['FirstNameAr'],
|
||||
firstNameEn: json['FirstNameEn'],
|
||||
secondNameAr: json['SecondNameAr'],
|
||||
secondNameEn: json['SecondNameEn'],
|
||||
thirdNameAr: json['ThirdNameAr'],
|
||||
thirdNameEn: json['ThirdNameEn'],
|
||||
lastNameAr: json['LastNameAr'],
|
||||
lastNameEn: json['LastNameEn'],
|
||||
gender: json['Gender'],
|
||||
healthId: json['HealthId'],
|
||||
idNumber: json['IdNumber'],
|
||||
idType: json['IdType'],
|
||||
isHijri: json['IsHijri'],
|
||||
maritalStatus: json['MaritalStatus'],
|
||||
maritalStatusCode: json['MaritalStatusCode'],
|
||||
nationalDateOfBirth: json['NationalDateOfBirth'],
|
||||
nationality: json['Nationality'],
|
||||
nationalityCode: json['NationalityCode'],
|
||||
occupation: json['Occupation'],
|
||||
patientStatus: json['PatientStatus']?.toString(),
|
||||
placeOfBirth: json['PlaceofBirth'],
|
||||
messageStatus: json['MessageStatus'],
|
||||
errorEndUserMessage: json['ErrorEndUserMessage'],
|
||||
errorMessage: json['ErrorMessage'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'Age': age,
|
||||
'DateOfBirth': dateOfBirth,
|
||||
'FirstNameAr': firstNameAr,
|
||||
'FirstNameEn': firstNameEn,
|
||||
'SecondNameAr': secondNameAr,
|
||||
'SecondNameEn': secondNameEn,
|
||||
'ThirdNameAr': thirdNameAr,
|
||||
'ThirdNameEn': thirdNameEn,
|
||||
'LastNameAr': lastNameAr,
|
||||
'LastNameEn': lastNameEn,
|
||||
'Gender': gender,
|
||||
'HealthId': healthId,
|
||||
'IdNumber': idNumber,
|
||||
'IdType': idType,
|
||||
'IsHijri': isHijri,
|
||||
'MaritalStatus': maritalStatus,
|
||||
'MaritalStatusCode': maritalStatusCode,
|
||||
'NationalDateOfBirth': nationalDateOfBirth,
|
||||
'Nationality': nationality,
|
||||
'NationalityCode': nationalityCode,
|
||||
'Occupation': occupation,
|
||||
'PatientStatus': patientStatus,
|
||||
'PlaceofBirth': placeOfBirth,
|
||||
'MessageStatus': messageStatus,
|
||||
'ErrorEndUserMessage': errorEndUserMessage,
|
||||
'ErrorMessage': errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
String get fullNameAr {
|
||||
List<String> parts = [
|
||||
firstNameAr ?? '',
|
||||
secondNameAr ?? '',
|
||||
(thirdNameAr != null && thirdNameAr != '-') ? thirdNameAr! : '',
|
||||
lastNameAr ?? '',
|
||||
].where((s) => s.trim().isNotEmpty && s != '-').toList();
|
||||
return parts.join(' ').trim();
|
||||
}
|
||||
|
||||
String get fullNameEn {
|
||||
List<String> parts = [
|
||||
firstNameEn ?? '',
|
||||
secondNameEn ?? '',
|
||||
(thirdNameEn != null && thirdNameEn != '-') ? thirdNameEn! : '',
|
||||
lastNameEn ?? '',
|
||||
].where((s) => s.trim().isNotEmpty && s != '-').toList();
|
||||
return parts.join(' ').trim();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,674 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
||||
import 'package:mohem_flutter_app/classes/utils.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class MazayaAccessResultParams {
|
||||
final bool isGranted;
|
||||
final String dependentName;
|
||||
final String? dependentInitials;
|
||||
final String? downloadUrl;
|
||||
|
||||
const MazayaAccessResultParams({
|
||||
required this.isGranted,
|
||||
required this.dependentName,
|
||||
this.dependentInitials,
|
||||
this.downloadUrl,
|
||||
});
|
||||
}
|
||||
|
||||
class _ShieldPainter extends CustomPainter {
|
||||
final Color color;
|
||||
final bool isGranted;
|
||||
|
||||
_ShieldPainter({required this.color, required this.isGranted});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
Paint paint = Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2.4
|
||||
..strokeCap = StrokeCap.round
|
||||
..strokeJoin = StrokeJoin.round;
|
||||
|
||||
double w = size.width;
|
||||
double h = size.height;
|
||||
|
||||
// Shield path
|
||||
Path path = Path();
|
||||
path.moveTo(w * 0.5, h * 0.1);
|
||||
path.cubicTo(w * 0.72, h * 0.1, w * 0.88, h * 0.18, w * 0.88, h * 0.38);
|
||||
path.cubicTo(w * 0.88, h * 0.65, w * 0.68, h * 0.84, w * 0.5, h * 0.92);
|
||||
path.cubicTo(w * 0.32, h * 0.84, w * 0.12, h * 0.65, w * 0.12, h * 0.38);
|
||||
path.cubicTo(w * 0.12, h * 0.18, w * 0.28, h * 0.1, w * 0.5, h * 0.1);
|
||||
path.close();
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
|
||||
if (isGranted) {
|
||||
// Checkmark path
|
||||
Path checkPath = Path();
|
||||
checkPath.moveTo(w * 0.34, h * 0.49);
|
||||
checkPath.lineTo(w * 0.46, h * 0.61);
|
||||
checkPath.lineTo(w * 0.66, h * 0.39);
|
||||
canvas.drawPath(checkPath, paint);
|
||||
} else {
|
||||
// Cross path
|
||||
canvas.drawLine(
|
||||
Offset(w * 0.38, h * 0.38),
|
||||
Offset(w * 0.62, h * 0.62),
|
||||
paint,
|
||||
);
|
||||
canvas.drawLine(
|
||||
Offset(w * 0.62, h * 0.38),
|
||||
Offset(w * 0.38, h * 0.62),
|
||||
paint,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant _ShieldPainter oldDelegate) =>
|
||||
color != oldDelegate.color || isGranted != oldDelegate.isGranted;
|
||||
}
|
||||
|
||||
class MazayaAccessResultScreen extends StatelessWidget {
|
||||
final bool isGranted;
|
||||
final String dependentName;
|
||||
final String? dependentInitials;
|
||||
final String? downloadUrl;
|
||||
|
||||
const MazayaAccessResultScreen({
|
||||
Key? key,
|
||||
this.isGranted = true,
|
||||
this.dependentName = "",
|
||||
this.dependentInitials,
|
||||
this.downloadUrl,
|
||||
}) : super(key: key);
|
||||
|
||||
static String getDownloadLink() {
|
||||
int channel = AppState().postParamsObject?.channel ?? 31;
|
||||
bool isIos = Platform.isIOS;
|
||||
if (channel == 33) {
|
||||
return isIos
|
||||
? "https://apps.apple.com/sa/app/al-habib-mohem/id1480157255"
|
||||
: "https://play.google.com/store/apps/details?id=com.cloudsolutions.alhabibmohemm&hl=en";
|
||||
} else {
|
||||
return isIos
|
||||
? "https://apps.apple.com/sa/app/mohemm/id1468856602"
|
||||
: "https://play.google.com/store/apps/details?id=hmg.cloudSolutions.mohem&hl=en";
|
||||
}
|
||||
}
|
||||
|
||||
String _getInitials(String? name) {
|
||||
if (name == null || name.trim().isEmpty) return "D";
|
||||
List<String> parts = name.trim().split(RegExp(r'\s+')).where((String p) => p.isNotEmpty).toList();
|
||||
if (parts.isEmpty) return "D";
|
||||
if (parts.length == 1) {
|
||||
return parts.first.length >= 2 ? parts.first.substring(0, 2).toUpperCase() : parts.first.toUpperCase();
|
||||
}
|
||||
return "${parts.first[0]}${parts.last[0]}".toUpperCase();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isAr = AppState().isArabic(context);
|
||||
String fontFamily = isAr ? 'Cairo' : 'Poppins';
|
||||
|
||||
// Resolve arguments if passed via ModalRoute
|
||||
Object? routeArgs = ModalRoute.of(context)?.settings.arguments;
|
||||
bool effectiveGranted = isGranted;
|
||||
String effectiveName = dependentName;
|
||||
String? effectiveInitials = dependentInitials;
|
||||
String? effectiveUrl = downloadUrl;
|
||||
|
||||
if (routeArgs is MazayaAccessResultParams) {
|
||||
effectiveGranted = routeArgs.isGranted;
|
||||
effectiveName = routeArgs.dependentName;
|
||||
effectiveInitials = routeArgs.dependentInitials;
|
||||
effectiveUrl = routeArgs.downloadUrl;
|
||||
} else if (routeArgs is Map<String, dynamic>) {
|
||||
effectiveGranted = routeArgs['isGranted'] ?? isGranted;
|
||||
effectiveName = routeArgs['dependentName'] ?? dependentName;
|
||||
effectiveInitials = routeArgs['dependentInitials'] ?? dependentInitials;
|
||||
effectiveUrl = routeArgs['downloadUrl'] ?? downloadUrl;
|
||||
}
|
||||
|
||||
String linkToShare = effectiveUrl ?? getDownloadLink();
|
||||
String initials = effectiveInitials ?? _getInitials(effectiveName);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(56),
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
height: 56,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
size: 20,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
LocaleKeys.mazayaTitle.tr().toText20(
|
||||
isBold: true,
|
||||
color: const Color(0xFF1E293B),
|
||||
),
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
Icons.close_rounded,
|
||||
size: 24,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(20, 16, 20, 20),
|
||||
child: effectiveGranted
|
||||
? _buildGrantedContent(context, isAr, fontFamily, effectiveName, initials, linkToShare)
|
||||
: _buildRevokedContent(context, isAr, fontFamily, effectiveName, initials),
|
||||
),
|
||||
),
|
||||
_buildBottomButtons(context, isAr, fontFamily, effectiveGranted, linkToShare),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildGrantedContent(
|
||||
BuildContext context,
|
||||
bool isAr,
|
||||
String fontFamily,
|
||||
String name,
|
||||
String initials,
|
||||
String linkToShare,
|
||||
) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Shield checkmark badge
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFE6F7F2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: CustomPaint(
|
||||
size: const Size(40, 40),
|
||||
painter: _ShieldPainter(
|
||||
color: const Color(0xFF168A89),
|
||||
isGranted: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Title
|
||||
LocaleKeys.mazayaAccessGranted.tr().toText22(
|
||||
isBold: true,
|
||||
isCentered: true,
|
||||
color: const Color(0xFF1E293B),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Description
|
||||
LocaleKeys.mazayaAccessGrantedDesc.tr(args: <String>[name]).toText14(
|
||||
isCenter: true,
|
||||
color: const Color(0xFF64748B),
|
||||
),
|
||||
|
||||
const SizedBox(height: 22),
|
||||
|
||||
// Access is now active banner
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE8F8F0),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFFCEEFE7), width: 1),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
child: Icon(
|
||||
Icons.check_circle_outline_rounded,
|
||||
color: Color(0xFF168A89),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
LocaleKeys.accessIsNowActive.tr().toText14(
|
||||
isBold: true,
|
||||
color: const Color(0xFF168A89),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
LocaleKeys.accessIsNowActiveDesc.tr(args: <String>[name]).toText12(
|
||||
color: const Color(0xFF64748B),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Dependent Card
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFFF1F5F9)),
|
||||
boxShadow: const <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Color(0x08000000),
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 3),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 42,
|
||||
height: 42,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFE6F7F2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: initials.toText14(
|
||||
isBold: true,
|
||||
color: const Color(0xFF168A89),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
name.toText14(
|
||||
isBold: true,
|
||||
maxlines: 1,
|
||||
color: const Color(0xFF1E293B),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
LocaleKeys.dependentAccessActive.tr().toText12(
|
||||
isBold: true,
|
||||
color: const Color(0xFF168A89),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.lock_open_rounded,
|
||||
color: Color(0xFF168A89),
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Shareable App-Download Link Card
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFFE2E8F0)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE8F8F0),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.smartphone_rounded,
|
||||
color: Color(0xFF168A89),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
LocaleKeys.shareableAppDownloadLink.tr().toText14(
|
||||
isBold: true,
|
||||
color: const Color(0xFF1E293B),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
LocaleKeys.shareableAppDownloadLinkDesc.tr(args: <String>[name]).toText12(
|
||||
color: const Color(0xFF64748B),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF8FAFC),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: const Color(0xFFE2E8F0)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
LocaleKeys.downloadLink.tr().toText11(
|
||||
isBold: true,
|
||||
color: const Color(0xFF168A89),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
linkToShare.toText12(
|
||||
maxLine: 1,
|
||||
color: const Color(0xFF334155),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRevokedContent(
|
||||
BuildContext context,
|
||||
bool isAr,
|
||||
String fontFamily,
|
||||
String name,
|
||||
String initials,
|
||||
) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Shield bad badge
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFFEECEB),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: CustomPaint(
|
||||
size: const Size(40, 40),
|
||||
painter: _ShieldPainter(
|
||||
color: const Color(0xFFED1C24),
|
||||
isGranted: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Title
|
||||
LocaleKeys.mazayaAccessRevoked.tr().toText22(
|
||||
isBold: true,
|
||||
isCentered: true,
|
||||
color: const Color(0xFF1E293B),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Description
|
||||
LocaleKeys.mazayaAccessRevokedDesc.tr().toText14(
|
||||
isCenter: true,
|
||||
color: const Color(0xFF64748B),
|
||||
),
|
||||
|
||||
const SizedBox(height: 22),
|
||||
|
||||
// Contact your sponsor banner
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFFF5F5),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFFFFCDD2), width: 1),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
child: Icon(
|
||||
Icons.phone_outlined,
|
||||
color: Color(0xFFED1C24),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
LocaleKeys.contactYourSponsor.tr().toText14(
|
||||
isBold: true,
|
||||
color: const Color(0xFFED1C24),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
LocaleKeys.contactYourSponsorDesc.tr().toText12(
|
||||
color: const Color(0xFF64748B),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Dependent Card
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFFF1F5F9)),
|
||||
boxShadow: const <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: Color(0x08000000),
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 3),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 42,
|
||||
height: 42,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFFFF1F0),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: initials.toText14(
|
||||
isBold: true,
|
||||
color: const Color(0xFFED1C24),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
name.toText14(
|
||||
isBold: true,
|
||||
maxlines: 1,
|
||||
color: const Color(0xFF1E293B),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
LocaleKeys.dependentAccessBlocked.tr().toText12(
|
||||
isBold: true,
|
||||
color: const Color(0xFFED1C24),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.lock_outline_rounded,
|
||||
color: Color(0xFFED1C24),
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomButtons(
|
||||
BuildContext context,
|
||||
bool isAr,
|
||||
String fontFamily,
|
||||
bool granted,
|
||||
String linkToShare,
|
||||
) {
|
||||
if (granted) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.fromLTRB(20, 10, 20, 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
DefaultButton(
|
||||
LocaleKeys.shareDownloadLink.tr(),
|
||||
() async {
|
||||
try {
|
||||
await SharePlus.instance.share(ShareParams(text: linkToShare));
|
||||
} catch (_) {}
|
||||
},
|
||||
trailingIconData: isAr ? Icons.arrow_back_rounded : Icons.arrow_forward_rounded,
|
||||
fontSize: 14,
|
||||
isTextExpanded: false,
|
||||
height: 48,
|
||||
borderRadius: 12,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
DefaultButton(
|
||||
LocaleKeys.copyLink.tr(),
|
||||
() {
|
||||
Clipboard.setData(ClipboardData(text: linkToShare));
|
||||
Utils.showToast(LocaleKeys.linkCopied.tr());
|
||||
},
|
||||
colors: const <Color>[Colors.white, Colors.white],
|
||||
border: Border.all(color: const Color(0xFFCBD5E1)),
|
||||
textColor: const Color(0xFF168A89),
|
||||
fontSize: 14,
|
||||
isTextExpanded: false,
|
||||
height: 48,
|
||||
borderRadius: 12,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
DefaultButton(
|
||||
LocaleKeys.done.tr(),
|
||||
() => Navigator.pop(context),
|
||||
colors: const <Color>[Colors.white, Colors.white],
|
||||
border: Border.all(color: const Color(0xFFCBD5E1)),
|
||||
textColor: const Color(0xFF334155),
|
||||
fontSize: 14,
|
||||
isTextExpanded: false,
|
||||
height: 48,
|
||||
borderRadius: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.fromLTRB(20, 10, 20, 20),
|
||||
child: DefaultButton(
|
||||
LocaleKeys.returnToSignIn.tr(),
|
||||
() => Navigator.pop(context),
|
||||
colors: const <Color>[Colors.white, Colors.white],
|
||||
border: Border.all(color: const Color(0xFFCEEFE7), width: 1.2),
|
||||
textColor: const Color(0xFF168A89),
|
||||
iconData: isAr ? Icons.arrow_forward_rounded : Icons.arrow_back_rounded,
|
||||
fontSize: 14,
|
||||
isTextExpanded: false,
|
||||
height: 48,
|
||||
borderRadius: 12,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,153 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:mohem_flutter_app/classes/consts.dart';
|
||||
import 'package:mohem_flutter_app/config/routes.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class AppInAppWebViewScreen extends StatefulWidget {
|
||||
final String url;
|
||||
final String? title;
|
||||
|
||||
const AppInAppWebViewScreen({
|
||||
Key? key,
|
||||
required this.url,
|
||||
this.title,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AppInAppWebViewScreen> createState() => _AppInAppWebViewScreenState();
|
||||
}
|
||||
|
||||
class _AppInAppWebViewScreenState extends State<AppInAppWebViewScreen> {
|
||||
InAppWebViewController? _webViewController;
|
||||
double _progress = 0;
|
||||
String _title = "";
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_title = widget.title ?? "";
|
||||
_requestCameraPermission();
|
||||
}
|
||||
|
||||
Future<void> _requestCameraPermission() async {
|
||||
try {
|
||||
PermissionStatus cameraStatus = await Permission.camera.status;
|
||||
if (!cameraStatus.isGranted) {
|
||||
await Permission.camera.request();
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error requesting camera permission: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void _onHomeTapped() {
|
||||
if (ApiConsts.isDependetLogin) {
|
||||
Navigator.popUntil(context, ModalRoute.withName(AppRoutes.dashboardScreenForDependet));
|
||||
} else {
|
||||
Navigator.popUntil(context, ModalRoute.withName(AppRoutes.dashboard));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleBack() async {
|
||||
if (_webViewController != null && await _webViewController!.canGoBack()) {
|
||||
await _webViewController!.goBack();
|
||||
} else {
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String displayTitle = _title.isNotEmpty ? _title : LocaleKeys.offerDetails.tr();
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (bool didPop, Object? result) async {
|
||||
if (didPop) return;
|
||||
await _handleBack();
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBarWidget(
|
||||
context,
|
||||
title: displayTitle,
|
||||
showHomeButton: true,
|
||||
onHomeTapped: _onHomeTapped,
|
||||
onBackTapped: () async {
|
||||
await _handleBack();
|
||||
},
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
InAppWebView(
|
||||
initialUrlRequest: URLRequest(url: WebUri(widget.url)),
|
||||
initialSettings: InAppWebViewSettings(
|
||||
javaScriptEnabled: true,
|
||||
domStorageEnabled: true,
|
||||
supportZoom: true,
|
||||
mediaPlaybackRequiresUserGesture: false,
|
||||
allowsInlineMediaPlayback: true,
|
||||
javaScriptCanOpenWindowsAutomatically: true,
|
||||
transparentBackground: false,
|
||||
useShouldOverrideUrlLoading: false,
|
||||
cacheEnabled: true,
|
||||
clearCache: false,
|
||||
),
|
||||
onWebViewCreated: (InAppWebViewController controller) {
|
||||
_webViewController = controller;
|
||||
},
|
||||
onPermissionRequest: (InAppWebViewController controller, PermissionRequest permissionRequest) async {
|
||||
debugPrint("InAppWebView onPermissionRequest: ${permissionRequest.resources}");
|
||||
try {
|
||||
PermissionStatus status = await Permission.camera.status;
|
||||
if (!status.isGranted) {
|
||||
await Permission.camera.request();
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error requesting camera permission: $e");
|
||||
}
|
||||
return PermissionResponse(
|
||||
resources: permissionRequest.resources,
|
||||
action: PermissionResponseAction.GRANT,
|
||||
);
|
||||
},
|
||||
onProgressChanged: (InAppWebViewController controller, int progress) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_progress = progress / 100;
|
||||
});
|
||||
}
|
||||
},
|
||||
onTitleChanged: (InAppWebViewController controller, String? title) {
|
||||
if (widget.title == null || widget.title!.isEmpty) {
|
||||
if (title != null && title.isNotEmpty && !title.startsWith("http")) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_title = title;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
if (_progress < 1.0)
|
||||
LinearProgressIndicator(
|
||||
value: _progress,
|
||||
color: const Color(0xFF168A89),
|
||||
backgroundColor: Colors.transparent,
|
||||
minHeight: 2.5,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue