structure 1.0
parent
03c598bf64
commit
b6ac85e220
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"mohemm": "Mohemm",
|
||||||
|
"english": "English",
|
||||||
|
"arabic": "عربي",
|
||||||
|
"login": "Login",
|
||||||
|
"pleaseEnterLoginDetails": "Please enter the detail below to login",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password",
|
||||||
|
"welcomeBack": "Welcome back",
|
||||||
|
"wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?",
|
||||||
|
"lastLoginDetails": "Last Login Details:",
|
||||||
|
"verificationType": "Verification Type:",
|
||||||
|
"pleaseVerify": "Please Verify",
|
||||||
|
"pleaseVerifyForBio": "Please verify login with one of the following options",
|
||||||
|
"verifyThroughFace": "Verify Through Face",
|
||||||
|
"verifyThroughFingerprint": "Verify Through Fingerprint",
|
||||||
|
"verifyThroughSMS": "Verify Through SMS",
|
||||||
|
"verifyThroughWhatsapp": "Verify Through Whatsapp",
|
||||||
|
"useAnotherAccount": "Use Another Account",
|
||||||
|
"pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ",
|
||||||
|
"theVerificationCodeWillExpireIn": "The verification code will expire in ",
|
||||||
|
"goodMorning": "Good Morning",
|
||||||
|
"markAttendance": "Mark Attendance",
|
||||||
|
"timeLeftToday": "Time Left Today",
|
||||||
|
"checkIn": "Check In",
|
||||||
|
"workList": "Work List",
|
||||||
|
"leaveBalance": "Leave Balance",
|
||||||
|
"missingSwipes": "Missing Swipes",
|
||||||
|
"ticketBalance": "Ticket Balance",
|
||||||
|
"other": "Other",
|
||||||
|
"services": "Services",
|
||||||
|
"viewAllServices": "View All Services",
|
||||||
|
"monthlyAttendance": "Monthly Attendance",
|
||||||
|
"vacationRule": "Vacation Rule",
|
||||||
|
"vacationType": "Vacation Type",
|
||||||
|
"startDateT": "Start Date",
|
||||||
|
"endDateT": "End Date",
|
||||||
|
"workFromHome": "Work From Home",
|
||||||
|
"ticketRequest": "Ticket Request",
|
||||||
|
"viewAllOffers": "View All Offers",
|
||||||
|
"offers": "Offers & ",
|
||||||
|
"discounts": "Discounts",
|
||||||
|
"newString": "New",
|
||||||
|
"setTheNewPassword": "Set the new password",
|
||||||
|
"typeYourNewPasswordBelow": "Type your new password below",
|
||||||
|
"confirmPassword": "Confirm Password",
|
||||||
|
"update": "Update",
|
||||||
|
"title": "Title",
|
||||||
|
"home": "Home",
|
||||||
|
"mySalary": "My Salary",
|
||||||
|
"createRequest": "Create Request",
|
||||||
|
"forgotPassword": "Forgot Password",
|
||||||
|
"employeeId": "Employee ID",
|
||||||
|
"loginCodeWillSentToMobileNumber": "Please Enter your Employee ID, A login code will be sent to your mobile number",
|
||||||
|
"changePassword": "Change Password",
|
||||||
|
"ok": "OK",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"passwordChangedSuccessfully": "Password changed successfully",
|
||||||
|
"itemsForSale": "Items for Sale",
|
||||||
|
"attendanceDetails": "Attendance Details",
|
||||||
|
"order": "order",
|
||||||
|
"earlyOut": "Early Out",
|
||||||
|
"shortage": "Shortage",
|
||||||
|
"excess": "Excess",
|
||||||
|
"lateIn": "Late In",
|
||||||
|
"approvedCheckOut": "Approved Check Out",
|
||||||
|
"approvedCheckIn": "Approved Check In",
|
||||||
|
"actualCheckOut": "Actual Check Out",
|
||||||
|
"actualCheckIn": "Actual Check In",
|
||||||
|
"present": "PRESENT",
|
||||||
|
"pres": "present",
|
||||||
|
"shiftTime": "Shift Time",
|
||||||
|
"absent": "ABSENT",
|
||||||
|
"attendance": "Attendance",
|
||||||
|
"scheduleDays": "Schedule\nDays",
|
||||||
|
"offDays": "Off\nDays",
|
||||||
|
"nonAnalyzed": "Non\nAnalyzed",
|
||||||
|
"shortageHour": "Shortage\nHour",
|
||||||
|
"stats": "Stats",
|
||||||
|
"completed": "Completed",
|
||||||
|
"doNotUseRecentPassword": "Do not use recent password",
|
||||||
|
"atLeastOneLowercase": "At least one lowercase",
|
||||||
|
"atLeastOneUppercase": "At least one uppercase",
|
||||||
|
"atLeastOneNumeric": "At least one numeric",
|
||||||
|
"minimum8Characters": "Minimum 8 characters",
|
||||||
|
"doNotAddRepeatingLetters": "Do not add repeating letters",
|
||||||
|
"itShouldContainSpecialCharacter": "It should contain special character",
|
||||||
|
"confirmPasswordMustMatch": "Confirm password must match",
|
||||||
|
"sms": "SMS",
|
||||||
|
"fingerPrint": "Fingerprint",
|
||||||
|
"face": "Face",
|
||||||
|
"whatsapp": "Whatsapp",
|
||||||
|
"reject": "Reject",
|
||||||
|
"approve": "Approve",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"requestedItems": "Requested Items",
|
||||||
|
"request": "Request",
|
||||||
|
"myRequest": "My Request",
|
||||||
|
"actions": "Actions",
|
||||||
|
"delegate": "Delegate",
|
||||||
|
"request_info": "Request Info",
|
||||||
|
"attachments": "Attachments",
|
||||||
|
"info": "Info.",
|
||||||
|
"employeeNumber": "Employee Number",
|
||||||
|
"assignmentNumber": "Assignment Number",
|
||||||
|
"employeeName": "Employee Name",
|
||||||
|
"scheduleDate": "Schedule Date",
|
||||||
|
"shiftType": "Shift Type",
|
||||||
|
"shift": "Shift",
|
||||||
|
"breakText": "Break",
|
||||||
|
"actualSwipeStart": "Actual Swipe Start",
|
||||||
|
"actualSwipeEnd": "Actual Swipe End",
|
||||||
|
"approvedSwipeStart": "Approved Swipe Start",
|
||||||
|
"approvedSwipeStartReason": "Approved Swipe Start Reason",
|
||||||
|
"approvedSwipeEnd": "Approved Swipe End",
|
||||||
|
"approvedSwipeEndReason": "Approved Swipe End Reason",
|
||||||
|
"from": "From",
|
||||||
|
"to": "To",
|
||||||
|
"sent": "Sent",
|
||||||
|
"closed": "Closed",
|
||||||
|
"id": "ID",
|
||||||
|
"responder": "Responder",
|
||||||
|
"jobTitle": "Job Title",
|
||||||
|
"grade": "Grade",
|
||||||
|
"jobCategory": "Job Category",
|
||||||
|
"category": "Category",
|
||||||
|
"employeeEmailAddress": "Employee Email Address",
|
||||||
|
"payrollBranch": "Payroll Branch",
|
||||||
|
"yourChangeHasBeenSavedSuccessfully": "Your change has been saved successfully",
|
||||||
|
"code": "Code",
|
||||||
|
"unit": "Unit",
|
||||||
|
"quantity": "Quantity",
|
||||||
|
"dateRequired": "Date Required",
|
||||||
|
"lineStatus": "Line Status",
|
||||||
|
"statusDate": "Status Date",
|
||||||
|
"transactionType": "Transaction Type",
|
||||||
|
"operatingUnit": "Operating Unit",
|
||||||
|
"organizationCode": "Organization Code",
|
||||||
|
"organization": "Organization",
|
||||||
|
"fromSubInventory": "From Sub Inventory",
|
||||||
|
"fromLocator": "From Locator",
|
||||||
|
"toSubInventory": "To Sub Inventory",
|
||||||
|
"toLocator": "To Locator",
|
||||||
|
"shipToLocator": "Ship To Locator",
|
||||||
|
"itemHistory": "Item History",
|
||||||
|
"mfg": "MFG",
|
||||||
|
"lineType": "Line Type",
|
||||||
|
"price": "Price",
|
||||||
|
"lineAmount": "Line Amount",
|
||||||
|
"lineDiscount": "Line Discount %",
|
||||||
|
"needByDate": "Need By Date",
|
||||||
|
"promisedDate": "Promised Date",
|
||||||
|
"deliverToLocation": "Deliver To Location",
|
||||||
|
"requisitionNumber": "Requisition Number",
|
||||||
|
"requester": "Requester",
|
||||||
|
"subject": "Subject",
|
||||||
|
"quotationAnalysis": "Quotation Analysis",
|
||||||
|
"description": "Description",
|
||||||
|
"supplier": "Supplier",
|
||||||
|
"site": "Site",
|
||||||
|
"buyer": "Buyer",
|
||||||
|
"preparer": "Preparer",
|
||||||
|
"creationDate": "Creation Date",
|
||||||
|
"shipToLocation": "Ship To Location",
|
||||||
|
"quotationNumber": "Quotation Number",
|
||||||
|
"quotationDate": "Quotation Date",
|
||||||
|
"paymentTerms": "Payment Terms",
|
||||||
|
"currency": "Currency",
|
||||||
|
"grossAmount": "Gross Amount",
|
||||||
|
"discountAmount": "Discount Amount",
|
||||||
|
"customDuty": "Custom Duty",
|
||||||
|
"shipHandle": "Ship Handle",
|
||||||
|
"otherCharges": "Other Charges",
|
||||||
|
"totalPOAmountWithVAT": "Total PO Amount With VAT",
|
||||||
|
"totalPOAmountInWords": "Total PO Amount In Words",
|
||||||
|
"requestNumber": "Request Number",
|
||||||
|
"uom": "UOM",
|
||||||
|
"operatingCode": "Operating Code",
|
||||||
|
"poNumber": "PO Number",
|
||||||
|
"revision": "Revision",
|
||||||
|
"quantityOrdered": "Quantity Ordered",
|
||||||
|
"quantityReceived": "Quantity Received",
|
||||||
|
"bonusQuantity": "Bonus Quantity",
|
||||||
|
"purchasePrice": "Purchase Price",
|
||||||
|
"discountPer": "Discount %",
|
||||||
|
"balanceQuantity": "Balance Quantity",
|
||||||
|
"netPrice": "Net Price",
|
||||||
|
"closureStatus": "Closure Status",
|
||||||
|
"quotationNetPrice": "Quotation Net Price",
|
||||||
|
"quotationUOM": "Quotation UOM",
|
||||||
|
"quotationQty": "Quotation Qty",
|
||||||
|
"itemCode": "item Code",
|
||||||
|
"vendorName": "Vendor Name",
|
||||||
|
"quotationMFGPartNumber": "Quotation MFG Part Number",
|
||||||
|
"quotationDeliveryDate": "Quotation Delivery Date",
|
||||||
|
"quotationBonusQuantity": "Quotation Bonus Quantity",
|
||||||
|
"quotationLineTotal": "Quotation Line Total",
|
||||||
|
"rfqUOM": "RFQ UOM",
|
||||||
|
"rfqQty": "RFQ Qty",
|
||||||
|
"rfqNumber": "RFQ Number",
|
||||||
|
"msg": "Hello {} in the {} world ",
|
||||||
|
"msg_named": "{} are written in the {lang} language",
|
||||||
|
"clickMe": "Click me",
|
||||||
|
"human": "Human",
|
||||||
|
"resources": "Resources",
|
||||||
|
"details": "Details",
|
||||||
|
"noDataAvailable": "No Data Available",
|
||||||
|
"productName": "Product Name",
|
||||||
|
"productDescription": "Product Description",
|
||||||
|
"unitPrice": "Unit Price",
|
||||||
|
"manufacturerName": "Manufacturer Name",
|
||||||
|
"manufacturerPartName": "Manufacturer Part Name",
|
||||||
|
"supplierName": "Supplier Name",
|
||||||
|
"supplierContact": "Supplier Contact",
|
||||||
|
"chargeToPatient": "Charge To Patient",
|
||||||
|
"justification": "Justification",
|
||||||
|
"itemDescription": "Item Description",
|
||||||
|
"groupCode": "Group Code",
|
||||||
|
"primaryUOM": "Primary UOM",
|
||||||
|
"subgroupDescription": "Subgroup Description",
|
||||||
|
"subgroupCode": "Subgroup Code",
|
||||||
|
"groupDescription": "Group Description",
|
||||||
|
"templateName": "Template Name",
|
||||||
|
"itemCreationStatus": "Item Creation Status",
|
||||||
|
"standardizationApprovalStatus": "Standardization Approval Status",
|
||||||
|
"standardizationApprovalRejectionReason": "Standardization Approval Rejection Reason",
|
||||||
|
"analyzedBy": "Analyzed By",
|
||||||
|
"approvedDate": "Approved Date",
|
||||||
|
"itemType": "Item Type",
|
||||||
|
"relatedTo": "Related To",
|
||||||
|
"requestDate": "Request Date",
|
||||||
|
"analyzedDate": "Analyzed Date",
|
||||||
|
"urgent": "Urgent",
|
||||||
|
"requestDetails": "Request Details",
|
||||||
|
"approvalLevel": "Approval Level",
|
||||||
|
"requesterDetails": "Requester Details",
|
||||||
|
"myAttendance": "My Attendance",
|
||||||
|
"workOnBreak": "Work On Break",
|
||||||
|
"next": "Next",
|
||||||
|
"apply": "Apply",
|
||||||
|
"mobile": "Mobile",
|
||||||
|
"year": "Year",
|
||||||
|
"month": "Month",
|
||||||
|
"day": "Day",
|
||||||
|
"completingYear": "We appreciate you for completing the service of",
|
||||||
|
"address": "Address",
|
||||||
|
"phoneNumber": "Phone Number",
|
||||||
|
"businessGroup": "Business",
|
||||||
|
"Payroll": "Payroll",
|
||||||
|
"civilIdentityNumber": "Civil Identity Number",
|
||||||
|
"dateOfBirth": "Date of Birth",
|
||||||
|
"maritalStatus ": "Marital Status ",
|
||||||
|
"fullName": "Full Name",
|
||||||
|
"remove": "Remove",
|
||||||
|
"Attendance": "Attendance",
|
||||||
|
"submit": "Submit",
|
||||||
|
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
|
||||||
|
"comments": "Comments",
|
||||||
|
"writeComment": "Write a comment",
|
||||||
|
"approversList": "Approvers List",
|
||||||
|
"yourRequestHasBeenSubmittedForApprovals": "Your request has been submitted for approvals",
|
||||||
|
"monthlyPaySlip": "Monthly Pay Slip",
|
||||||
|
"particular": "Particular",
|
||||||
|
"earnings": "Earnings",
|
||||||
|
"deductions": "Deductions",
|
||||||
|
"paymentMethodName": "Payment Method Name",
|
||||||
|
"bankName": "Bank Name",
|
||||||
|
"branchCode": "Branch Code",
|
||||||
|
"accountNo": "Account No",
|
||||||
|
"summaryOfInformation": "Summary of Information",
|
||||||
|
"totalPayAmount": "Total Pay Amount",
|
||||||
|
"paymentInformation": "Payment Information",
|
||||||
|
"amount": "Amount",
|
||||||
|
"correctCurrentDatails": "correct or complete the current details",
|
||||||
|
"selectType": "Select the type of change you want to make",
|
||||||
|
"enterNewInfo": "Enter new Information because of a real change to the current details (e.g because of a change in marital status)",
|
||||||
|
"endDate": "*End Date",
|
||||||
|
"removeThisMember": "Are You Sure You Want to Remove this Member?",
|
||||||
|
"wantUpdateThisMember": "Are You Sure You Want to Update this Member?",
|
||||||
|
"addNewFamilyMember": "Add New Family Member",
|
||||||
|
"addRow": "Add new row",
|
||||||
|
"pleaseSelect": "Please Select *",
|
||||||
|
"delete": "delete",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit",
|
||||||
|
"myProfile": "My Profile",
|
||||||
|
"mowadhafhi": "Mowadhafi",
|
||||||
|
"searchAnnouncements": "Search Announcements",
|
||||||
|
"announcements": "Announcements",
|
||||||
|
"swipeRequest": "Swipe Request",
|
||||||
|
"serviceType": "Service Type",
|
||||||
|
"departmentName": "Department Name",
|
||||||
|
"selectDepartment": "Select Department",
|
||||||
|
"relatedSection": "Related Section",
|
||||||
|
"selectSection": "Select Section",
|
||||||
|
"relatedTopic": "Related Topic",
|
||||||
|
"selectTopic": "Select Topic",
|
||||||
|
"supportingDocument": "Supporting Document",
|
||||||
|
"mowadhafhiRequest": "Mowadhafi Request",
|
||||||
|
"ticketReference": "Ticket Reference",
|
||||||
|
"section": "Section",
|
||||||
|
"topic": "Topic",
|
||||||
|
"actionBy": "Action By",
|
||||||
|
"pendingTransactions": "Pending Transactions",
|
||||||
|
"selectRequestType": "Please select request type",
|
||||||
|
"dateFrom": "Date From",
|
||||||
|
"dateTo": "Date To",
|
||||||
|
"requestName": "Request Name",
|
||||||
|
"createdFor": "Created For",
|
||||||
|
"requestType": "Request Type",
|
||||||
|
"requestCreatedSuccessfully": "Request created successfully",
|
||||||
|
"search": "Search",
|
||||||
|
"wantToReject": "Are you sure want to reject?",
|
||||||
|
"employeeDigitalID": "Employee Digital ID",
|
||||||
|
"businessCard": "Business Card",
|
||||||
|
"checkOut": "Check Out",
|
||||||
|
"regular": "Regular",
|
||||||
|
"mark": "Mark",
|
||||||
|
"performance": "Performance Evaluation",
|
||||||
|
"performanceEvaluationIn": "Your performance Evaluation in",
|
||||||
|
"valuationIn": "Performance Evaluation in",
|
||||||
|
"viewBusinessCard": "View Business Card",
|
||||||
|
"performanceEvaluation": "Performance Evaluation",
|
||||||
|
"logout": "Logout",
|
||||||
|
"selectMethodOfAttendance": "Select the method to mark the attendance",
|
||||||
|
"comeNearHMGWifi": "Please come near to HMG wifi",
|
||||||
|
"deliverNotificationToMeRegardless": "Deliver notifications to me regardless of any general rules",
|
||||||
|
"close": "Close",
|
||||||
|
"respond": "Respond",
|
||||||
|
"vacationRuleAdded": "Vacation rule added",
|
||||||
|
"selectTypeT": "Select Type",
|
||||||
|
"notification": "Notification",
|
||||||
|
"selectNotification": "Select Notification",
|
||||||
|
"ifAllSelectedYouWillSkip": "*If All is selected, you will skip to step 3",
|
||||||
|
"applyForVacationRule": "Apply for Vacation Rule",
|
||||||
|
"step1": "Step 1",
|
||||||
|
"step2": "Step 2",
|
||||||
|
"step3": "Step 3",
|
||||||
|
"message": "Message",
|
||||||
|
"writeAMessage": "Write a message",
|
||||||
|
"notificationReassign": "Notification Reassign",
|
||||||
|
"selectEmployee": "Select Employee",
|
||||||
|
"searchEmployeeForReplacement": "Search employee for replacement",
|
||||||
|
"searchForEmployee": "Search for Employee",
|
||||||
|
"pleaseSpecifyEndTime": "Please specify End Time",
|
||||||
|
"pleaseSelectNotificationReassign": "Please select notification reassign",
|
||||||
|
"pleaseSelectEmployeeForReplacement": "Please select employee for replacement",
|
||||||
|
"pleaseSelectAction": "Please select action",
|
||||||
|
"pleaseSelectDate": "Please select date",
|
||||||
|
"todayAttendance": "Today's Attendance",
|
||||||
|
"viewAttendance": "View Attendance",
|
||||||
|
"teamMembers": "Team Members",
|
||||||
|
"profileDetails": "Profile Details",
|
||||||
|
"noResultsFound": "No Results Found",
|
||||||
|
"searchBy": "Search by",
|
||||||
|
"myTeamMembers": "My Team Members",
|
||||||
|
"save": "Save",
|
||||||
|
"TurnNotificationsFor": "Turn on notifications for",
|
||||||
|
"worklistSettings": "Worklist Settings",
|
||||||
|
"absenceType": "Absence Type",
|
||||||
|
"absenceCategory": "Absence Category",
|
||||||
|
"days": "Days",
|
||||||
|
"hours": "Hours",
|
||||||
|
"approvalStatus": "Approval Status",
|
||||||
|
"absenceStatus": "Absence Status",
|
||||||
|
"poweredBy": "Powered By",
|
||||||
|
"cloudSolutions": "Cloud Solutions",
|
||||||
|
"subordinateLeave": "Subordinate Leave",
|
||||||
|
"numberDays": "Number of days",
|
||||||
|
"selectTemplate": "Select Template",
|
||||||
|
"myPostedAds": "My posted ads",
|
||||||
|
"browseCategories": "Browse Categories",
|
||||||
|
"searchItems": "Search Items",
|
||||||
|
"offerAndDiscounts": "Offer & Discounts",
|
||||||
|
"offerValid": "Offer Valid",
|
||||||
|
"offerExpired": "Offer Expired",
|
||||||
|
"whatAreYouOffering": "What are you offering?",
|
||||||
|
"selectCategory": "Select Category",
|
||||||
|
"inProgress": "InProgress",
|
||||||
|
"locked": "Locked",
|
||||||
|
"addDetails": "Add Details",
|
||||||
|
"reviewAndSell": "Review & Sell",
|
||||||
|
"itemTitle": "Item Title",
|
||||||
|
"itemCondition": "Item Condition",
|
||||||
|
"used": "Used",
|
||||||
|
"region": "Region",
|
||||||
|
"selectRegion": "Select Region",
|
||||||
|
"itemPrice": "Item Price",
|
||||||
|
"itemPhotos": "Item Photos",
|
||||||
|
"itemInfo": "Item Info",
|
||||||
|
"uploadAttachment": "Upload Attachment",
|
||||||
|
"selectFromGalleryOrOpenCamera": "Select from gallery or open camera",
|
||||||
|
"openCamera": "Open\nCamera",
|
||||||
|
"uploadFromGallery": "Upload from\nGallery",
|
||||||
|
"name": "Name",
|
||||||
|
"email": "Email",
|
||||||
|
"noHistoryAvailable": "No History Available",
|
||||||
|
"purchaseRequisition": "Purchase Requisition",
|
||||||
|
"moveOrder": "Move Order",
|
||||||
|
"humanResource": "Human Resource",
|
||||||
|
"purchaseOrder": "Purchase Order",
|
||||||
|
"ITGForms": "ITG Forms",
|
||||||
|
"itemCreation": "Item Creation",
|
||||||
|
"stamp": "Stamp",
|
||||||
|
"addFavoriteList": "Do you want to add {name} in your favorite list",
|
||||||
|
"feedbackUserExperience": "This is to get the feedback about the user experience",
|
||||||
|
"rateUI": "1. How would you rate this UI?",
|
||||||
|
"submitSurvey": "Submit Survey",
|
||||||
|
"typeHere": "Type here",
|
||||||
|
"infoDetail": "Info Detail",
|
||||||
|
"amount_detail": "Amount Detail",
|
||||||
|
"currentBalance": "Current Balance",
|
||||||
|
"currentLeaveBalance": "Current Leave Balance",
|
||||||
|
"calculatedDays": "Calculated Days",
|
||||||
|
"totalDays": "Total Days",
|
||||||
|
"usedBalance": "Used",
|
||||||
|
"infants": "Infants",
|
||||||
|
"child": "Child",
|
||||||
|
"adult": "Adult",
|
||||||
|
"updateMember": "Are You Sure You Want to Update this Member?",
|
||||||
|
"fieldIsEmpty": "'{data}' Field is empty. Please select",
|
||||||
|
"pleaseEnterComments": "Please enter comments",
|
||||||
|
"skip": "Skip",
|
||||||
|
"typeCurrentPasswordBelow": "Type Your Current password below",
|
||||||
|
"currentPassword": "Current password",
|
||||||
|
"concurrentReports": "Concurrent Reports",
|
||||||
|
"profile": {
|
||||||
|
"reset_password": {
|
||||||
|
"label": "Reset Password",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "password"
|
||||||
|
},
|
||||||
|
"profileCompletionPer": "Profile Completion",
|
||||||
|
"completeProfile": "Complete Profile",
|
||||||
|
"personalInformation": "Personal Information",
|
||||||
|
"basicDetails": "Basic Details",
|
||||||
|
"address": "Address",
|
||||||
|
"contactDetails": "Contact Details",
|
||||||
|
"familyDetails": "Family Members",
|
||||||
|
"effectiveDate": "Effective Date",
|
||||||
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"clicked": {
|
||||||
|
"zero": "You clicked {} times!",
|
||||||
|
"one": "You clicked {} time!",
|
||||||
|
"two": "You clicked {} times!",
|
||||||
|
"few": "You clicked {} times!",
|
||||||
|
"many": "You clicked {} times!",
|
||||||
|
"other": "You clicked {} times!"
|
||||||
|
},
|
||||||
|
"gender": {
|
||||||
|
"male": "Hi man ;) ",
|
||||||
|
"female": "Hello girl :)",
|
||||||
|
"with_arg": {
|
||||||
|
"male": "Hi man ;) {}",
|
||||||
|
"female": "Hello girl :) {}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reset_locale": "Reset Language",
|
||||||
|
"chat": "Chat",
|
||||||
|
"mychats": "My Chats",
|
||||||
|
"createNewChat": "Create New Chat",
|
||||||
|
"brainMarathon": "Brain Marathon",
|
||||||
|
"contestTopicAbout": "Contest Topic will be about:",
|
||||||
|
"gameDate": "Game Date:",
|
||||||
|
"gameTime": "Game Time:",
|
||||||
|
"joinMarathon": "Join Marathon",
|
||||||
|
"joinDemoMarathon": "Join Demo Marathon",
|
||||||
|
"minutes": "Minutes",
|
||||||
|
"seconds": "Seconds",
|
||||||
|
"note": "Note:",
|
||||||
|
"demoMarathonNoteP1": "You can play the demo Marathon to learn how it works. You can join the Marathon",
|
||||||
|
"demoMarathonNoteP2": "5 Minutes",
|
||||||
|
"demoMarathonNoteP3": "before the actual time.",
|
||||||
|
"sponsoredBy": "Sponsored By:",
|
||||||
|
"question": "Question",
|
||||||
|
"marathoners": "Marathoners",
|
||||||
|
"prize": "Prize:",
|
||||||
|
"advancedSearch": "Advanced Search",
|
||||||
|
"openNot": "Open Notifications",
|
||||||
|
"fyi": "FYI Notifications",
|
||||||
|
"toDo": "To Do Notifications",
|
||||||
|
"all": "All Notifications",
|
||||||
|
"meNot": "Notifications from Me",
|
||||||
|
"view": "View",
|
||||||
|
"fromUserName": "From User Name",
|
||||||
|
"sentDate": "Sent Date",
|
||||||
|
"itemTypeDisplayName": "Item Type Display Name",
|
||||||
|
"none": "None",
|
||||||
|
"winnerSelection": "Winner Selection",
|
||||||
|
"qualifiers": "Qualifiers",
|
||||||
|
"getReadyForContest": "Get Ready for the coming contest:",
|
||||||
|
"winnerSelectedRandomly": "The winner will be selected randomly among the qualifiers.",
|
||||||
|
"fingersCrossed": "Fingers Crossed!!!",
|
||||||
|
"congrats": "Congratulations!!!",
|
||||||
|
"otp": "OTP",
|
||||||
|
"verification": "Verification",
|
||||||
|
"resend": "Resend",
|
||||||
|
"codeExpire": "The verification code has been expired",
|
||||||
|
"allQuestionsCorrect": "You have answered all questions correct",
|
||||||
|
"typeheretoreply": "Type here to reply"
|
||||||
|
}
|
||||||
@ -0,0 +1,321 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:http/io_client.dart';
|
||||||
|
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
||||||
|
import 'package:mohem_flutter_app/exceptions/api_exception.dart';
|
||||||
|
import 'package:mohem_flutter_app/main.dart';
|
||||||
|
// ignore_for_file: avoid_annotating_with_dynamic
|
||||||
|
|
||||||
|
typedef FactoryConstructor<U> = U Function(dynamic);
|
||||||
|
|
||||||
|
class APIError {
|
||||||
|
int? errorCode;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
APIError(this.errorCode, this.errorMessage);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() =>
|
||||||
|
{'errorCode': errorCode, 'errorMessage': errorMessage};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return jsonEncode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
APIException _throwAPIException(Response response) {
|
||||||
|
switch (response.statusCode) {
|
||||||
|
case 200:
|
||||||
|
APIError? apiError;
|
||||||
|
if (response.body != null && response.body.isNotEmpty) {
|
||||||
|
var jsonError = jsonDecode(response.body);
|
||||||
|
print(jsonError);
|
||||||
|
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']);
|
||||||
|
}
|
||||||
|
return APIException(APIException.BAD_REQUEST, error: apiError);
|
||||||
|
case 400:
|
||||||
|
APIError? apiError;
|
||||||
|
if (response.body != null && response.body.isNotEmpty) {
|
||||||
|
var jsonError = jsonDecode(response.body);
|
||||||
|
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']);
|
||||||
|
}
|
||||||
|
return APIException(APIException.BAD_REQUEST, error: apiError);
|
||||||
|
case 401:
|
||||||
|
return APIException(APIException.UNAUTHORIZED);
|
||||||
|
case 403:
|
||||||
|
return APIException(APIException.FORBIDDEN);
|
||||||
|
case 404:
|
||||||
|
return APIException(APIException.NOT_FOUND);
|
||||||
|
case 500:
|
||||||
|
return APIException(APIException.INTERNAL_SERVER_ERROR);
|
||||||
|
case 444:
|
||||||
|
var downloadUrl = response.headers["location"];
|
||||||
|
return APIException(APIException.UPGRADE_REQUIRED,
|
||||||
|
arguments: downloadUrl);
|
||||||
|
default:
|
||||||
|
return APIException(APIException.OTHER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApiClient {
|
||||||
|
static final ApiClient _instance = ApiClient._internal();
|
||||||
|
|
||||||
|
ApiClient._internal();
|
||||||
|
|
||||||
|
factory ApiClient() => _instance;
|
||||||
|
|
||||||
|
Future<U> postJsonForObject<T, U>(
|
||||||
|
FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
|
||||||
|
{String? token,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
int retryTimes = 0,
|
||||||
|
bool isFormData = false}) async {
|
||||||
|
var _headers = {'Accept': 'application/json'};
|
||||||
|
if (headers != null && headers.isNotEmpty) {
|
||||||
|
_headers.addAll(headers);
|
||||||
|
}
|
||||||
|
if (!kReleaseMode) {
|
||||||
|
print("Url:$url");
|
||||||
|
var bodyJson = json.encode(jsonObject);
|
||||||
|
print("body:$bodyJson");
|
||||||
|
}
|
||||||
|
var response = await postJsonForResponse(url, jsonObject,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: _headers,
|
||||||
|
retryTimes: retryTimes,
|
||||||
|
isFormData: isFormData);
|
||||||
|
// try {
|
||||||
|
if (!kReleaseMode) {
|
||||||
|
logger.i("res: " + response.body);
|
||||||
|
}
|
||||||
|
var jsonData = jsonDecode(response.body);
|
||||||
|
if (jsonData["IsAuthenticated"] != null) {
|
||||||
|
AppState().setIsAuthenticated = jsonData["IsAuthenticated"];
|
||||||
|
}
|
||||||
|
if (jsonData["ErrorMessage"] == null) {
|
||||||
|
return factoryConstructor(jsonData);
|
||||||
|
} else {
|
||||||
|
APIError? apiError;
|
||||||
|
apiError =
|
||||||
|
APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage']);
|
||||||
|
throw APIException(APIException.BAD_REQUEST, error: apiError);
|
||||||
|
}
|
||||||
|
// } catch (ex) {
|
||||||
|
// if (ex is APIException) {
|
||||||
|
// rethrow;
|
||||||
|
// } else {
|
||||||
|
// throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> postJsonForResponse<T>(String url, T jsonObject,
|
||||||
|
{String? token,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
int retryTimes = 0,
|
||||||
|
bool isFormData = false}) async {
|
||||||
|
String? requestBody;
|
||||||
|
late Map<String, String> stringObj;
|
||||||
|
if (jsonObject != null) {
|
||||||
|
requestBody = jsonEncode(jsonObject);
|
||||||
|
if (headers == null) {
|
||||||
|
headers = {'Content-Type': 'application/json'};
|
||||||
|
} else {
|
||||||
|
headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFormData) {
|
||||||
|
headers = {'Content-Type': 'application/x-www-form-urlencoded'};
|
||||||
|
stringObj = ((jsonObject ?? {}) as Map<String, dynamic>)
|
||||||
|
.map((key, value) => MapEntry(key, value?.toString() ?? ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return await _postForResponse(url, isFormData ? stringObj : requestBody,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> _postForResponse(String url, requestBody,
|
||||||
|
{String? token,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
int retryTimes = 0}) async {
|
||||||
|
try {
|
||||||
|
var _headers = <String, String>{};
|
||||||
|
if (token != null) {
|
||||||
|
_headers['Authorization'] = 'Bearer $token';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headers != null && headers.isNotEmpty) {
|
||||||
|
_headers.addAll(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryParameters != null) {
|
||||||
|
var queryString = new Uri(queryParameters: queryParameters).query;
|
||||||
|
url = url + '?' + queryString;
|
||||||
|
}
|
||||||
|
var response =
|
||||||
|
await _post(Uri.parse(url), body: requestBody, headers: _headers)
|
||||||
|
.timeout(Duration(seconds: 120));
|
||||||
|
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
return response;
|
||||||
|
} else {
|
||||||
|
throw _throwAPIException(response);
|
||||||
|
}
|
||||||
|
} on SocketException catch (e) {
|
||||||
|
if (retryTimes > 0) {
|
||||||
|
print('will retry after 3 seconds...');
|
||||||
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
return await _postForResponse(url, requestBody,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes - 1);
|
||||||
|
} else {
|
||||||
|
throw APIException(APIException.OTHER, arguments: e);
|
||||||
|
}
|
||||||
|
} on HttpException catch (e) {
|
||||||
|
if (retryTimes > 0) {
|
||||||
|
print('will retry after 3 seconds...');
|
||||||
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
return await _postForResponse(url, requestBody,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes - 1);
|
||||||
|
} else {
|
||||||
|
throw APIException(APIException.OTHER, arguments: e);
|
||||||
|
}
|
||||||
|
} on TimeoutException catch (e) {
|
||||||
|
throw APIException(APIException.TIMEOUT, arguments: e);
|
||||||
|
} on ClientException catch (e) {
|
||||||
|
if (retryTimes > 0) {
|
||||||
|
print('will retry after 3 seconds...');
|
||||||
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
return await _postForResponse(url, requestBody,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes - 1);
|
||||||
|
} else {
|
||||||
|
throw APIException(APIException.OTHER, arguments: e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> getJsonForResponse<T>(String url,
|
||||||
|
{String? token,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
int retryTimes = 0}) async {
|
||||||
|
if (headers == null) {
|
||||||
|
headers = {'Content-Type': 'application/json'};
|
||||||
|
} else {
|
||||||
|
headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
return await _getForResponse(url,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> _getForResponse(String url,
|
||||||
|
{String? token,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
Map<String, String>? headers,
|
||||||
|
int retryTimes = 0}) async {
|
||||||
|
try {
|
||||||
|
var _headers = <String, String>{};
|
||||||
|
if (token != null) {
|
||||||
|
_headers['Authorization'] = 'Bearer $token';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headers != null && headers.isNotEmpty) {
|
||||||
|
_headers.addAll(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryParameters != null) {
|
||||||
|
var queryString = new Uri(queryParameters: queryParameters).query;
|
||||||
|
url = url + '?' + queryString;
|
||||||
|
}
|
||||||
|
var response = await _get(Uri.parse(url), headers: _headers)
|
||||||
|
.timeout(Duration(seconds: 60));
|
||||||
|
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
return response;
|
||||||
|
} else {
|
||||||
|
throw _throwAPIException(response);
|
||||||
|
}
|
||||||
|
} on SocketException catch (e) {
|
||||||
|
if (retryTimes > 0) {
|
||||||
|
print('will retry after 3 seconds...');
|
||||||
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
return await _getForResponse(url,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes - 1);
|
||||||
|
} else {
|
||||||
|
throw APIException(APIException.OTHER, arguments: e);
|
||||||
|
}
|
||||||
|
} on HttpException catch (e) {
|
||||||
|
if (retryTimes > 0) {
|
||||||
|
print('will retry after 3 seconds...');
|
||||||
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
return await _getForResponse(url,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes - 1);
|
||||||
|
} else {
|
||||||
|
throw APIException(APIException.OTHER, arguments: e);
|
||||||
|
}
|
||||||
|
} on TimeoutException catch (e) {
|
||||||
|
throw APIException(APIException.TIMEOUT, arguments: e);
|
||||||
|
} on ClientException catch (e) {
|
||||||
|
if (retryTimes > 0) {
|
||||||
|
print('will retry after 3 seconds...');
|
||||||
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
return await _getForResponse(url,
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
headers: headers,
|
||||||
|
retryTimes: retryTimes - 1);
|
||||||
|
} else {
|
||||||
|
throw APIException(APIException.OTHER, arguments: e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> _get(url, {Map<String, String>? headers}) =>
|
||||||
|
_withClient((client) => client.get(url, headers: headers));
|
||||||
|
|
||||||
|
bool _certificateCheck(X509Certificate cert, String host, int port) => true;
|
||||||
|
|
||||||
|
Future<T> _withClient<T>(Future<T> Function(Client) fn) async {
|
||||||
|
var httpClient = HttpClient()..badCertificateCallback = _certificateCheck;
|
||||||
|
var client = IOClient(httpClient);
|
||||||
|
try {
|
||||||
|
return await fn(client);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> _post(url,
|
||||||
|
{Map<String, String>? headers, body, Encoding? encoding}) =>
|
||||||
|
_withClient((client) =>
|
||||||
|
client.post(url, headers: headers, body: body, encoding: encoding));
|
||||||
|
}
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:mohem_flutter_app/api/api_client.dart';
|
||||||
|
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/consts.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/basic_member_information_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/check_mobile_app_version_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/generic_response_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/member_login_list_model.dart';
|
||||||
|
|
||||||
|
class LoginApiClient {
|
||||||
|
static final LoginApiClient _instance = LoginApiClient._internal();
|
||||||
|
|
||||||
|
LoginApiClient._internal();
|
||||||
|
|
||||||
|
factory LoginApiClient() => _instance;
|
||||||
|
|
||||||
|
Future<GetMobileLoginInfoListModel?> getMobileLoginInfoNEW(String deviceToken, String deviceType) async {
|
||||||
|
String url = "${ApiConsts.erpRest}Mohemm_GetMobileLoginInfo_NEW";
|
||||||
|
Map<String, dynamic> postParams = {};
|
||||||
|
postParams["DeviceToken"] = deviceToken;
|
||||||
|
postParams["DeviceType"] = deviceType;
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel? responseData = GenericResponseModel.fromJson(json);
|
||||||
|
return (responseData.mohemmGetMobileLoginInfoList?.length ?? 0) > 0 ? (responseData.mohemmGetMobileLoginInfoList!.first) : null;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GenericResponseModel?> insertMobileLoginInfoNEW(
|
||||||
|
String email, int sessionId, String employeeName, int loginType, String mobileNumber, String userName, String deviceToken, String deviceType) async {
|
||||||
|
String url = "${ApiConsts.erpRest}Mohemm_InsertMobileLoginInfo";
|
||||||
|
Map<String, dynamic> postParams = {
|
||||||
|
"MobileNumber": mobileNumber,
|
||||||
|
"P_USER_NAME": userName,
|
||||||
|
"UserName": userName,
|
||||||
|
"CompanyID": 1, // todo 'sikander' @discuss umer for companyID
|
||||||
|
"DeviceToken": deviceToken,
|
||||||
|
"LoginType": loginType,
|
||||||
|
"EmployeeName": employeeName,
|
||||||
|
"P_SESSION_ID": sessionId,
|
||||||
|
"P_EMAIL_ADDRESS": email
|
||||||
|
};
|
||||||
|
postParams["DeviceToken"] = deviceToken;
|
||||||
|
postParams["DeviceType"] = deviceType;
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel? responseData = GenericResponseModel.fromJson(json);
|
||||||
|
AppState().setLogged = true;
|
||||||
|
return responseData;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<CheckMobileAppVersionModel> checkMobileAppVersion() async {
|
||||||
|
String url = "${ApiConsts.utilitiesRest}CheckMobileAppVersion";
|
||||||
|
Map<String, dynamic> postParams = {};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) => CheckMobileAppVersionModel.fromJson(json), url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<MemberLoginListModel?> memberLogin(String username, String password) async {
|
||||||
|
String url = "${ApiConsts.erpRest}MemberLogin";
|
||||||
|
Map<String, dynamic> postParams = {"P_APP_VERSION": "CS", "P_LANGUAGE": "US", "P_PASSWORD": password, "P_USER_NAME": username};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
|
||||||
|
AppState().postParamsObject?.setLogInTokenID = responseData.logInTokenID;
|
||||||
|
return responseData.memberLoginList;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<BasicMemberInformationModel?> mohemmSendActivationCodeByOTPNotificationType(int isMobileFingerPrint, String? mobileNumber, int optSendType, String? pUserName) async {
|
||||||
|
String url = "${ApiConsts.erpRest}Mohemm_SendActivationCodebyOTPNotificationType";
|
||||||
|
Map<String, dynamic> postParams = {"IsMobileFingerPrint": isMobileFingerPrint, "MobileNumber": mobileNumber, "OTP_SendType": optSendType, "P_USER_NAME": pUserName};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) => GenericResponseModel.fromJson(json).basicMemberInformation, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GenericResponseModel?> checkActivationCode(bool isDeviceNFC, String? mobileNumber, String activationCode, String? pUserName) async {
|
||||||
|
String url = "${ApiConsts.erpRest}CheckActivationCode";
|
||||||
|
Map<String, dynamic> postParams = {"IsDeviceNFC": isDeviceNFC, "MobileNumber": mobileNumber, "activationCode": activationCode, "P_USER_NAME": pUserName};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
|
||||||
|
AppState().postParamsObject?.setTokenID = responseData.tokenID;
|
||||||
|
AppState().postParamsObject?.mobileNumber = responseData.basicMemberInformation!.pMOBILENUMBER;
|
||||||
|
AppState().postParamsObject?.userName = AppState().getUserName;
|
||||||
|
AppState().postParamsObject?.pEmailAddress = responseData.basicMemberInformation!.pEMAILADDRESS;
|
||||||
|
AppState().postParamsObject?.pSessionId = responseData.pSESSIONID;
|
||||||
|
AppState().postParamsObject?.pUserName = AppState().getUserName;
|
||||||
|
AppState().postParamsObject?.pSelectedEmployeeNumber = AppState().getUserName;
|
||||||
|
AppState().postParamsObject?.setPLegislationCode = responseData.basicMemberInformation!.pLEGISLATIONCODE;
|
||||||
|
AppState().postParamsObject?.setPayrollCodeStr = responseData.memberInformationList!.first.pAYROLLCODE;
|
||||||
|
AppState().setBusinessCardPrivilege = responseData.businessCardPrivilege ?? false;
|
||||||
|
return responseData;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<BasicMemberInformationModel?> getBasicUserInformation(String pAppVersion, String pUsername) async {
|
||||||
|
String url = "${ApiConsts.erpRest}Get_BasicUserInformation";
|
||||||
|
Map<String, dynamic> postParams = {"P_APP_VERSION": pAppVersion, "P_USER_NAME": pUsername};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) => GenericResponseModel.fromJson(json).basicMemberInformation, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GenericResponseModel?> sendPublicActivationCode(String? mobileNumber, String? pUsername) async {
|
||||||
|
String url = "${ApiConsts.erpRest}SendPublicActivationCode";
|
||||||
|
Map<String, dynamic> postParams = {"MobileNumber": mobileNumber, "P_MOBILE_NUMBER": mobileNumber, "P_USER_NAME": pUsername};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
|
||||||
|
AppState().postParamsObject?.setLogInTokenID = responseData.logInTokenID;
|
||||||
|
return responseData;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GenericResponseModel?> checkPublicActivationCode(String activationCode, String? pUserName) async {
|
||||||
|
String url = "${ApiConsts.erpRest}checkPublicActivationCode";
|
||||||
|
Map<String, dynamic> postParams = {"activationCode": activationCode, "P_USER_NAME": pUserName};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
|
||||||
|
AppState().setForgetPasswordTokenID = responseData.forgetPasswordTokenID;
|
||||||
|
return responseData;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GenericResponseModel?> changePasswordForget(String forgetPasswordTokenID, String pNewPassword, String pConfirmNewPassword, String? pUserName) async {
|
||||||
|
String url = "${ApiConsts.erpRest}ChangePassword_Forget";
|
||||||
|
Map<String, dynamic> postParams = {"P_USER_NAME": pUserName, "ForgetPasswordTokenID": forgetPasswordTokenID, "P_Confirm_NEW_PASSWORD": pConfirmNewPassword, "P_NEW_PASSWORD": pNewPassword};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
|
||||||
|
|
||||||
|
return responseData;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GenericResponseModel?> changePasswordFromActiveSession(String pOldPassword, String pNewPassword, String pConfirmNewPassword) async {
|
||||||
|
String url = "${ApiConsts.erpRest}ChangePassword_FromActiveSession";
|
||||||
|
Map<String, dynamic> postParams = {"P_OLD_PASSWORD": pOldPassword, "P_Confirm_NEW_PASSWORD": pConfirmNewPassword, "P_NEW_PASSWORD": pNewPassword};
|
||||||
|
postParams.addAll(AppState().postParamsJson);
|
||||||
|
return await ApiClient().postJsonForObject((json) {
|
||||||
|
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
|
||||||
|
return responseData;
|
||||||
|
}, url, postParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,48 @@
|
|||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
class AppPermissions {
|
||||||
|
static void location(Function(bool) completion, BuildContext context) {
|
||||||
|
Permission.location.isGranted.then((isGranted){
|
||||||
|
if(!isGranted){
|
||||||
|
Permission.location.request().then((granted){
|
||||||
|
completion(granted == PermissionStatus.granted);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
completion(isGranted);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showErrorLocationDialog(bool isPermissionError, BuildContext context) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (cxt) => ConfirmDialog(
|
||||||
|
message: "Please provide location permission",
|
||||||
|
onTap: () {
|
||||||
|
if (isPermissionError) {
|
||||||
|
Geolocator.openAppSettings();
|
||||||
|
} else {
|
||||||
|
Geolocator.openLocationSettings();
|
||||||
|
}
|
||||||
|
Navigator.pop(context);
|
||||||
|
// createVacationRule(list);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkAll(Function(bool) completion) {
|
||||||
|
[Permission.location].request().then((value) {
|
||||||
|
bool allGranted = false;
|
||||||
|
value.values.forEach((element) {
|
||||||
|
allGranted = allGranted && element == PermissionStatus.granted;
|
||||||
|
});
|
||||||
|
|
||||||
|
completion(allGranted);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
class MyColors {
|
||||||
|
static const Color kWhiteColor = Color(0xffffffff);
|
||||||
|
static const Color darkIconColor = Color(0xff28323A);
|
||||||
|
static const Color darkTextColor = Color(0xff2B353E);
|
||||||
|
static const Color normalTextColor = Color(0xff5A5A5A);
|
||||||
|
static const Color lightTextColor = Color(0xffBFBFBF);
|
||||||
|
static const Color gradiantStartColor = Color(0xff33c0a5);
|
||||||
|
static const Color gradiantEndColor = Color(0xff259db7);
|
||||||
|
static const Color textMixColor = Color(0xff2BB8A6);
|
||||||
|
static const Color backgroundColor = Color(0xffF8F8F8);
|
||||||
|
static const Color grey41Color = Color(0xff414141);
|
||||||
|
static const Color grey57Color = Color(0xff575757);
|
||||||
|
static const Color grey67Color = Color(0xff676767);
|
||||||
|
static const Color grey77Color = Color(0xff777777);
|
||||||
|
static const Color greyF7Color = Color(0xffF7F7F7);
|
||||||
|
static const Color grey80Color = Color(0xff808080);
|
||||||
|
static const Color grey70Color = Color(0xff707070);
|
||||||
|
static const Color greyACColor = Color(0xffACACAC);
|
||||||
|
static const Color grey98Color = Color(0xff989898);
|
||||||
|
static const Color lightGreyEFColor = Color(0xffEFEFEF);
|
||||||
|
static const Color lightGreyEDColor = Color(0xffEDEDED);
|
||||||
|
static const Color lightGreyDeColor = Color(0xffDEDEDE);
|
||||||
|
static const Color lightGreyE3Color = Color(0xffE3E3E3);
|
||||||
|
static const Color lightGreyE6Color = Color(0xffE6E6E6);
|
||||||
|
static const Color lightGreyEAColor = Color(0xffEAEAEA);
|
||||||
|
static const Color lightGreyE5Color = Color(0xffE5E5E5);
|
||||||
|
static const Color darkWhiteColor = Color(0xffE0E0E0);
|
||||||
|
static const Color redColor = Color(0xffD02127);
|
||||||
|
static const Color pinkColor = Color(0xffEBA9A9);
|
||||||
|
static const Color pinkDarkColor = Color(0xffe3797d);
|
||||||
|
static const Color yellowColor = Color(0xffF4E31C);
|
||||||
|
static const Color orange = Color(0xFFCC9B14);
|
||||||
|
static const Color yellowFavColor = Color(0xffEAC321);
|
||||||
|
static const Color yellowColorII = Color(0xffEAA118);
|
||||||
|
static const Color backgroundBlackColor = Color(0xff202529);
|
||||||
|
static const Color black = Color(0xff000000);
|
||||||
|
static const Color white = Color(0xffffffff);
|
||||||
|
static const Color borderColor = Color(0xffE8E8E8);
|
||||||
|
static const Color borderE3Color = Color(0xffE3E3E3);
|
||||||
|
static const Color borderCEColor = Color(0xffCECECE);
|
||||||
|
//static const Color grey67Color = Color(0xff676767);
|
||||||
|
static const Color whiteColor = Color(0xFFEEEEEE);
|
||||||
|
static const Color greenColor = Color(0xff1FA269);
|
||||||
|
static const Color lightGreenColor = Color(0xff2AB2AB);
|
||||||
|
static const Color darkGreyColor = Color(0xff464646);
|
||||||
|
static const Color greyA5Color = Color(0xffA5A5A5);
|
||||||
|
static const Color blackColor = Color(0xff000014);
|
||||||
|
static const Color grey3AColor = Color(0xff2E303A);
|
||||||
|
static const Color darkColor = Color(0xff000015);
|
||||||
|
static const Color lightGrayColor = Color(0xff808080);
|
||||||
|
static const Color darkRedColor = Color(0xffD02127);
|
||||||
|
static const Color lightGreyColor = Color(0xffC7C7C7);
|
||||||
|
static const Color green69Color = Color(0xff1FA169);
|
||||||
|
static const Color redA3Color = Color(0xffCA3332);
|
||||||
|
static const Color green9CColor = Color(0xff259CB8);
|
||||||
|
static const Color green2DColor = Color(0xff32D892);
|
||||||
|
static const Color greyC4Color = Color(0xffC4C4C4);
|
||||||
|
static const Color grey35Color = Color(0xff535353);
|
||||||
|
static const Color grey9DColor = Color(0xff9D9D9D);
|
||||||
|
static const Color darkDigitColor = Color(0xff2D2F39);
|
||||||
|
static const Color grey71Color = Color(0xff717171);
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
class ApiConsts {
|
||||||
|
//static String baseUrl = "http://10.200.204.20:2801/"; // Local server
|
||||||
|
static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server
|
||||||
|
// static String baseUrl = "https://hmgwebservices.com"; // Live server
|
||||||
|
static String baseUrlServices = baseUrl + "/Services/"; // server
|
||||||
|
// static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server
|
||||||
|
static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/";
|
||||||
|
static String erpRest = baseUrlServices + "ERP.svc/REST/";
|
||||||
|
static String swpRest = baseUrlServices + "SWP.svc/REST/";
|
||||||
|
static String user = baseUrlServices + "api/User/";
|
||||||
|
static String cocRest = baseUrlServices + "COCWS.svc/REST/";
|
||||||
|
|
||||||
|
//Chat
|
||||||
|
static String chatServerBaseUrl = "https://apiderichat.hmg.com";
|
||||||
|
static String chatServerBaseApiUrl = "https://apiderichat.hmg.com/api/";
|
||||||
|
static String chatHubConnectionUrl = chatServerBaseUrl + "/ConnectionChatHub";
|
||||||
|
static String chatSearchMember = "user/getUserWithStatusAndFavAsync/";
|
||||||
|
static String chatRecentUrl = "UserChatHistory/getchathistorybyuserid"; //For a Mem
|
||||||
|
static String chatSingleUserHistoryUrl = "UserChatHistory/GetUserChatHistory";
|
||||||
|
static String chatMediaImageUploadUrl = "shared/upload";
|
||||||
|
static String chatFavoriteUsers = "FavUser/getFavUserById/";
|
||||||
|
}
|
||||||
|
|
||||||
|
class SharedPrefsConsts {
|
||||||
|
static String isRememberMe = "remember_me";
|
||||||
|
static String username = "username";
|
||||||
|
static String password = "password";
|
||||||
|
static String privilegeList = "privilegeList";
|
||||||
|
static String firebaseToken = "firebaseToken";
|
||||||
|
static String memberInformation = "memberInformation";
|
||||||
|
static String welcomeVideoUrl = "welcomeVideoUrl";
|
||||||
|
static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo";
|
||||||
|
static String mohemmWifiSSID = "mohemmWifiSSID";
|
||||||
|
static String mohemmWifiPassword = "mohemmWifiPassword";
|
||||||
|
static String editItemForSale = "editItemForSale";
|
||||||
|
}
|
||||||
@ -0,0 +1,460 @@
|
|||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
class DateUtil {
|
||||||
|
/// convert String To Date function
|
||||||
|
/// [date] String we want to convert
|
||||||
|
static DateTime convertStringToDate(String date) {
|
||||||
|
// /Date(1585774800000+0300)/
|
||||||
|
if (date != null) {
|
||||||
|
const start = "/Date(";
|
||||||
|
const end = "+0300)";
|
||||||
|
int startIndex = date.indexOf(start);
|
||||||
|
int endIndex = date.indexOf(end, startIndex + start.length);
|
||||||
|
return DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
int.parse(
|
||||||
|
date.substring(startIndex + start.length, endIndex),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
return DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime convertSimpleStringDateToDate(String date) {
|
||||||
|
return DateFormat("MM/dd/yyyy hh:mm:ss").parse(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime convertSimpleStringDateToDateddMMyyyy(String date) {
|
||||||
|
return DateFormat("MM/dd/yyyy hh:mm:ss").parse(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime convertStringToDateNoTimeZone(String date) {
|
||||||
|
// /Date(1585774800000+0300)/
|
||||||
|
if (date != null) {
|
||||||
|
const start = "/Date(";
|
||||||
|
const end = ")";
|
||||||
|
int startIndex = date.indexOf(start);
|
||||||
|
int endIndex = date.indexOf(end, startIndex + start.length);
|
||||||
|
return DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
int.parse(
|
||||||
|
date.substring(startIndex + start.length, endIndex),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
return DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime convertStringToDateTime(String date) {
|
||||||
|
if (date != null) {
|
||||||
|
try {
|
||||||
|
var dateT = date.split('/');
|
||||||
|
var year = dateT[2].substring(0, 4);
|
||||||
|
var dateP = DateTime(int.parse(year), int.parse(dateT[1]), int.parse(dateT[0]));
|
||||||
|
return dateP;
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateTime.now();
|
||||||
|
} else
|
||||||
|
return DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String convertDateToString(DateTime date) {
|
||||||
|
const start = "/Date(";
|
||||||
|
const end = "+0300)/";
|
||||||
|
int milliseconds = date.millisecondsSinceEpoch;
|
||||||
|
|
||||||
|
return start + "$milliseconds" + end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String convertDateToStringLocation(DateTime date) {
|
||||||
|
const start = "/Date(";
|
||||||
|
const end = ")/";
|
||||||
|
int milliseconds = date.millisecondsSinceEpoch;
|
||||||
|
|
||||||
|
return start + "$milliseconds" + end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatDateToDate(DateTime date, bool isArabic) {
|
||||||
|
return DateFormat('dd MMM yyy', isArabic ? "ar_SA" : "en_US").format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatDateToTime(DateTime date) {
|
||||||
|
return DateFormat('hh:mm a').format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String yearMonthDay(DateTime dateTime) {
|
||||||
|
String dateFormat = '${dateTime.year}-${dateTime.month}-${dateTime.day}';
|
||||||
|
return dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String time(DateTime dateTime) {
|
||||||
|
String dateFormat = '${dateTime.hour}:${dateTime.minute}:00';
|
||||||
|
return dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String convertDateMSToJsonDate(utc) {
|
||||||
|
var dt = new DateTime.fromMicrosecondsSinceEpoch(utc);
|
||||||
|
|
||||||
|
return "/Date(" + (dt.millisecondsSinceEpoch * 1000).toString() + '+0300' + ")/";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check Date
|
||||||
|
/// [dateString] String we want to convert
|
||||||
|
static String checkDate(DateTime checkedTime) {
|
||||||
|
DateTime currentTime = DateTime.now();
|
||||||
|
if ((currentTime.year == checkedTime.year) && (currentTime.month == checkedTime.month) && (currentTime.day == checkedTime.day)) {
|
||||||
|
return "Today";
|
||||||
|
} else if ((currentTime.year == checkedTime.year) && (currentTime.month == checkedTime.month)) {
|
||||||
|
if ((currentTime.day - checkedTime.day) == 1) {
|
||||||
|
return "YESTERDAY";
|
||||||
|
} else if ((currentTime.day - checkedTime.day) == -1) {
|
||||||
|
return "Tomorrow";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((currentTime.day - checkedTime.day) <= -2) {
|
||||||
|
return "Next Week";
|
||||||
|
} else {
|
||||||
|
return "Old Date";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "Old Date";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getDateFormatted(String date) {
|
||||||
|
DateTime dateObj = DateUtil.convertStringToDate(date);
|
||||||
|
return DateUtil.getWeekDay(dateObj.weekday) + ", " + dateObj.day.toString() + " " + DateUtil.getMonth(dateObj.month) + " " + dateObj.year.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getISODateFormat(DateTime dateTime) {
|
||||||
|
// 2020-04-30T00:00:00.000
|
||||||
|
return dateTime.toIso8601String();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get month by
|
||||||
|
/// [month] convert month number in to month name
|
||||||
|
static String getMonth(int month) {
|
||||||
|
switch (month) {
|
||||||
|
case 1:
|
||||||
|
return "January";
|
||||||
|
case 2:
|
||||||
|
return "February";
|
||||||
|
case 3:
|
||||||
|
return "March";
|
||||||
|
case 4:
|
||||||
|
return "April";
|
||||||
|
case 5:
|
||||||
|
return "May";
|
||||||
|
case 6:
|
||||||
|
return "June";
|
||||||
|
case 7:
|
||||||
|
return "July";
|
||||||
|
case 8:
|
||||||
|
return "August";
|
||||||
|
case 9:
|
||||||
|
return "September";
|
||||||
|
case 10:
|
||||||
|
return "October";
|
||||||
|
case 11:
|
||||||
|
return "November";
|
||||||
|
case 12:
|
||||||
|
return "December";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get month by
|
||||||
|
/// [month] convert month number in to month name in Arabic
|
||||||
|
static String getMonthArabic(int month) {
|
||||||
|
switch (month) {
|
||||||
|
case 1:
|
||||||
|
return "يناير";
|
||||||
|
case 2:
|
||||||
|
return " فبراير";
|
||||||
|
case 3:
|
||||||
|
return "مارس";
|
||||||
|
case 4:
|
||||||
|
return "أبريل";
|
||||||
|
case 5:
|
||||||
|
return "مايو";
|
||||||
|
case 6:
|
||||||
|
return "يونيو";
|
||||||
|
case 7:
|
||||||
|
return "يوليو";
|
||||||
|
case 8:
|
||||||
|
return "أغسطس";
|
||||||
|
case 9:
|
||||||
|
return "سبتمبر";
|
||||||
|
case 10:
|
||||||
|
return " اكتوبر";
|
||||||
|
case 11:
|
||||||
|
return " نوفمبر";
|
||||||
|
case 12:
|
||||||
|
return "ديسمبر";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getMonthByName(String month) {
|
||||||
|
switch (month.toLowerCase()) {
|
||||||
|
case 'january':
|
||||||
|
return 1;
|
||||||
|
case 'february':
|
||||||
|
return 2;
|
||||||
|
case 'march':
|
||||||
|
return 3;
|
||||||
|
case 'april':
|
||||||
|
return 4;
|
||||||
|
case 'may':
|
||||||
|
return 5;
|
||||||
|
case 'june':
|
||||||
|
return 6;
|
||||||
|
case 'july':
|
||||||
|
return 7;
|
||||||
|
case 'august':
|
||||||
|
return 8;
|
||||||
|
case 'september':
|
||||||
|
return 9;
|
||||||
|
case 'october':
|
||||||
|
return 10;
|
||||||
|
case 'november':
|
||||||
|
return 11;
|
||||||
|
case 'december':
|
||||||
|
return 12;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime getMonthDateTime(String month, yearName) {
|
||||||
|
DateTime? date;
|
||||||
|
try {
|
||||||
|
date = DateTime(int.parse(yearName), getMonthByName(month));
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
return date ?? DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get month by
|
||||||
|
/// [weekDay] convert week day in int to week day name
|
||||||
|
static String getWeekDay(int weekDay) {
|
||||||
|
switch (weekDay) {
|
||||||
|
case 1:
|
||||||
|
return "Monday";
|
||||||
|
case 2:
|
||||||
|
return "Tuesday";
|
||||||
|
case 3:
|
||||||
|
return "Wednesday";
|
||||||
|
case 4:
|
||||||
|
return "Thursday";
|
||||||
|
case 5:
|
||||||
|
return "Friday";
|
||||||
|
case 6:
|
||||||
|
return "Saturday ";
|
||||||
|
case 7:
|
||||||
|
return "Sunday";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get month by
|
||||||
|
/// [weekDay] convert week day in int to week day name arabic
|
||||||
|
static String getWeekDayArabic(int weekDay) {
|
||||||
|
switch (weekDay) {
|
||||||
|
case 1:
|
||||||
|
return "الاثنين";
|
||||||
|
case 2:
|
||||||
|
return "الثلاثاء";
|
||||||
|
case 3:
|
||||||
|
return "الاربعاء";
|
||||||
|
case 4:
|
||||||
|
return "الخميس";
|
||||||
|
case 5:
|
||||||
|
return "الجمعه";
|
||||||
|
case 6:
|
||||||
|
return "السبت ";
|
||||||
|
case 7:
|
||||||
|
return "الاحد";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getWeekDayEnglish(int weekDay) {
|
||||||
|
switch (weekDay) {
|
||||||
|
case 1:
|
||||||
|
return "Monday";
|
||||||
|
case 2:
|
||||||
|
return "Tuesday";
|
||||||
|
case 3:
|
||||||
|
return "Wednesday";
|
||||||
|
case 4:
|
||||||
|
return "Thursday";
|
||||||
|
case 5:
|
||||||
|
return "Friday";
|
||||||
|
case 6:
|
||||||
|
return "Saturday ";
|
||||||
|
case 7:
|
||||||
|
return "Sunday";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like Apr 26,2020
|
||||||
|
/// [dateTime] convert DateTime to data formatted
|
||||||
|
static String getMonthDayYearDateFormatted(DateTime dateTime) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like Apr 26,2020
|
||||||
|
/// [dateTime] convert DateTime to data formatted Arabic
|
||||||
|
static String getMonthDayYearDateFormattedAr(DateTime dateTime) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like Thursday, Apr 26,2020
|
||||||
|
/// [dateTime] convert DateTime to date formatted
|
||||||
|
static String getWeekDayMonthDayYearDateFormatted(DateTime dateTime, String lang) {
|
||||||
|
// print(dateTime);
|
||||||
|
// print(dateTime.weekday);
|
||||||
|
// print(dateTime.weekday.getDayOfWeekEnumValue.value);
|
||||||
|
if (dateTime != null)
|
||||||
|
return lang == 'en'
|
||||||
|
? getWeekDayEnglish(dateTime.weekday) + ", " + getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString()
|
||||||
|
: getWeekDayArabic(dateTime.weekday) + ", " + dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getMonthDayYearLangDateFormatted(DateTime dateTime, String lang) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return lang == 'en'
|
||||||
|
? getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString()
|
||||||
|
: dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 26/4/2020
|
||||||
|
static String getDayMonthYearLangDateFormatted(DateTime dateTime, String lang) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return lang == 'en'
|
||||||
|
? dateTime.day.toString() + " " + getMonth(dateTime.month) + " " + dateTime.year.toString()
|
||||||
|
: dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getMonthYearLangDateFormatted(DateTime dateTime, String lang) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return lang == 'en' ? getMonth(dateTime.month) + " " + dateTime.year.toString() : getMonthArabic(dateTime.month) + " " + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 26/4/2020
|
||||||
|
/// [dateTime] convert DateTime to data formatted
|
||||||
|
static String getDayMonthYearDateFormatted(DateTime dateTime) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 26/4/2020
|
||||||
|
/// [dateTime] convert DateTime to data formatted
|
||||||
|
static String getDayMonthDateFormatted(DateTime dateTime) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return DateFormat('dd/MM').format(dateTime);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 26/4/2020
|
||||||
|
/// [dateTime] convert DateTime to data formatted according to language
|
||||||
|
static String getDayMonthYearDateFormattedLang(DateTime dateTime, bool isArabic) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return DateFormat('dd/MM/yyyy', isArabic ? "ar_SA" : "en_US").format(dateTime);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 10:30 according to lang
|
||||||
|
static String formatDateToTimeLang(DateTime date, bool isArabic) {
|
||||||
|
return DateFormat('HH:mm', isArabic ? "ar_SA" : "en_US").format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 26/4/2020 10:30
|
||||||
|
/// [dateTime] convert DateTime to data formatted
|
||||||
|
static String getDayMonthYearHourMinuteDateFormatted(DateTime dateTime) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString() + " " + DateFormat('HH:mm').format(dateTime);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get data formatted like 2020-8-13 09:43:00
|
||||||
|
/// [dateTime] convert DateTime to data formatted
|
||||||
|
static String getYearMonthDayHourMinSecDateFormatted(DateTime dateTime) {
|
||||||
|
if (dateTime != null)
|
||||||
|
return dateTime.year.toString() +
|
||||||
|
"-" +
|
||||||
|
dateTime.month.toString() +
|
||||||
|
"-" +
|
||||||
|
dateTime.day.toString() +
|
||||||
|
" " +
|
||||||
|
dateTime.hour.toString() +
|
||||||
|
":" +
|
||||||
|
dateTime.minute.toString() +
|
||||||
|
":" +
|
||||||
|
dateTime.second.toString();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getFormattedDate(DateTime dateTime, String formattedString) {
|
||||||
|
return DateFormat(formattedString).format(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String convertISODateToJsonDate(String isoDate) {
|
||||||
|
return "/Date(" + DateFormat('mm-dd-yyy').parse(isoDate).millisecondsSinceEpoch.toString() + ")/";
|
||||||
|
}
|
||||||
|
|
||||||
|
// static String getDay(DayOfWeek dayOfWeek) {
|
||||||
|
// switch (dayOfWeek) {
|
||||||
|
// case DayOfWeek.Monday:
|
||||||
|
// return "Monday";
|
||||||
|
// break;
|
||||||
|
// case DayOfWeek.Tuesday:
|
||||||
|
// return "Tuesday";
|
||||||
|
// break;
|
||||||
|
// case DayOfWeek.Wednesday:
|
||||||
|
// return "Wednesday";
|
||||||
|
// break;
|
||||||
|
// case DayOfWeek.Thursday:
|
||||||
|
// return "Thursday";
|
||||||
|
// break;
|
||||||
|
// case DayOfWeek.Friday:
|
||||||
|
// return "Friday";
|
||||||
|
// break;
|
||||||
|
// case DayOfWeek.Saturday:
|
||||||
|
// return "Saturday";
|
||||||
|
// break;
|
||||||
|
// case DayOfWeek.Sunday:
|
||||||
|
// return "Sunday";
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// return "";
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
|
||||||
|
class MyDecorations {
|
||||||
|
static Decoration shadowDecoration = BoxDecoration(
|
||||||
|
color: MyColors.kWhiteColor,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: const Color(0xff000000).withOpacity(.05),
|
||||||
|
blurRadius: 26,
|
||||||
|
offset: const Offset(0, -3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
static Decoration getContainersDecoration(Color color) {
|
||||||
|
Decoration answerContainerDecoration = BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
color: color,
|
||||||
|
border: Border.all(width: 1, color: MyColors.lightGreyEFColor),
|
||||||
|
);
|
||||||
|
return answerContainerDecoration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:open_file/open_file.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
class FileProcess {
|
||||||
|
static bool isFolderCreated = false;
|
||||||
|
static Directory? directory;
|
||||||
|
|
||||||
|
static Future checkDocumentFolder() async {
|
||||||
|
try {
|
||||||
|
if (!isFolderCreated) {
|
||||||
|
directory = await getApplicationDocumentsDirectory();
|
||||||
|
await directory!.exists().then((value) {
|
||||||
|
if (value) directory!.create();
|
||||||
|
isFolderCreated = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openFile(String fileName) {
|
||||||
|
String dir = directory!.path + "/$fileName.pdf";
|
||||||
|
OpenFile.open(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<File> downloadFile(String base64Content, String fileName) async {
|
||||||
|
Uint8List bytes = base64.decode(base64Content);
|
||||||
|
await checkDocumentFolder();
|
||||||
|
String dir = directory!.path + "/" + fileName + ".pdf";
|
||||||
|
File file = File(dir);
|
||||||
|
if (!file.existsSync()) file.create();
|
||||||
|
await file.writeAsBytes(bytes);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
class MyLottieConsts {
|
||||||
|
static const String hourGlassLottie = "assets/lottie/hourglass.json";
|
||||||
|
static const String celebrate1Lottie = "assets/lottie/celebrate1.json";
|
||||||
|
static const String celebrate2Lottie = "assets/lottie/celebrate2.json";
|
||||||
|
static const String winnerLottie = "assets/lottie/winner3.json";
|
||||||
|
static const String allQuestions = "assets/lottie/all_questions.json";
|
||||||
|
}
|
||||||
@ -0,0 +1,346 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/config/routes.dart';
|
||||||
|
import 'package:mohem_flutter_app/exceptions/api_exception.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/loading_dialog.dart';
|
||||||
|
import 'package:nfc_manager/nfc_manager.dart';
|
||||||
|
import 'package:nfc_manager/platform_tags.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
// ignore_for_file: avoid_annotating_with_dynamic
|
||||||
|
|
||||||
|
class Utils {
|
||||||
|
static bool _isLoadingVisible = false;
|
||||||
|
|
||||||
|
static bool get isLoading => _isLoadingVisible;
|
||||||
|
|
||||||
|
static void showToast(String message, {bool longDuration = true}) {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: message,
|
||||||
|
toastLength: longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
timeInSecForIosWeb: 1,
|
||||||
|
backgroundColor: Colors.black54,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 16.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dynamic getNotNullValue(List<dynamic> list, int index) {
|
||||||
|
try {
|
||||||
|
return list[index];
|
||||||
|
} catch (ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stringToHex(String colorCode) {
|
||||||
|
try {
|
||||||
|
return int.parse(colorCode.replaceAll("#", "0xff"));
|
||||||
|
} catch (ex) {
|
||||||
|
return (0xff000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future delay(int millis) async {
|
||||||
|
return await Future.delayed(Duration(milliseconds: millis));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showLoading(BuildContext context) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_isLoadingVisible = true;
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierColor: Colors.black.withOpacity(0.5),
|
||||||
|
builder: (BuildContext context) => LoadingDialog(),
|
||||||
|
).then((value) {
|
||||||
|
_isLoadingVisible = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hideLoading(BuildContext context) {
|
||||||
|
if (_isLoadingVisible) {
|
||||||
|
_isLoadingVisible = false;
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
_isLoadingVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> getStringFromPrefs(String key) async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
return prefs.getString(key) ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> saveStringFromPrefs(String key, String value) async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
return await prefs.setString(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleException(dynamic exception, cxt, Function(String)? onErrorMessage) {
|
||||||
|
String errorMessage;
|
||||||
|
if (exception is APIException) {
|
||||||
|
if (exception.message == APIException.UNAUTHORIZED) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
errorMessage = exception.error?.errorMessage ?? exception.message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorMessage = APIException.UNKNOWN;
|
||||||
|
}
|
||||||
|
if (onErrorMessage != null) {
|
||||||
|
onErrorMessage(errorMessage);
|
||||||
|
} else {
|
||||||
|
if (!AppState().isAuthenticated) {
|
||||||
|
showDialog(
|
||||||
|
context: cxt,
|
||||||
|
builder: (cxt) => ConfirmDialog(
|
||||||
|
message: errorMessage,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route<dynamic> route) => false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
showToast(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void confirmDialog(cxt, String message) {
|
||||||
|
showDialog(
|
||||||
|
context: cxt,
|
||||||
|
builder: (cxt) => ConfirmDialog(
|
||||||
|
message: message,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget getNoDataWidget(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0),
|
||||||
|
LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15),
|
||||||
|
],
|
||||||
|
).center;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget getNoChatWidget(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0),
|
||||||
|
LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15),
|
||||||
|
],
|
||||||
|
).center;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Uint8List getPostBytes(img) {
|
||||||
|
try {
|
||||||
|
var b64 = img.replaceFirst('data:image/png;base64,', '');
|
||||||
|
if (img != null && Utils.isBase64(b64)) return Utils.dataFromBase64String(b64);
|
||||||
|
} catch (e) {}
|
||||||
|
return Uint8List.fromList([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getBase64FromJpeg(img) {
|
||||||
|
try {
|
||||||
|
var b64 = img.replaceFirst('data:image/jpeg;base64,', '');
|
||||||
|
return b64;
|
||||||
|
} catch (e) {}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isBase64(String str) {
|
||||||
|
RegExp _base64 = RegExp(r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$');
|
||||||
|
return _base64.hasMatch(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Uint8List dataFromBase64String(String base64String) {
|
||||||
|
return base64Decode(base64String);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget tableColumnTitle(String? text, {bool showDivider = true, bool alignCenter = false}) {
|
||||||
|
text ??= "";
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
6.height,
|
||||||
|
alignCenter ? text.toText12().center : text.toText12(),
|
||||||
|
5.height,
|
||||||
|
if (showDivider)
|
||||||
|
const Divider(
|
||||||
|
height: 1,
|
||||||
|
color: Color(0xff2E303A),
|
||||||
|
thickness: 1,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Decoration containerRadius(Color background, double radius) {
|
||||||
|
return BoxDecoration(
|
||||||
|
color: background,
|
||||||
|
border: Border.all(
|
||||||
|
width: 1, //
|
||||||
|
color: background // <--- border width here
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(radius),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget mHeight(double h) {
|
||||||
|
return Container(
|
||||||
|
height: h,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget mDivider(Color color) {
|
||||||
|
return Divider(
|
||||||
|
// width: double.infinity,
|
||||||
|
height: 1,
|
||||||
|
color: color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget tableColumnValue(String text, {bool isCapitable = true, bool alignCenter = false}) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
12.height,
|
||||||
|
if (alignCenter)
|
||||||
|
(isCapitable ? text.toLowerCase().capitalizeFirstofEach : text).toText12(color: MyColors.normalTextColor).center
|
||||||
|
else
|
||||||
|
(isCapitable ? text.toLowerCase().capitalizeFirstofEach : text).toText12(color: MyColors.normalTextColor),
|
||||||
|
12.height,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// EIT Forms date formats
|
||||||
|
|
||||||
|
static String getMonthNamedFormat(DateTime date) {
|
||||||
|
/// it will return like "29-Sep-2022"
|
||||||
|
return DateFormat('dd-MMM-yyyy').format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String reverseFormatDate(String date) {
|
||||||
|
String formattedDate;
|
||||||
|
if (date.isNotEmpty) {
|
||||||
|
formattedDate = date.replaceAll('/', '-');
|
||||||
|
formattedDate = formattedDate.replaceAll(' 00:00:00', '');
|
||||||
|
} else {
|
||||||
|
formattedDate = date;
|
||||||
|
}
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatStandardDate(String date) {
|
||||||
|
String formattedDate;
|
||||||
|
if (date.isNotEmpty) {
|
||||||
|
formattedDate = date.replaceAll('-', '/');
|
||||||
|
} else {
|
||||||
|
formattedDate = date;
|
||||||
|
}
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String reverseFormatStandardDate(String date) {
|
||||||
|
String formattedDate;
|
||||||
|
if (date.isNotEmpty) {
|
||||||
|
formattedDate = date.replaceAll('/', '-');
|
||||||
|
} else {
|
||||||
|
formattedDate = date;
|
||||||
|
}
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatDate(String date) {
|
||||||
|
String formattedDate;
|
||||||
|
|
||||||
|
if (date.isNotEmpty) {
|
||||||
|
date = date.substring(0, 10);
|
||||||
|
formattedDate = date.replaceAll('-', '/');
|
||||||
|
formattedDate = formattedDate + ' 00:00:00';
|
||||||
|
} else {
|
||||||
|
formattedDate = date;
|
||||||
|
}
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatDateNew(String date) {
|
||||||
|
String formattedDate;
|
||||||
|
if (date.isNotEmpty) {
|
||||||
|
formattedDate = date.split('T')[0];
|
||||||
|
if(!formattedDate.contains("00:00:00")) {
|
||||||
|
formattedDate = formattedDate + ' 00:00:00';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formattedDate = date;
|
||||||
|
}
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<DateTime> selectDate(BuildContext context, DateTime selectedDate) async {
|
||||||
|
if (!Platform.isIOS) {
|
||||||
|
await showCupertinoModalPopup(
|
||||||
|
context: context,
|
||||||
|
builder: (cxt) => Container(
|
||||||
|
height: 250,
|
||||||
|
color: Colors.white,
|
||||||
|
child: CupertinoDatePicker(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
mode: CupertinoDatePickerMode.date,
|
||||||
|
onDateTimeChanged: (value) {
|
||||||
|
if (value != null && value != selectedDate) {
|
||||||
|
selectedDate = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initialDateTime: selectedDate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101));
|
||||||
|
if (picked != null && picked != selectedDate) {
|
||||||
|
selectedDate = picked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readNFc({required Function(String) onRead}) {
|
||||||
|
|
||||||
|
NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async {
|
||||||
|
print(tag.data);
|
||||||
|
var f;
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
|
||||||
|
} else {
|
||||||
|
f = MifareUltralight(tag: tag, identifier: tag.data["mifare"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22);
|
||||||
|
}
|
||||||
|
String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join('');
|
||||||
|
NfcManager.instance.stopSession();
|
||||||
|
onRead(identifier);
|
||||||
|
}).catchError((err) {
|
||||||
|
print(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class AppProvider extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
AppProvider({required this.child});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return child;
|
||||||
|
return MultiProvider(
|
||||||
|
providers: [
|
||||||
|
// ChangeNotifierProvider(create: (_) => Counter()),
|
||||||
|
],
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,300 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/attendance/add_vacation_rule_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/attendance/monthly_attendance_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/attendance/vacation_rule_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/bottom_sheets/attendence_details_bottom_sheet.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/chat/chat_home.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/landing/itg/survey_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/landing/today_attendance_screen2.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/leave_balance/add_leave_balance_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/leave_balance/leave_balance_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/login/change_password_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/login/forgot_password_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/login/login_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/login/new_password_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/login/verify_last_login_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/login/verify_login_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/marathon/marathon_intro_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/marathon/marathon_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/marathon/marathon_winner_selection.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/marathon/winner_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart';
|
||||||
|
|
||||||
|
// import 'package:mohem_flutter_app/ui/my_attendance/my_attendance_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/create_request.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/employee_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/my_team.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/profile_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/subordinate_leave.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/team_members.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/my_team/view_attendance.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/payslip/monthly_pay_slip_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/performance/performance_appraisal_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/add_update_family_member.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/basic_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/contact_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/delete_family_member.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/dynamic_screens/dynamic_input_address_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/dynamic_screens/dynamic_input_basic_details_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/family_members.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/personal_info.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/profile/profile_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/announcements/announcement_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart';
|
||||||
|
|
||||||
|
// import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/items_for_sale/add_new_item_for_sale.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/items_for_sale/item_for_sale_detail.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/items_for_sale/items_for_sale_home.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_home.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/mowadhafhi/request_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/my_requests/my_requests.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/my_requests/new_request.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/offers_and_discounts/offers_and_discounts_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/offers_and_discounts/offers_and_discounts_home.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/pending_transactions/pending_transactions.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/pending_transactions/pending_transactions_details.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/screens/submenu_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/termination/end_employement.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/work_list/item_history_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/work_list/itg_detail_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/work_list/work_list_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/work_list/worklist_detail_screen.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/work_list/worklist_settings.dart';
|
||||||
|
|
||||||
|
class AppRoutes {
|
||||||
|
static const String splash = "/splash";
|
||||||
|
static const String registerSelection = "/registerSelection";
|
||||||
|
static const String loginVerifyAccount = "/loginVerifyAccount";
|
||||||
|
static const String login = "/login";
|
||||||
|
static const String verifyLogin = "/verifyLogin";
|
||||||
|
static const String verifyLastLogin = "/verifyLastLogin";
|
||||||
|
static const String forgotPassword = "/forgotPassword";
|
||||||
|
static const String newPassword = "/newPassword";
|
||||||
|
static const String loginVerification = "/loginVerification";
|
||||||
|
static const String dashboard = "/dashboard";
|
||||||
|
static const String todayAttendance = "/todayAttendance";
|
||||||
|
static const String subMenuScreen = "/submenuScreen";
|
||||||
|
static const String addEitScreen = "/addeitScreen";
|
||||||
|
static const String initialRoute = login;
|
||||||
|
static const String survey = "/survey";
|
||||||
|
|
||||||
|
//Work List
|
||||||
|
static const String workList = "/workList";
|
||||||
|
static const String workListDetail = "/workListDetail";
|
||||||
|
static const String itgDetail = "/itgDetail";
|
||||||
|
static const String itemHistory = "/itemHistory";
|
||||||
|
static const String worklistSettings = "/worklistSettings";
|
||||||
|
|
||||||
|
// Leave Balance
|
||||||
|
static const String leaveBalance = "/leaveBalance";
|
||||||
|
static const String addLeaveBalance = "/addLeaveBalance";
|
||||||
|
|
||||||
|
static const String servicesMenuListScreen = "/servicesMenuListScreen";
|
||||||
|
static const String dynamicScreen = "/dynamicScreen";
|
||||||
|
static const String addDynamicInput = "/addDynamicInput";
|
||||||
|
static const String requestSubmitScreen = "/requestSubmitScreen";
|
||||||
|
|
||||||
|
//profile
|
||||||
|
|
||||||
|
static const String addDynamicInputProfile = 'addDynamicInputProfile';
|
||||||
|
static const String addDynamicAddressScreen = 'addDynamicAddressProfile';
|
||||||
|
|
||||||
|
//Attendance
|
||||||
|
static const String attendance = "/attendance";
|
||||||
|
static const String monthlyAttendance = "/monthlyAttendance";
|
||||||
|
static const String vacationRule = "/vacationRule";
|
||||||
|
static const String addVacationRule = "/addVacationRule";
|
||||||
|
|
||||||
|
//Bottom Sheet
|
||||||
|
static const String attendanceDetailsBottomSheet =
|
||||||
|
"/attendanceDetailsBottomSheet";
|
||||||
|
|
||||||
|
//Profile
|
||||||
|
static const String profile = "/profile";
|
||||||
|
static const String personalInfo = "/personalInfo";
|
||||||
|
static const String basicDetails = "/basicDetails";
|
||||||
|
static const String contactDetails = "/contactDetails";
|
||||||
|
static const String familyMembers = "/familyMembers";
|
||||||
|
static const String deleteFamilyMember = "/deleteFamilyMember";
|
||||||
|
static const String addUpdateFamilyMember = "/addUpdateFamilyMember";
|
||||||
|
|
||||||
|
// Mowadhafhi
|
||||||
|
static const String mowadhafhi = "/mowadhafhi";
|
||||||
|
static const String mowadhafhiDetails = "/mowadhafhiDetails";
|
||||||
|
static const String mowadhafhiHRRequest = "/mowadhafhiHRRequest";
|
||||||
|
|
||||||
|
// Pending Transactions
|
||||||
|
static const String pendingTransactions = "/pendingTransactions";
|
||||||
|
static const String pendingTransactionsDetails =
|
||||||
|
"/pendingTransactionsDetails";
|
||||||
|
|
||||||
|
// Announcements
|
||||||
|
static const String announcements = "/announcements";
|
||||||
|
static const String announcementsDetails = "/announcementsDetails";
|
||||||
|
|
||||||
|
// My Requests
|
||||||
|
static const String myRequests = "/myRequests";
|
||||||
|
static const String newRequest = "/newRequests";
|
||||||
|
|
||||||
|
// Items For Sale
|
||||||
|
static const String itemsForSale = "/itemsForSale";
|
||||||
|
static const String itemsForSaleDetail = "/itemsForSaleDetail";
|
||||||
|
static const String addNewItemForSale = "/addNewItemForSale";
|
||||||
|
|
||||||
|
// Offers & Discounts
|
||||||
|
static const String offersAndDiscounts = "/offersAndDiscounts";
|
||||||
|
static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails";
|
||||||
|
|
||||||
|
//Pay slip
|
||||||
|
static const String monthlyPaySlip = "/monthlyPaySlip";
|
||||||
|
|
||||||
|
//performance evaluation
|
||||||
|
|
||||||
|
static const String performanceEvaluation = "/performanceEvaluation";
|
||||||
|
|
||||||
|
static const String endEmploymentScreen = "/endEmploymentScreen";
|
||||||
|
|
||||||
|
//My Team
|
||||||
|
static const String myTeam = "/myTeam";
|
||||||
|
static const String employeeDetails = "/employeeDetails";
|
||||||
|
static const String profileDetails = "/profileDetails";
|
||||||
|
static const String viewAttendance = "/viewAttendance";
|
||||||
|
static const String teamMembers = "/teamMembers";
|
||||||
|
static const String createRequest = "/createRequest";
|
||||||
|
static const String subordinateLeave = "/subordinateLeave";
|
||||||
|
|
||||||
|
static const String changePassword = "/changePassword";
|
||||||
|
|
||||||
|
//Chat
|
||||||
|
static const String chat = "/chat";
|
||||||
|
static const String chatDetailed = "/chatDetailed";
|
||||||
|
|
||||||
|
//Marathon
|
||||||
|
static const String marathonIntroScreen = "/marathonIntroScreen";
|
||||||
|
static const String marathonScreen = "/marathonScreen";
|
||||||
|
static const String marathonWinnerSelection = "/marathonWinnerSelection";
|
||||||
|
static const String marathonWinnerScreen = "/marathonWinnerScreen";
|
||||||
|
|
||||||
|
static final Map<String, WidgetBuilder> routes = {
|
||||||
|
login: (BuildContext context) => LoginScreen(),
|
||||||
|
verifyLogin: (BuildContext context) => VerifyLoginScreen(),
|
||||||
|
verifyLastLogin: (BuildContext context) => VerifyLastLoginScreen(),
|
||||||
|
dashboard: (BuildContext context) => DashboardScreen(),
|
||||||
|
survey: (BuildContext context) => SurveyScreen(),
|
||||||
|
|
||||||
|
subMenuScreen: (BuildContext context) => SubMenuScreen(),
|
||||||
|
newPassword: (BuildContext context) => NewPasswordScreen(),
|
||||||
|
forgotPassword: (BuildContext context) => ForgotPasswordScreen(),
|
||||||
|
todayAttendance: (BuildContext context) => TodayAttendanceScreen2(),
|
||||||
|
//eit
|
||||||
|
|
||||||
|
addEitScreen: (BuildContext context) => AddEITScreen(),
|
||||||
|
|
||||||
|
//Work List
|
||||||
|
workList: (BuildContext context) => WorkListScreen(),
|
||||||
|
workListDetail: (BuildContext context) => WorkListDetailScreen(),
|
||||||
|
itgDetail: (BuildContext context) => ItgDetailScreen(),
|
||||||
|
itemHistory: (BuildContext context) => ItemHistoryScreen(),
|
||||||
|
worklistSettings: (BuildContext context) => WorklistSettings(),
|
||||||
|
|
||||||
|
// Leave Balance
|
||||||
|
|
||||||
|
leaveBalance: (BuildContext context) => LeaveBalance(),
|
||||||
|
addLeaveBalance: (BuildContext context) => AddLeaveBalanceScreen(),
|
||||||
|
|
||||||
|
servicesMenuListScreen: (BuildContext context) => ServicesMenuListScreen(),
|
||||||
|
// workFromHome: (BuildContext context) => WorkFromHomeScreen(),
|
||||||
|
// addWorkFromHome: (BuildContext context) => AddWorkFromHomeScreen(),
|
||||||
|
profile: (BuildContext context) => ProfileScreen(),
|
||||||
|
//Attendance
|
||||||
|
monthlyAttendance: (BuildContext context) => MonthlyAttendanceScreen(),
|
||||||
|
vacationRule: (BuildContext context) => VacationRuleScreen(),
|
||||||
|
addVacationRule: (BuildContext context) => AddVacationRuleScreen(),
|
||||||
|
|
||||||
|
//Bottom Sheet
|
||||||
|
attendanceDetailsBottomSheet: (BuildContext context) =>
|
||||||
|
AttendenceDetailsBottomSheet(),
|
||||||
|
|
||||||
|
//Profile
|
||||||
|
//profile: (BuildContext context) => Profile(),
|
||||||
|
//profile: (BuildContext context) => Profile(),
|
||||||
|
personalInfo: (BuildContext context) => PersonalInfo(),
|
||||||
|
basicDetails: (BuildContext context) => BasicDetails(),
|
||||||
|
contactDetails: (BuildContext context) => ContactDetails(),
|
||||||
|
familyMembers: (BuildContext context) => FamilyMembers(),
|
||||||
|
dynamicScreen: (BuildContext context) => DynamicListViewScreen(),
|
||||||
|
addDynamicInput: (BuildContext context) => DynamicInputScreen(),
|
||||||
|
addDynamicInputProfile: (BuildContext context) =>
|
||||||
|
DynamicInputScreenProfile(),
|
||||||
|
addDynamicAddressScreen: (BuildContext context) =>
|
||||||
|
DynamicInputScreenAddress(),
|
||||||
|
|
||||||
|
deleteFamilyMember: (BuildContext context) =>
|
||||||
|
DeleteFamilyMember(ModalRoute.of(context)!.settings.arguments as int),
|
||||||
|
requestSubmitScreen: (BuildContext context) => RequestSubmitScreen(),
|
||||||
|
addUpdateFamilyMember: (BuildContext context) => AddUpdateFamilyMember(),
|
||||||
|
|
||||||
|
//mowadhafhi
|
||||||
|
mowadhafhi: (BuildContext context) => MowadhafhiHome(),
|
||||||
|
mowadhafhiDetails: (BuildContext context) => MowadhafhiRequestDetails(),
|
||||||
|
mowadhafhiHRRequest: (BuildContext context) => MowadhafhiHRRequest(),
|
||||||
|
|
||||||
|
pendingTransactions: (BuildContext context) => PendingTransactions(),
|
||||||
|
pendingTransactionsDetails: (BuildContext context) =>
|
||||||
|
PendingTransactionsDetails(),
|
||||||
|
|
||||||
|
announcements: (BuildContext context) => Announcements(),
|
||||||
|
announcementsDetails: (BuildContext context) => AnnouncementDetails(),
|
||||||
|
|
||||||
|
//My Requests
|
||||||
|
myRequests: (BuildContext context) => MyRequests(),
|
||||||
|
newRequest: (BuildContext context) => NewRequest(),
|
||||||
|
|
||||||
|
// Items for sale
|
||||||
|
itemsForSale: (BuildContext context) => ItemsForSale(),
|
||||||
|
itemsForSaleDetail: (BuildContext context) => ItemForSaleDetailPage(),
|
||||||
|
addNewItemForSale: (BuildContext context) => AddNewItemForSale(),
|
||||||
|
|
||||||
|
// Offers & Discounts
|
||||||
|
offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(),
|
||||||
|
offersAndDiscountsDetails: (BuildContext context) =>
|
||||||
|
OffersAndDiscountsDetails(),
|
||||||
|
|
||||||
|
//pay slip
|
||||||
|
monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(),
|
||||||
|
performanceEvaluation: (BuildContext context) => PerformanceAppraisal(),
|
||||||
|
|
||||||
|
endEmploymentScreen: (BuildContext context) => EndEmploymentScreen(),
|
||||||
|
|
||||||
|
//My Team
|
||||||
|
myTeam: (BuildContext context) => MyTeam(),
|
||||||
|
employeeDetails: (BuildContext context) => EmployeeDetails(),
|
||||||
|
profileDetails: (BuildContext context) => ProfileDetails(),
|
||||||
|
viewAttendance: (BuildContext context) => ViewAttendance(),
|
||||||
|
teamMembers: (BuildContext context) => TeamMembers(),
|
||||||
|
createRequest: (BuildContext context) => CreateRequest(),
|
||||||
|
subordinateLeave: (BuildContext context) => SubordinateLeave(),
|
||||||
|
|
||||||
|
changePassword: (BuildContext context) => ChangePasswordScreen(),
|
||||||
|
|
||||||
|
//Chat
|
||||||
|
chat: (BuildContext context) => ChatHomeScreen(),
|
||||||
|
chatDetailed: (BuildContext context) => ChatDetailScreen(),
|
||||||
|
|
||||||
|
// Marathon
|
||||||
|
marathonIntroScreen: (BuildContext context) => MarathonIntroScreen(),
|
||||||
|
marathonScreen: (BuildContext context) => MarathonScreen(),
|
||||||
|
marathonWinnerSelection: (BuildContext context) =>
|
||||||
|
MarathonWinnerSelection(),
|
||||||
|
marathonWinnerScreen: (BuildContext context) => WinnerScreen(),
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,274 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:easy_localization/src/public_ext.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.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:mohem_flutter_app/widgets/otp_widget.dart';
|
||||||
|
import 'package:sizer/sizer.dart';
|
||||||
|
|
||||||
|
final ValueNotifier<String> otpFieldClear = ValueNotifier<String>("");
|
||||||
|
|
||||||
|
class OtpDialog {
|
||||||
|
final int type;
|
||||||
|
final int? mobileNo;
|
||||||
|
final Function(String, TextEditingController _pinPutController) onSuccess;
|
||||||
|
final Function onFailure;
|
||||||
|
final BuildContext context;
|
||||||
|
final Function onResendCode;
|
||||||
|
|
||||||
|
int remainingTime = 120;
|
||||||
|
|
||||||
|
Future<Null>? timer;
|
||||||
|
|
||||||
|
static BuildContext? _context;
|
||||||
|
|
||||||
|
static bool? _loading;
|
||||||
|
|
||||||
|
OtpDialog(this.context, this.type, this.mobileNo, this.onSuccess, this.onFailure, {required this.onResendCode});
|
||||||
|
|
||||||
|
GlobalKey? verifyAccountForm = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final TextEditingController _pinPutController = TextEditingController();
|
||||||
|
|
||||||
|
TextEditingController digit1 = TextEditingController(text: "");
|
||||||
|
TextEditingController digit2 = TextEditingController(text: "");
|
||||||
|
TextEditingController digit3 = TextEditingController(text: "");
|
||||||
|
TextEditingController digit4 = TextEditingController(text: "");
|
||||||
|
|
||||||
|
Map verifyAccountFormValue = {
|
||||||
|
'digit1': '',
|
||||||
|
'digit2': '',
|
||||||
|
'digit3': '',
|
||||||
|
'digit4': '',
|
||||||
|
};
|
||||||
|
final focusD1 = FocusNode();
|
||||||
|
final focusD2 = FocusNode();
|
||||||
|
final focusD3 = FocusNode();
|
||||||
|
final focusD4 = FocusNode();
|
||||||
|
String? errorMsg;
|
||||||
|
|
||||||
|
// ProjectViewModel projectProvider;
|
||||||
|
String displayTime = '';
|
||||||
|
String? _code;
|
||||||
|
dynamic setState;
|
||||||
|
bool stopTimer = false;
|
||||||
|
|
||||||
|
// static String signature;
|
||||||
|
|
||||||
|
void displayDialog(BuildContext context) async {
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierColor: Colors.black.withOpacity(0.63),
|
||||||
|
builder: (context) {
|
||||||
|
// projectProvider = Provider.of(context);
|
||||||
|
return Dialog(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
|
insetPadding: const EdgeInsets.only(left: 21, right: 21),
|
||||||
|
child: StatefulBuilder(builder: (context, setState) {
|
||||||
|
if (displayTime == '') {
|
||||||
|
startTimer(setState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(21),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
type == 1
|
||||||
|
? "assets/images/login/verify_sms.svg"
|
||||||
|
: type == 2
|
||||||
|
? "assets/images/login/verify_whatsapp.svg"
|
||||||
|
: type == 3
|
||||||
|
? "assets/images/login/verify_face.svg"
|
||||||
|
: 'assets/images/login/verify_thumb.svg',
|
||||||
|
height: 50,
|
||||||
|
width: 50,
|
||||||
|
),
|
||||||
|
12.height,
|
||||||
|
LocaleKeys.otp.tr().toText14(),
|
||||||
|
LocaleKeys.verification.tr().toText24(isBold: true),
|
||||||
|
6.height,
|
||||||
|
(LocaleKeys.pleaseEnterTheVerificationCodeSentTo.tr() + ' xxxxxxxx' + mobileNo.toString().substring(mobileNo.toString().length - 3)).toText16(),
|
||||||
|
18.height,
|
||||||
|
ValueListenableBuilder<String>(
|
||||||
|
builder: (BuildContext context, String value, Widget? child) {
|
||||||
|
// This builder will only get called when the _counter
|
||||||
|
// is updated.
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Center(
|
||||||
|
child: OTPWidget(
|
||||||
|
autoFocus: true,
|
||||||
|
controller: _pinPutController,
|
||||||
|
defaultBorderColor: const Color(0xffD8D8D8),
|
||||||
|
maxLength: 4,
|
||||||
|
onTextChanged: (text) {},
|
||||||
|
pinBoxColor: Colors.white,
|
||||||
|
onDone: (code) => _onOtpCallBack(code, null),
|
||||||
|
textBorderColor: const Color(0xffD8D8D8),
|
||||||
|
pinBoxWidth: 60,
|
||||||
|
pinBoxHeight: 60,
|
||||||
|
pinTextStyle: const TextStyle(fontSize: 24.0, color: MyColors.darkTextColor),
|
||||||
|
pinTextAnimatedSwitcherTransition: ProvidedPinBoxTextAnimation.scalingTransition,
|
||||||
|
pinTextAnimatedSwitcherDuration: const Duration(milliseconds: 300),
|
||||||
|
pinBoxRadius: 10,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
10.height,
|
||||||
|
stopTimer
|
||||||
|
? Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: LocaleKeys.codeExpire.tr().toText16(
|
||||||
|
color: MyColors.redColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
12.width,
|
||||||
|
Image.asset(
|
||||||
|
"assets/icons/ic_alarm.png",
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: MyColors.redColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: LocaleKeys.theVerificationCodeWillExpireIn.tr() + '\n',
|
||||||
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.darkTextColor, letterSpacing: -0.48),
|
||||||
|
children: <TextSpan>[
|
||||||
|
TextSpan(
|
||||||
|
text: displayTime,
|
||||||
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.textMixColor, letterSpacing: -0.48),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
valueListenable: otpFieldClear,
|
||||||
|
),
|
||||||
|
18.height,
|
||||||
|
DefaultButton(
|
||||||
|
stopTimer ? LocaleKeys.resend.tr() : LocaleKeys.cancel.tr(),
|
||||||
|
() async {
|
||||||
|
if (stopTimer) {
|
||||||
|
hideSMSBox(context);
|
||||||
|
onResendCode();
|
||||||
|
} else {
|
||||||
|
stopTimer = true;
|
||||||
|
// onFailure();
|
||||||
|
hideSMSBox(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: stopTimer
|
||||||
|
? null
|
||||||
|
: [
|
||||||
|
MyColors.pinkDarkColor,
|
||||||
|
MyColors.pinkDarkColor,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDecoration buildInputDecoration(BuildContext context) {
|
||||||
|
return InputDecoration(
|
||||||
|
counterText: " ",
|
||||||
|
enabledBorder: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
|
borderSide: BorderSide(color: Colors.black),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
||||||
|
borderSide: BorderSide(color: Theme.of(context).primaryColor),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
||||||
|
borderSide: BorderSide(color: Theme.of(context).errorColor),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
||||||
|
borderSide: BorderSide(color: Theme.of(context).errorColor),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// String validateCodeDigit(value) {
|
||||||
|
// if (value.isEmpty) {
|
||||||
|
// return ' ';
|
||||||
|
// } else if (value.length == 3) {
|
||||||
|
// print(value);
|
||||||
|
// } else {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
String getSecondsAsDigitalClock(int inputSeconds) {
|
||||||
|
int secNum = int.parse(inputSeconds.toString()); // don't forget the second param
|
||||||
|
int hours = (secNum / 3600).floor();
|
||||||
|
int minutes = ((secNum - hours * 3600) / 60).floor();
|
||||||
|
double seconds = secNum - hours * 3600 - minutes * 60;
|
||||||
|
String minutesString = "";
|
||||||
|
String secondsString = "";
|
||||||
|
minutesString = minutes < 10 ? "0" + minutes.toString() : minutes.toString();
|
||||||
|
secondsString = seconds < 10 ? "0" + seconds.toStringAsFixed(0) : seconds.toStringAsFixed(0);
|
||||||
|
return minutesString + ":" + secondsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startTimer(setState) {
|
||||||
|
remainingTime--;
|
||||||
|
if (stopTimer) return;
|
||||||
|
setState(() {
|
||||||
|
displayTime = getSecondsAsDigitalClock(remainingTime);
|
||||||
|
});
|
||||||
|
|
||||||
|
timer = Future.delayed(const Duration(seconds: 1), () {
|
||||||
|
if (remainingTime > 0) {
|
||||||
|
startTimer(setState);
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
stopTimer = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void hideSMSBox(context) {
|
||||||
|
onFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onOtpCallBack(String otpCode, bool? isAutofill) {
|
||||||
|
if (otpCode.length == 4) {
|
||||||
|
// stopTimer = true;
|
||||||
|
otpFieldClear.value = otpCode;
|
||||||
|
onSuccess(otpCode, _pinPutController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static getSignature() async {
|
||||||
|
// // if (Platform.isAndroid) {
|
||||||
|
// // return await SmsRetriever.getAppSignature();
|
||||||
|
// // } else {
|
||||||
|
// // return null;
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:mohem_flutter_app/api/api_client.dart';
|
||||||
|
|
||||||
|
class APIException implements Exception {
|
||||||
|
static const String BAD_REQUEST = 'api_common_bad_request';
|
||||||
|
static const String UNAUTHORIZED = 'api_common_unauthorized';
|
||||||
|
static const String FORBIDDEN = 'api_common_forbidden';
|
||||||
|
static const String NOT_FOUND = 'api_common_not_found';
|
||||||
|
static const String INTERNAL_SERVER_ERROR = 'api_common_internal_server_error';
|
||||||
|
static const String UPGRADE_REQUIRED = 'api_common_upgrade_required';
|
||||||
|
static const String BAD_RESPONSE_FORMAT = 'api_common_bad_response_format';
|
||||||
|
static const String OTHER = 'api_common_http_error';
|
||||||
|
static const String TIMEOUT = 'api_common_http_timeout';
|
||||||
|
static const String UNKNOWN = 'unexpected_error';
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
final APIError? error;
|
||||||
|
final arguments;
|
||||||
|
|
||||||
|
const APIException(this.message, {this.arguments, this.error});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {'message': message, 'error': error, 'arguments': '$arguments'};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return jsonEncode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
|
||||||
|
extension IntExtensions on int {
|
||||||
|
Widget get height => SizedBox(height: toDouble());
|
||||||
|
|
||||||
|
Widget get width => SizedBox(width: toDouble());
|
||||||
|
|
||||||
|
Widget get divider => Divider(height: toDouble(), thickness: toDouble(), color: MyColors.lightGreyEFColor);
|
||||||
|
|
||||||
|
Widget get makeItSquare => SizedBox(width: toDouble(), height: toDouble());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,234 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
|
||||||
|
extension CapExtension on String {
|
||||||
|
String get toCamelCase => "${this[0].toUpperCase()}${this.substring(1)}";
|
||||||
|
|
||||||
|
String get inCaps => '${this[0].toUpperCase()}${this.substring(1)}';
|
||||||
|
|
||||||
|
String get allInCaps => this.toUpperCase();
|
||||||
|
|
||||||
|
String get capitalizeFirstofEach => this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
extension EmailValidator on String {
|
||||||
|
Widget get toWidget => Text(this);
|
||||||
|
|
||||||
|
Widget toText10({Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle}) => Text(
|
||||||
|
this,
|
||||||
|
maxLines: maxlines,
|
||||||
|
style: TextStyle(fontSize: 10, fontStyle: fontStyle ?? FontStyle.normal, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
letterSpacing: -0.33,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text(
|
||||||
|
this,
|
||||||
|
textAlign: isCenter ? TextAlign.center : null,
|
||||||
|
maxLines: (maxLine > 0) ? maxLine : null,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
letterSpacing: -0.72,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => AutoSizeText(
|
||||||
|
this,
|
||||||
|
textAlign: isCenter ? TextAlign.center : null,
|
||||||
|
maxLines: (maxLine > 0) ? maxLine : null,
|
||||||
|
minFontSize: 8,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
letterSpacing: -0.72,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toTextAuto({
|
||||||
|
Color? color,
|
||||||
|
bool isUnderLine = false,
|
||||||
|
bool isBold = false,
|
||||||
|
bool isCenter = false,
|
||||||
|
int maxLine = 0,
|
||||||
|
double fontSize = 12,
|
||||||
|
double letterSpacing = -0.72,
|
||||||
|
double height = 1,
|
||||||
|
}) =>
|
||||||
|
AutoSizeText(
|
||||||
|
this,
|
||||||
|
textAlign: isCenter ? TextAlign.center : null,
|
||||||
|
maxLines: (maxLine > 0) ? maxLine : null,
|
||||||
|
minFontSize: 5,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: fontSize,
|
||||||
|
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
letterSpacing: letterSpacing,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText13({Color? color, bool isUnderLine = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
|
||||||
|
this,
|
||||||
|
maxLines: maxlines,
|
||||||
|
style: TextStyle(
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
fontSize: 14,
|
||||||
|
letterSpacing: -0.48,
|
||||||
|
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines}) => Text(
|
||||||
|
this,
|
||||||
|
maxLines: maxlines,
|
||||||
|
style: TextStyle(
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
fontSize: 16,
|
||||||
|
letterSpacing: -0.64,
|
||||||
|
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText17({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.68, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText18({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.08),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText19({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: 19, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.14),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText20({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: 20, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
|
||||||
|
this,
|
||||||
|
maxLines: maxlines,
|
||||||
|
style: TextStyle(color: color ?? MyColors.grey3AColor, fontSize: 21, letterSpacing: -0.31, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText22({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 1, color: color ?? MyColors.darkTextColor, fontSize: 22, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText24({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText32({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText44({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 44, letterSpacing: -2.64, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
|
||||||
|
String upper = "";
|
||||||
|
String lower = "";
|
||||||
|
String heading = this;
|
||||||
|
if (heading.isNotEmpty) {
|
||||||
|
List<String> data = heading.split(" ");
|
||||||
|
|
||||||
|
if (data.length > 1) {
|
||||||
|
upper = data[0];
|
||||||
|
data.removeAt(0);
|
||||||
|
lower = data.join(" ");
|
||||||
|
} else {
|
||||||
|
lower = data[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (upperHeading.isNotEmpty) {
|
||||||
|
upper = upperHeading;
|
||||||
|
}
|
||||||
|
if (lowerHeading.isNotEmpty) {
|
||||||
|
lower = lowerHeading;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (upper.isNotEmpty) upper.toText12(),
|
||||||
|
lower.toText24(isBold: true),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValidEmail() {
|
||||||
|
return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toFormattedDate() {
|
||||||
|
String date = this.split("T")[0];
|
||||||
|
String time = this.split("T")[1];
|
||||||
|
var dates = date.split("-");
|
||||||
|
return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}";
|
||||||
|
}
|
||||||
|
|
||||||
|
String getMonth(int month) {
|
||||||
|
switch (month) {
|
||||||
|
case 1:
|
||||||
|
return "January";
|
||||||
|
case 2:
|
||||||
|
return "February";
|
||||||
|
case 3:
|
||||||
|
return "March";
|
||||||
|
case 4:
|
||||||
|
return "April";
|
||||||
|
case 5:
|
||||||
|
return "May";
|
||||||
|
case 6:
|
||||||
|
return "June";
|
||||||
|
case 7:
|
||||||
|
return "July";
|
||||||
|
case 8:
|
||||||
|
return "August";
|
||||||
|
case 9:
|
||||||
|
return "September";
|
||||||
|
case 10:
|
||||||
|
return "October";
|
||||||
|
case 11:
|
||||||
|
return "November";
|
||||||
|
case 12:
|
||||||
|
return "December";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
|
extension WidgetExtensions on Widget {
|
||||||
|
Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this);
|
||||||
|
|
||||||
|
Widget get expanded => Expanded(child: this);
|
||||||
|
|
||||||
|
Widget get center => Center(child: this);
|
||||||
|
|
||||||
|
Widget circle(double _value) => ClipRRect(borderRadius: BorderRadius.circular(_value), child: this);
|
||||||
|
|
||||||
|
Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this);
|
||||||
|
|
||||||
|
Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) =>
|
||||||
|
Padding(padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom), child: this);
|
||||||
|
|
||||||
|
Widget toExpanded({int flex = 1}) => Expanded(flex: flex, child: this);
|
||||||
|
|
||||||
|
Widget toShimmer({bool isShow = true}) => isShow
|
||||||
|
? Shimmer.fromColors(
|
||||||
|
baseColor: Color(0xffe8eff0),
|
||||||
|
highlightColor: Colors.white,
|
||||||
|
child: Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: this,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
child: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget animatedSwither() => AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
// transitionBuilder: (Widget child, Animation<double> animation) {
|
||||||
|
// return ScaleTransition(scale: animation, child: child);
|
||||||
|
// },
|
||||||
|
switchInCurve: Curves.linearToEaseOut,
|
||||||
|
switchOutCurve: Curves.linearToEaseOut,
|
||||||
|
child: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget objectContainerView({String title = "", String note = "", bool disablePadding = false, double radius = 15}) {
|
||||||
|
return Container(
|
||||||
|
padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(radius),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: const Color(0xff000000).withOpacity(.05),
|
||||||
|
blurRadius: 26,
|
||||||
|
offset: const Offset(0, -3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (title.isNotEmpty) title.toText16(),
|
||||||
|
if (title.isNotEmpty) 12.height,
|
||||||
|
this,
|
||||||
|
if (note.isNotEmpty) note.toText11(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget objectContainerBorderView(
|
||||||
|
{String title = "",
|
||||||
|
String note = "",
|
||||||
|
bool disablePadding = false,
|
||||||
|
double radius = 15,
|
||||||
|
Color? color,
|
||||||
|
Color borderColor = MyColors.lightGreyEFColor,
|
||||||
|
bool disableWidth = false,
|
||||||
|
bool isAlignment = false}) {
|
||||||
|
return Container(
|
||||||
|
padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(radius),
|
||||||
|
color: color,
|
||||||
|
border: Border.all(
|
||||||
|
color: borderColor,
|
||||||
|
width: disableWidth ? 2 : 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alignment: isAlignment ? Alignment.center : null,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (title.isNotEmpty) title.toText16(),
|
||||||
|
if (title.isNotEmpty) 12.height,
|
||||||
|
this,
|
||||||
|
if (note.isNotEmpty) note.toText11(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,274 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
|
||||||
|
import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/utils.dart';
|
||||||
|
import 'package:mohem_flutter_app/config/routes.dart';
|
||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mohem_flutter_app/main.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/menus.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/generic_response_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
|
||||||
|
|
||||||
|
/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool
|
||||||
|
// ignore: prefer_mixin
|
||||||
|
class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
|
//Attendance Tracking
|
||||||
|
bool isAttendanceTrackingLoading = true;
|
||||||
|
int endTime = 0, isTimeRemainingInSeconds = 0;
|
||||||
|
double progress = 0.0;
|
||||||
|
GetAttendanceTracking? attendanceTracking;
|
||||||
|
|
||||||
|
//Work List
|
||||||
|
bool isWorkListLoading = true;
|
||||||
|
int workListCounter = 0;
|
||||||
|
|
||||||
|
//Misssing Swipe
|
||||||
|
bool isMissingSwipeLoading = true;
|
||||||
|
int missingSwipeCounter = 0;
|
||||||
|
|
||||||
|
//Leave and Ticket Balance
|
||||||
|
bool isLeaveTicketBalanceLoading = true;
|
||||||
|
List<GetAccrualBalancesList>? accrualList;
|
||||||
|
GetAccrualBalancesList? leaveBalanceAccrual;
|
||||||
|
|
||||||
|
double get leaveBalance => leaveBalanceAccrual?.accrualNetEntitlement ?? 0;
|
||||||
|
double ticketBalance = 0;
|
||||||
|
|
||||||
|
//Menu Entries
|
||||||
|
bool isServicesMenusLoading = true;
|
||||||
|
List<Menus>? homeMenus;
|
||||||
|
List<GetMenuEntriesList>? getMenuEntriesList;
|
||||||
|
|
||||||
|
//Offers And Discounts
|
||||||
|
bool isOffersLoading = true;
|
||||||
|
List<OffersListModel> getOffersList = [];
|
||||||
|
|
||||||
|
//Attendance Tracking API's & Methods
|
||||||
|
Future<bool> fetchAttendanceTracking(context) async {
|
||||||
|
try {
|
||||||
|
attendanceTracking = await DashboardApiClient().getAttendanceTracking();
|
||||||
|
isAttendanceTrackingLoading = false;
|
||||||
|
// isTimeRemainingInSeconds = calculateSeconds( "00:00:00");
|
||||||
|
if (attendanceTracking?.pSwipeIn != null) {
|
||||||
|
isTimeRemainingInSeconds = calculateSeconds(attendanceTracking!.pRemainingHours ?? "00:00:00");
|
||||||
|
int totalShiftTimeInSeconds = calculateSeconds(attendanceTracking!.pScheduledHours ?? "00:00:00");
|
||||||
|
progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds);
|
||||||
|
endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds;
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
} catch (ex) {
|
||||||
|
Utils.handleException(ex, context, null);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initProvider() {
|
||||||
|
isAttendanceTrackingLoading = true;
|
||||||
|
endTime = 0;
|
||||||
|
isTimeRemainingInSeconds = 0;
|
||||||
|
progress = 0.0;
|
||||||
|
attendanceTracking = null;
|
||||||
|
|
||||||
|
isWorkListLoading = true;
|
||||||
|
workListCounter = 0;
|
||||||
|
|
||||||
|
isMissingSwipeLoading = true;
|
||||||
|
missingSwipeCounter = 0;
|
||||||
|
|
||||||
|
isLeaveTicketBalanceLoading = true;
|
||||||
|
accrualList = null;
|
||||||
|
leaveBalanceAccrual = null;
|
||||||
|
|
||||||
|
ticketBalance = 0;
|
||||||
|
isServicesMenusLoading = true;
|
||||||
|
homeMenus = null;
|
||||||
|
getMenuEntriesList = null;
|
||||||
|
isOffersLoading = true;
|
||||||
|
getOffersList = [];
|
||||||
|
|
||||||
|
drawerMenuItemList = [
|
||||||
|
DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile),
|
||||||
|
DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation),
|
||||||
|
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi),
|
||||||
|
DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions),
|
||||||
|
DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen),
|
||||||
|
DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword),
|
||||||
|
];
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
int calculateSeconds(String time) {
|
||||||
|
int hour = int.parse(time.split(":")[0]);
|
||||||
|
int mints = int.parse(time.split(":")[1]);
|
||||||
|
int seconds = int.parse(time.split(":")[2]);
|
||||||
|
return ((hour * 60 * 60) + (mints * 60) + seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(context) {
|
||||||
|
fetchAttendanceTracking(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItgFormsModel? itgFormsModel;
|
||||||
|
List<GetOpenNotificationsList>? getOpenNotificationsList;
|
||||||
|
MohemmITGPendingTaskResponseItem? cocCount;
|
||||||
|
int cocFinalCount = 0;
|
||||||
|
|
||||||
|
//Work List API's & Methods
|
||||||
|
Future fetchWorkListCounter(context, {bool showLoading = false}) async {
|
||||||
|
try {
|
||||||
|
if (showLoading) Utils.showLoading(context);
|
||||||
|
GenericResponseModel? genericResponseModel = await DashboardApiClient().getOpenNotifications();
|
||||||
|
|
||||||
|
isWorkListLoading = false;
|
||||||
|
getOpenNotificationsList = genericResponseModel?.getOpenNotificationsList;
|
||||||
|
|
||||||
|
workListCounter = genericResponseModel?.pOPENNTFNUMBER ?? 0;
|
||||||
|
|
||||||
|
itgFormsModel = await DashboardApiClient().getItgFormsPendingTask();
|
||||||
|
workListCounter = workListCounter + (itgFormsModel?.totalCount ?? 0);
|
||||||
|
GenericResponseModel? cocGenericResponseModel = await DashboardApiClient().getCOCNotifications();
|
||||||
|
cocCount = cocGenericResponseModel?.mohemmITGPendingTaskResponseItem;
|
||||||
|
if (cocCount != null) {
|
||||||
|
cocFinalCount = (cocCount?.escalation ?? 0) + (cocCount?.waitingToClose ?? 0) + (cocCount?.waitingForAcceptance ?? 0) + (cocCount?.extendTATRequest ?? 0);
|
||||||
|
workListCounter += cocFinalCount;
|
||||||
|
}
|
||||||
|
if (showLoading) Utils.hideLoading(context);
|
||||||
|
notifyListeners();
|
||||||
|
} catch (ex) {
|
||||||
|
isWorkListLoading = false;
|
||||||
|
logger.wtf(ex);
|
||||||
|
if (showLoading) Utils.hideLoading(context);
|
||||||
|
notifyListeners();
|
||||||
|
Utils.handleException(ex, context, (err) {
|
||||||
|
Utils.hideLoading(context);
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (cxt) => ConfirmDialog(
|
||||||
|
message: err,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route<dynamic> route) => false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Missing Siwpe API's & Methods
|
||||||
|
Future fetchMissingSwipe(context) async {
|
||||||
|
try {
|
||||||
|
GenericResponseModel? genericResponseModel = await DashboardApiClient().getOpenMissingSwipes();
|
||||||
|
isMissingSwipeLoading = false;
|
||||||
|
missingSwipeCounter = genericResponseModel!.getOpenMissingSwipesList!.pOpenMissingSwipes ?? 0;
|
||||||
|
notifyListeners();
|
||||||
|
} catch (ex) {
|
||||||
|
isMissingSwipeLoading = false;
|
||||||
|
logger.wtf(ex);
|
||||||
|
notifyListeners();
|
||||||
|
Utils.handleException(ex, context, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Leave and Ticket Balance API's & Methods
|
||||||
|
Future fetchLeaveTicketBalance(context, DateTime date) async {
|
||||||
|
try {
|
||||||
|
accrualList = await DashboardApiClient().getAccrualBalances(DateFormat("MM/dd/yyyy").format(date));
|
||||||
|
isLeaveTicketBalanceLoading = false;
|
||||||
|
leaveBalanceAccrual = accrualList![0];
|
||||||
|
ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0);
|
||||||
|
notifyListeners();
|
||||||
|
} catch (ex) {
|
||||||
|
isLeaveTicketBalanceLoading = false;
|
||||||
|
logger.wtf(ex);
|
||||||
|
notifyListeners();
|
||||||
|
Utils.handleException(ex, context, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//List Menu API's & Methods
|
||||||
|
|
||||||
|
List<DrawerMenuItem> drawerMenuItemList = [];
|
||||||
|
|
||||||
|
void fetchListMenu() async {
|
||||||
|
try {
|
||||||
|
List<ListMenu> menuList = await DashboardApiClient().getListMenu();
|
||||||
|
List findMyRequest = menuList.where((element) => element.menuType == "E").toList();
|
||||||
|
if (findMyRequest.isNotEmpty) {
|
||||||
|
drawerMenuItemList.insert(3, DrawerMenuItem("assets/images/drawer/my_requests.svg", LocaleKeys.myRequest.tr(), AppRoutes.myRequests));
|
||||||
|
}
|
||||||
|
List findMyTeam = menuList.where((element) => element.menuType == "M").toList();
|
||||||
|
if (findMyTeam.isNotEmpty) {
|
||||||
|
drawerMenuItemList.insert(2, DrawerMenuItem("assets/images/drawer/my_team.svg", LocaleKeys.myTeamMembers.tr(), AppRoutes.myTeam));
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
logger.wtf(ex);
|
||||||
|
Utils.handleException(ex, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Menu Entries API's & Methods
|
||||||
|
void fetchMenuEntries() async {
|
||||||
|
try {
|
||||||
|
GenericResponseModel? genericResponseModel = await DashboardApiClient().getGetMenuEntries();
|
||||||
|
getMenuEntriesList = genericResponseModel!.getMenuEntriesList;
|
||||||
|
homeMenus = parseMenus(getMenuEntriesList ?? []);
|
||||||
|
if (homeMenus!.isNotEmpty) {
|
||||||
|
homeMenus!.first.menuEntiesList.insert(0, GetMenuEntriesList(requestType: "MONTHLY_ATTENDANCE", prompt: LocaleKeys.monthlyAttendance.tr()));
|
||||||
|
homeMenus!.first.menuEntiesList.add(GetMenuEntriesList(requestType: "VACATION_RULE", prompt: LocaleKeys.vacationRule.tr()));
|
||||||
|
}
|
||||||
|
isServicesMenusLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
} catch (ex) {
|
||||||
|
logger.wtf(ex);
|
||||||
|
notifyListeners();
|
||||||
|
Utils.handleException(ex, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCategoryOffersListAPI(BuildContext context) async {
|
||||||
|
try {
|
||||||
|
// Utils.showLoading(context);
|
||||||
|
getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 6);
|
||||||
|
isOffersLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
} catch (ex) {
|
||||||
|
// Utils.hideLoading(context);
|
||||||
|
notifyListeners();
|
||||||
|
Utils.handleException(ex, context, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Menus> parseMenus(List<GetMenuEntriesList> getMenuEntriesList) {
|
||||||
|
List<Menus> menus = [];
|
||||||
|
for (int i = 0; i < getMenuEntriesList.length; i++) {
|
||||||
|
if (getMenuEntriesList[i].parentMenuName!.isEmpty) {
|
||||||
|
menus.add(Menus(getMenuEntriesList[i], getMenuEntriesList.where((element) => getMenuEntriesList[i].menuName == element.parentMenuName).toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return menus;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<MohemmItgResponseItem?> getITGNotification() async {
|
||||||
|
MohemmItgResponseItem? res = await DashboardApiClient().getITGPageNotification();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void notify() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/theme/colors.dart';
|
||||||
|
|
||||||
|
class AppTheme {
|
||||||
|
static ThemeData getTheme(isArabic) => ThemeData(
|
||||||
|
fontFamily: isArabic ? 'Cairo' : 'Poppins',
|
||||||
|
primarySwatch: Colors.red,
|
||||||
|
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||||
|
brightness: Brightness.light,
|
||||||
|
pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
|
builders: {
|
||||||
|
TargetPlatform.android: ZoomPageTransitionsBuilder(),
|
||||||
|
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
hintColor: Colors.grey[400],
|
||||||
|
colorScheme: ColorScheme.fromSwatch(accentColor: MyColors.backgroundColor),
|
||||||
|
disabledColor: Colors.grey[300],
|
||||||
|
errorColor: const Color.fromRGBO(235, 80, 60, 1.0),
|
||||||
|
scaffoldBackgroundColor: MyColors.backgroundColor,
|
||||||
|
textSelectionTheme: const TextSelectionThemeData(cursorColor: Colors.grey, selectionColor: Color.fromRGBO(80, 100, 253, 0.5), selectionHandleColor: Colors.grey),
|
||||||
|
canvasColor: Colors.white,
|
||||||
|
backgroundColor: const Color.fromRGBO(255, 255, 255, 1),
|
||||||
|
highlightColor: Colors.grey[100]!.withOpacity(0.4),
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
primaryColor: primaryColor,
|
||||||
|
primaryColorDark: primaryColor,
|
||||||
|
buttonColor: Colors.black,
|
||||||
|
toggleableActiveColor: secondaryColor,
|
||||||
|
indicatorColor: secondaryColor,
|
||||||
|
bottomSheetTheme: const BottomSheetThemeData(
|
||||||
|
backgroundColor: Color(0xFFE0E0E0),
|
||||||
|
),
|
||||||
|
primaryTextTheme: const TextTheme(
|
||||||
|
bodyText2: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
iconTheme: const IconThemeData(color: MyColors.darkIconColor),
|
||||||
|
textTheme: const TextTheme(
|
||||||
|
bodyText1: TextStyle(color: Colors.black, letterSpacing: 0.6),
|
||||||
|
headline1: TextStyle(color: Colors.white, letterSpacing: 0.6),
|
||||||
|
headline2: TextStyle(color: Colors.white, letterSpacing: 0.6),
|
||||||
|
),
|
||||||
|
floatingActionButtonTheme: const FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2),
|
||||||
|
appBarTheme: AppBarTheme(
|
||||||
|
color: const Color(0xff515A5D),
|
||||||
|
brightness: Brightness.light,
|
||||||
|
elevation: 0.0,
|
||||||
|
actionsIconTheme: IconThemeData(
|
||||||
|
color: Colors.grey[800],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExtendedRevoCheckTheme on TextTheme {
|
||||||
|
//add custom styles and colors here
|
||||||
|
//taken from https://medium.com/@crizantlai/flutter-how-to-extend-themedata-b5b987a95bb5
|
||||||
|
TextStyle get price => const TextStyle(color: Colors.redAccent);
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
const Color primaryColor = Color(0xffF8F8F8);
|
||||||
|
const Color secondaryColor = Color(0xff2BB8A6);
|
||||||
|
const Color accentColor = Colors.blue;
|
||||||
|
const Color appBackgroundColor = Colors.white;
|
||||||
|
Color? accentColorDark = Colors.green[800];
|
||||||
|
const Color borderColor = Color(0xffE8E8E8);
|
||||||
|
Color? borderLightColor = Colors.blueGrey[50];
|
||||||
|
Color backgroudColor = Colors.blueGrey[50]!.withOpacity(0.5);
|
||||||
|
const Color iconColor = Colors.blueGrey;
|
||||||
|
Color? headingColor = Colors.blueGrey[800];
|
||||||
|
Color? txtColor = Colors.blueGrey[500];
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
/* ZiK */
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
typedef ChildProvider<E> = Widget Function(BuildContext context, E? data);
|
||||||
|
|
||||||
|
class Updater<T> extends StatelessWidget{
|
||||||
|
final ChildProvider<T> childProvider;
|
||||||
|
StreamController<T?>? sink;
|
||||||
|
T? initialData;
|
||||||
|
List<T?> _history = [];
|
||||||
|
|
||||||
|
Stream<T?>? _stream;
|
||||||
|
Updater({T? initialData, required this.childProvider}){
|
||||||
|
this.sink = StreamController<T?>();
|
||||||
|
this.initialData = initialData;
|
||||||
|
_stream = this.sink?.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return StreamBuilder<T?>(
|
||||||
|
initialData: this.initialData,
|
||||||
|
stream: _stream,
|
||||||
|
builder: (ctx, snapshot){
|
||||||
|
return childProvider(context, snapshot.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void pushData(T? data) {
|
||||||
|
_history.add(data);
|
||||||
|
sink?.sink.add(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T?> getDataHistory() => _history;
|
||||||
|
T? getLatestData() => _history.last;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/config/routes.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
|
||||||
|
AppBar AppBarWidget(BuildContext context,
|
||||||
|
{required String title,
|
||||||
|
bool showHomeButton = true,
|
||||||
|
bool showNotificationButton = false,
|
||||||
|
bool showMemberButton = false,
|
||||||
|
String? image}) {
|
||||||
|
return AppBar(
|
||||||
|
leadingWidth: 0,
|
||||||
|
// leading: GestureDetector(
|
||||||
|
// behavior: HitTestBehavior.opaque,
|
||||||
|
// onTap: Feedback.wrapForTap(() => Navigator.maybePop(context), context),
|
||||||
|
// child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor),
|
||||||
|
// ),
|
||||||
|
//titleSpacing: -1.44,
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap:
|
||||||
|
Feedback.wrapForTap(() => Navigator.maybePop(context), context),
|
||||||
|
child:
|
||||||
|
const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor),
|
||||||
|
),
|
||||||
|
4.width,
|
||||||
|
if (image != null) SvgPicture.asset(
|
||||||
|
image,
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
),
|
||||||
|
if (image != null) 14.width,
|
||||||
|
title.toText24(color: MyColors.darkTextColor, isBold: true).expanded,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
centerTitle: false,
|
||||||
|
elevation: 0,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
actions: [
|
||||||
|
if (showHomeButton)
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.popUntil(
|
||||||
|
context, ModalRoute.withName(AppRoutes.dashboard));
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.home, color: MyColors.darkIconColor),
|
||||||
|
),
|
||||||
|
if (showNotificationButton)
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, AppRoutes.worklistSettings);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.notifications, color: MyColors.textMixColor),
|
||||||
|
),
|
||||||
|
if (showMemberButton)
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, AppRoutes.subordinateLeave);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.people, color: MyColors.textMixColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
|
||||||
|
class AppLogo extends StatelessWidget {
|
||||||
|
AppLogo({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
"assets/mohemm_logo.svg",
|
||||||
|
height: 48,
|
||||||
|
width: 48,
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
),
|
||||||
|
8.width,
|
||||||
|
LocaleKeys.mohemm.tr().toText14()
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
|
||||||
|
void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc}) {
|
||||||
|
showModalBottomSheet<String>(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topRight: Radius.circular(25),
|
||||||
|
topLeft: Radius.circular(25),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
13.height,
|
||||||
|
Container(
|
||||||
|
height: 6,
|
||||||
|
width: 60,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Color(0xff9A9A9A),
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(20),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
child,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).then((value) {
|
||||||
|
// print("BACK FROM DELEGATE!!!!");
|
||||||
|
// print("value: $value");
|
||||||
|
if (value == "delegate_reload") {
|
||||||
|
callBackFunc();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class BottomSheetItem extends StatelessWidget {
|
||||||
|
final Function onTap;
|
||||||
|
final IconData icon;
|
||||||
|
final String title;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
const BottomSheetItem({Key? key, required this.onTap, required this.title, required this.icon, this.color = Colors.black}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if (onTap != null) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
onTap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 18.0),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
if (icon != null)
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
color: color,
|
||||||
|
size: 18.0,
|
||||||
|
),
|
||||||
|
if (icon != null) SizedBox(width: 24.0),
|
||||||
|
Text(
|
||||||
|
title ?? "",
|
||||||
|
style: TextStyle(color: color),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
|
||||||
|
extension WithContainer on Widget {
|
||||||
|
Widget get insideContainer => Container(
|
||||||
|
color: Colors.white,
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21),
|
||||||
|
child: this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultButton extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final VoidCallback? onPress;
|
||||||
|
final Color textColor;
|
||||||
|
final Color? color;
|
||||||
|
final Color? disabledColor;
|
||||||
|
final IconData? iconData;
|
||||||
|
final String? svgIcon;
|
||||||
|
final double? fontSize;
|
||||||
|
final bool isTextExpanded;
|
||||||
|
final int count;
|
||||||
|
final List<Color>? colors;
|
||||||
|
|
||||||
|
const DefaultButton(
|
||||||
|
this.text,
|
||||||
|
this.onPress, {
|
||||||
|
Key? key,
|
||||||
|
this.color,
|
||||||
|
this.isTextExpanded = true,
|
||||||
|
this.svgIcon,
|
||||||
|
this.disabledColor,
|
||||||
|
this.count = 0,
|
||||||
|
this.textColor = Colors.white,
|
||||||
|
this.iconData,
|
||||||
|
this.fontSize,
|
||||||
|
this.colors,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onPress,
|
||||||
|
child: Container(
|
||||||
|
height: 43,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(6.0),
|
||||||
|
gradient: onPress == null
|
||||||
|
? const LinearGradient(
|
||||||
|
colors: <Color>[
|
||||||
|
Color(0xffEAEAEA),
|
||||||
|
Color(0xffEAEAEA),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: color == MyColors.yellowColorII
|
||||||
|
? const LinearGradient(
|
||||||
|
colors: <Color>[
|
||||||
|
MyColors.yellowColorII,
|
||||||
|
MyColors.yellowColorII,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: LinearGradient(
|
||||||
|
transform: const GradientRotation(.83),
|
||||||
|
begin: Alignment.topRight,
|
||||||
|
end: Alignment.bottomLeft,
|
||||||
|
colors: colors ??
|
||||||
|
<Color>[
|
||||||
|
MyColors.gradiantEndColor,
|
||||||
|
MyColors.gradiantStartColor,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
if (iconData != null) Icon(iconData, color: textColor),
|
||||||
|
if (svgIcon != null)
|
||||||
|
SvgPicture.asset(svgIcon ?? "", color: textColor),
|
||||||
|
if (!isTextExpanded)
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: (iconData ?? svgIcon) != null ? 6 : 0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: fontSize ?? 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: textColor,
|
||||||
|
letterSpacing: -0.48,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isTextExpanded)
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: fontSize ?? 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: textColor,
|
||||||
|
letterSpacing: -0.48,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (count > 0)
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.only(top: 6, bottom: 6),
|
||||||
|
padding: const EdgeInsets.only(left: 5, right: 5),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
height: 16,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"$count",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: Color(0xffD02127),
|
||||||
|
letterSpacing: -0.6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
|
||||||
|
class SimpleButton extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final VoidCallback? onPress;
|
||||||
|
final Color textColor;
|
||||||
|
final Color? color;
|
||||||
|
final double? fontSize;
|
||||||
|
final List<Color>? colors;
|
||||||
|
|
||||||
|
SimpleButton(this.text, this.onPress, {this.color, this.textColor = Colors.white, this.fontSize, this.colors});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onPress,
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: const EdgeInsets.only(left: 12, right: 12, top: 4, bottom: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(6.0),
|
||||||
|
gradient: onPress == null
|
||||||
|
? const LinearGradient(colors: [Color(0xffEAEAEA), Color(0xffEAEAEA)])
|
||||||
|
: LinearGradient(
|
||||||
|
transform: const GradientRotation(.83),
|
||||||
|
begin: Alignment.topRight,
|
||||||
|
end: Alignment.bottomLeft,
|
||||||
|
colors: colors ??
|
||||||
|
[
|
||||||
|
MyColors.gradiantEndColor,
|
||||||
|
MyColors.gradiantStartColor,
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: TextStyle(fontSize: fontSize ?? 16, fontWeight: FontWeight.w600, color: textColor, letterSpacing: -0.48),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CircularAvatar extends StatelessWidget {
|
||||||
|
final String? url;
|
||||||
|
final double radius;
|
||||||
|
final double width;
|
||||||
|
final double height;
|
||||||
|
final bool isImageBase64;
|
||||||
|
|
||||||
|
CircularAvatar({Key? key, this.radius = 70.0, this.width = 70, this.height = 60, this.url, this.isImageBase64 = false}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
image: isImageBase64
|
||||||
|
? null
|
||||||
|
: DecorationImage(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: NetworkImage(url ?? "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: (isImageBase64 && url != null) ? imageFromBase64String(url!) : Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget imageFromBase64String(String base64String) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(100),
|
||||||
|
child: Image.memory(
|
||||||
|
base64Decode(base64String),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,515 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CircularStepProgressBar extends StatelessWidget {
|
||||||
|
/// Defines if steps grow from
|
||||||
|
/// clockwise [CircularDirection.clockwise] or
|
||||||
|
/// counterclockwise [CircularDirection.counterclockwise]
|
||||||
|
final CircularDirection circularDirection;
|
||||||
|
|
||||||
|
/// Number of steps to underline, all the steps with
|
||||||
|
/// index <= [currentStep] will have [Color] equal to
|
||||||
|
/// [selectedColor]
|
||||||
|
///
|
||||||
|
/// Only used when [customColor] is [null]
|
||||||
|
///
|
||||||
|
/// Default value: 0
|
||||||
|
final int currentStep;
|
||||||
|
|
||||||
|
/// Total number of step of the complete indicator
|
||||||
|
final int totalSteps;
|
||||||
|
|
||||||
|
/// Radial spacing between each step. Remember to
|
||||||
|
/// define the value in radiant units
|
||||||
|
///
|
||||||
|
/// Default value: math.pi / 20
|
||||||
|
final double padding;
|
||||||
|
|
||||||
|
/// Height of the indicator's box container
|
||||||
|
final double? height;
|
||||||
|
|
||||||
|
/// Width of the indicator's box container
|
||||||
|
final double? width;
|
||||||
|
|
||||||
|
/// Assign a custom [Color] for each step
|
||||||
|
///
|
||||||
|
/// Takes a [int], index of the current step starting from 0, and
|
||||||
|
/// must return a [Color]
|
||||||
|
///
|
||||||
|
/// **NOTE**: If provided, it overrides
|
||||||
|
/// [selectedColor] and [unselectedColor]
|
||||||
|
final Color Function(int)? customColor;
|
||||||
|
|
||||||
|
/// [Color] of the selected steps
|
||||||
|
///
|
||||||
|
/// All the steps with index <= [currentStep]
|
||||||
|
///
|
||||||
|
/// Default value: [Colors.blue]
|
||||||
|
final Color? selectedColor;
|
||||||
|
|
||||||
|
/// [Color] of the unselected steps
|
||||||
|
///
|
||||||
|
/// All the steps with index between
|
||||||
|
/// [currentStep] and [totalSteps]
|
||||||
|
///
|
||||||
|
/// Default value: [Colors.grey]
|
||||||
|
final Color? unselectedColor;
|
||||||
|
|
||||||
|
/// The size of a single step in the indicator
|
||||||
|
///
|
||||||
|
/// Default value: 6.0
|
||||||
|
final double stepSize;
|
||||||
|
|
||||||
|
/// Specify a custom size for selected steps
|
||||||
|
///
|
||||||
|
/// Only applicable when not custom setting (customColor, customStepSize) is defined
|
||||||
|
///
|
||||||
|
/// This value will replace the [stepSize] only for selected steps
|
||||||
|
final double? selectedStepSize;
|
||||||
|
|
||||||
|
/// Specify a custom size for unselected steps
|
||||||
|
///
|
||||||
|
/// Only applicable when not custom setting (customColor, customStepSize) is defined
|
||||||
|
///
|
||||||
|
/// This value will replace the [stepSize] only for unselected steps
|
||||||
|
final double? unselectedStepSize;
|
||||||
|
|
||||||
|
/// Assign a custom size [double] for each step
|
||||||
|
///
|
||||||
|
/// Function takes a [int], index of the current step starting from 0, and
|
||||||
|
/// a [bool], which tells if the step is selected based on [currentStep],
|
||||||
|
/// and must return a [double] size of the step
|
||||||
|
///
|
||||||
|
/// **NOTE**: If provided, it overrides [stepSize]
|
||||||
|
final double Function(int, bool)? customStepSize;
|
||||||
|
|
||||||
|
/// [Widget] contained inside the circular indicator
|
||||||
|
final Widget? child;
|
||||||
|
|
||||||
|
/// Height of the indicator container in case no [height] parameter
|
||||||
|
/// given and parent height is [double.infinity]
|
||||||
|
///
|
||||||
|
/// Default value: 100.0
|
||||||
|
final double fallbackHeight;
|
||||||
|
|
||||||
|
/// Height of the indicator container in case no [width] parameter
|
||||||
|
/// given and parent height is [double.infinity]
|
||||||
|
///
|
||||||
|
/// Default value: 100.0
|
||||||
|
final double fallbackWidth;
|
||||||
|
|
||||||
|
/// Angle in radiants in which the first step of the indicator is placed.
|
||||||
|
/// The initial value is on the top of the indicator (- math.pi / 2)
|
||||||
|
/// - 0 => TOP
|
||||||
|
/// - math.pi / 2 => LEFT
|
||||||
|
/// - math.pi => BOTTOM
|
||||||
|
/// - math.pi / 2 * 3 => RIGHT
|
||||||
|
/// - math.pi / 2 => TOP (again)
|
||||||
|
final double startingAngle;
|
||||||
|
|
||||||
|
/// Angle in radiants which represents the size of the arc used to display the indicator.
|
||||||
|
/// It allows you to draw a semi-circle instead of a full 360° (math.pi * 2) circle.
|
||||||
|
final double arcSize;
|
||||||
|
|
||||||
|
/// Adds rounded edges at the beginning and at the end of the circular indicator
|
||||||
|
/// given a [int], index of each step, and a [bool],
|
||||||
|
/// which tells if the step is selected based on [currentStep], and must return a
|
||||||
|
/// [bool] that tells if the edges are rounded or not
|
||||||
|
///
|
||||||
|
/// **NOTE**: For continuous circular indicators (`padding: 0`), to check if to apply
|
||||||
|
/// the rounded edges the packages uses index 0 (for the first arc painted) and
|
||||||
|
/// 1 (for the second arc painted)
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// // Example: Add rounded edges for all the steps
|
||||||
|
/// roundedCap: (index, _) => true
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// // Example: Add rounded edges for the selected arc of the indicator
|
||||||
|
/// roundedCap: (index, _) => index == 0,
|
||||||
|
/// padding: 0
|
||||||
|
/// ```
|
||||||
|
final bool Function(int, bool)? roundedCap;
|
||||||
|
|
||||||
|
/// Adds a gradient color to the circular indicator
|
||||||
|
///
|
||||||
|
/// **NOTE**: If provided, it overrides [selectedColor], [unselectedColor], and [customColor]
|
||||||
|
final Gradient? gradientColor;
|
||||||
|
|
||||||
|
/// Removes the extra angle caused by [StrokeCap.round] when [roundedCap] is applied
|
||||||
|
final bool removeRoundedCapExtraAngle;
|
||||||
|
|
||||||
|
const CircularStepProgressBar({
|
||||||
|
required this.totalSteps,
|
||||||
|
this.child,
|
||||||
|
this.height,
|
||||||
|
this.width,
|
||||||
|
this.customColor,
|
||||||
|
this.customStepSize,
|
||||||
|
this.selectedStepSize,
|
||||||
|
this.unselectedStepSize,
|
||||||
|
this.roundedCap,
|
||||||
|
this.gradientColor,
|
||||||
|
this.circularDirection = CircularDirection.clockwise,
|
||||||
|
this.fallbackHeight = 100.0,
|
||||||
|
this.fallbackWidth = 100.0,
|
||||||
|
this.currentStep = 0,
|
||||||
|
this.selectedColor = Colors.blue,
|
||||||
|
this.unselectedColor = Colors.grey,
|
||||||
|
this.padding = math.pi / 20,
|
||||||
|
this.stepSize = 6.0,
|
||||||
|
this.startingAngle = 0,
|
||||||
|
this.arcSize = math.pi * 2,
|
||||||
|
this.removeRoundedCapExtraAngle = false,
|
||||||
|
Key? key,
|
||||||
|
}) : assert(totalSteps > 0, "Number of total steps (totalSteps) of the CircularStepProgressBar must be greater than 0"),
|
||||||
|
assert(currentStep >= 0, "Current step (currentStep) of the CircularStepProgressBar must be greater than or equal to 0"),
|
||||||
|
assert(padding >= 0.0, "Padding (padding) of the CircularStepProgressBar must be greater or equal to 0"),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// Print warning when arcSize greater than math.pi * 2 which causes steps to overlap
|
||||||
|
if (arcSize > math.pi * 2) print("WARNING (step_progress_indicator): arcSize of CircularStepProgressBar is greater than 360° (math.pi * 2), this will cause some steps to overlap!");
|
||||||
|
TextDirection textDirection = Directionality.of(context);
|
||||||
|
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) => SizedBox(
|
||||||
|
// Apply fallback for both height and width
|
||||||
|
// if their value is null and no parent size limit
|
||||||
|
height: height != null
|
||||||
|
? height
|
||||||
|
: constraints.maxHeight != double.infinity
|
||||||
|
? constraints.maxHeight
|
||||||
|
: fallbackHeight,
|
||||||
|
width: width != null
|
||||||
|
? width
|
||||||
|
: constraints.maxWidth != double.infinity
|
||||||
|
? constraints.maxWidth
|
||||||
|
: fallbackWidth,
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: _CircularIndicatorPainter(
|
||||||
|
totalSteps: totalSteps,
|
||||||
|
currentStep: currentStep,
|
||||||
|
customColor: customColor,
|
||||||
|
padding: padding,
|
||||||
|
circularDirection: circularDirection,
|
||||||
|
selectedColor: selectedColor,
|
||||||
|
unselectedColor: unselectedColor,
|
||||||
|
arcSize: arcSize,
|
||||||
|
stepSize: stepSize,
|
||||||
|
customStepSize: customStepSize,
|
||||||
|
maxDefinedSize: maxDefinedSize,
|
||||||
|
selectedStepSize: selectedStepSize,
|
||||||
|
unselectedStepSize: unselectedStepSize,
|
||||||
|
startingAngle: startingAngleTopOfIndicator,
|
||||||
|
roundedCap: roundedCap,
|
||||||
|
gradientColor: gradientColor,
|
||||||
|
textDirection: textDirection,
|
||||||
|
removeRoundedCapExtraAngle: removeRoundedCapExtraAngle,
|
||||||
|
),
|
||||||
|
// Padding needed to show the indicator when child is placed on top of it
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(maxDefinedSize),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the maximum possible size of the indicator between
|
||||||
|
/// [stepSize] and [customStepSize]
|
||||||
|
double get maxDefinedSize {
|
||||||
|
if (customStepSize == null) {
|
||||||
|
return math.max(stepSize, math.max(selectedStepSize ?? 0, unselectedStepSize ?? 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// When customSize defined, compute and return max possible size
|
||||||
|
double currentMaxSize = 0;
|
||||||
|
|
||||||
|
for (int step = 0; step < totalSteps; ++step) {
|
||||||
|
// Consider max between selected and unselected case
|
||||||
|
var customSizeValue = math.max(customStepSize!(step, false), customStepSize!(step, true));
|
||||||
|
if (customSizeValue > currentMaxSize) {
|
||||||
|
currentMaxSize = customSizeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentMaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make [startingAngle] to top-center of indicator (0°) by default
|
||||||
|
double get startingAngleTopOfIndicator => startingAngle - math.pi / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CircularIndicatorPainter implements CustomPainter {
|
||||||
|
final int totalSteps;
|
||||||
|
final int currentStep;
|
||||||
|
final double padding;
|
||||||
|
final Color? selectedColor;
|
||||||
|
final Color? unselectedColor;
|
||||||
|
final double stepSize;
|
||||||
|
final double? selectedStepSize;
|
||||||
|
final double? unselectedStepSize;
|
||||||
|
final double Function(int, bool)? customStepSize;
|
||||||
|
final double maxDefinedSize;
|
||||||
|
final Color Function(int)? customColor;
|
||||||
|
final CircularDirection circularDirection;
|
||||||
|
final double startingAngle;
|
||||||
|
final double arcSize;
|
||||||
|
final bool Function(int, bool)? roundedCap;
|
||||||
|
final Gradient? gradientColor;
|
||||||
|
final TextDirection textDirection;
|
||||||
|
final bool removeRoundedCapExtraAngle;
|
||||||
|
|
||||||
|
_CircularIndicatorPainter({
|
||||||
|
required this.totalSteps,
|
||||||
|
required this.circularDirection,
|
||||||
|
required this.customColor,
|
||||||
|
required this.currentStep,
|
||||||
|
required this.selectedColor,
|
||||||
|
required this.unselectedColor,
|
||||||
|
required this.padding,
|
||||||
|
required this.stepSize,
|
||||||
|
required this.selectedStepSize,
|
||||||
|
required this.unselectedStepSize,
|
||||||
|
required this.customStepSize,
|
||||||
|
required this.startingAngle,
|
||||||
|
required this.arcSize,
|
||||||
|
required this.maxDefinedSize,
|
||||||
|
required this.roundedCap,
|
||||||
|
required this.gradientColor,
|
||||||
|
required this.textDirection,
|
||||||
|
required this.removeRoundedCapExtraAngle,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
var w = size.width;
|
||||||
|
var h = size.height;
|
||||||
|
|
||||||
|
// Step length is user-defined arcSize
|
||||||
|
// divided by the total number of steps (each step same size)
|
||||||
|
var stepLength = arcSize / totalSteps;
|
||||||
|
|
||||||
|
// Define general arc paint
|
||||||
|
Paint paint = Paint()
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = maxDefinedSize;
|
||||||
|
|
||||||
|
var rect = Rect.fromCenter(
|
||||||
|
// Rect created from the center of the widget
|
||||||
|
center: Offset(w / 2, h / 2),
|
||||||
|
// For both height and width, subtract maxDefinedSize to fit indicator inside the parent container
|
||||||
|
height: h - maxDefinedSize,
|
||||||
|
width: w - maxDefinedSize,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (gradientColor != null) {
|
||||||
|
paint.shader = gradientColor!.createShader(rect, textDirection: textDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change color selected or unselected based on the circularDirection
|
||||||
|
var isClockwise = circularDirection == CircularDirection.clockwise;
|
||||||
|
|
||||||
|
// Make a continuous arc without rendering all the steps when possible
|
||||||
|
if (padding == 0 && customColor == null && customStepSize == null && roundedCap == null) {
|
||||||
|
_drawContinuousArc(canvas, paint, rect, isClockwise);
|
||||||
|
} else {
|
||||||
|
_drawStepArc(canvas, paint, rect, isClockwise, stepLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a series of arcs, each composing the full steps of the indicator
|
||||||
|
void _drawStepArc(Canvas canvas, Paint paint, Rect rect, bool isClockwise, double stepLength) {
|
||||||
|
// Draw a series of circular arcs to compose the indicator
|
||||||
|
// Starting based on startingAngle attribute
|
||||||
|
//
|
||||||
|
// When clockwise:
|
||||||
|
// - Start drawing counterclockwise so to have the selected steps on top of the unselected
|
||||||
|
int step = isClockwise ? totalSteps - 1 : 0;
|
||||||
|
double stepAngle = isClockwise ? startingAngle - stepLength : startingAngle;
|
||||||
|
for (; isClockwise ? step >= 0 : step < totalSteps; isClockwise ? stepAngle -= stepLength : stepAngle += stepLength, isClockwise ? --step : ++step) {
|
||||||
|
// Check if the current step is selected or unselected
|
||||||
|
var isSelectedColor = _isSelectedColor(step, isClockwise);
|
||||||
|
|
||||||
|
// Size of the step
|
||||||
|
var indexStepSize = customStepSize != null
|
||||||
|
// Consider step index inverted when counterclockwise
|
||||||
|
? customStepSize!(_indexOfStep(step, isClockwise), isSelectedColor)
|
||||||
|
: isSelectedColor
|
||||||
|
? selectedStepSize ?? stepSize
|
||||||
|
: unselectedStepSize ?? stepSize;
|
||||||
|
|
||||||
|
// Use customColor if defined
|
||||||
|
var stepColor = customColor != null
|
||||||
|
// Consider step index inverted when counterclockwise
|
||||||
|
? customColor!(_indexOfStep(step, isClockwise))
|
||||||
|
: isSelectedColor
|
||||||
|
? selectedColor!
|
||||||
|
: unselectedColor!;
|
||||||
|
|
||||||
|
// Apply stroke cap to each step
|
||||||
|
var hasStrokeCap = roundedCap != null ? roundedCap!(_indexOfStep(step, isClockwise), isSelectedColor) : false;
|
||||||
|
var strokeCap = hasStrokeCap ? StrokeCap.round : StrokeCap.butt;
|
||||||
|
|
||||||
|
// Remove extra size caused by rounded stroke cap
|
||||||
|
// https://github.com/SandroMaglione/step-progress-indicator/issues/20#issue-786114745
|
||||||
|
var extraCapSize = indexStepSize / 2;
|
||||||
|
var extraCapAngle = extraCapSize / (rect.width / 2);
|
||||||
|
var extraCapRemove = hasStrokeCap && removeRoundedCapExtraAngle;
|
||||||
|
|
||||||
|
// Draw arc steps of the indicator
|
||||||
|
_drawArcOnCanvas(
|
||||||
|
canvas: canvas,
|
||||||
|
rect: rect,
|
||||||
|
startingAngle: stepAngle + (extraCapRemove ? extraCapAngle : 0),
|
||||||
|
sweepAngle: stepLength - padding - (extraCapRemove ? extraCapAngle * 2 : 0),
|
||||||
|
paint: paint,
|
||||||
|
color: stepColor,
|
||||||
|
strokeWidth: indexStepSize,
|
||||||
|
strokeCap: strokeCap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw optimized continuous indicator instead of multiple steps
|
||||||
|
void _drawContinuousArc(Canvas canvas, Paint paint, Rect rect, bool isClockwise) {
|
||||||
|
// Compute color of the selected and unselected bars
|
||||||
|
var firstStepColor = isClockwise ? selectedColor : unselectedColor;
|
||||||
|
var secondStepColor = !isClockwise ? selectedColor : unselectedColor;
|
||||||
|
|
||||||
|
// Selected and unselected step sizes if defined, otherwise use stepSize
|
||||||
|
var firstStepSize = isClockwise ? selectedStepSize ?? stepSize : unselectedStepSize ?? stepSize;
|
||||||
|
var secondStepSize = !isClockwise ? selectedStepSize ?? stepSize : unselectedStepSize ?? stepSize;
|
||||||
|
|
||||||
|
// Compute length and starting angle of the selected and unselected bars
|
||||||
|
var firstArcLength = arcSize * (currentStep / totalSteps);
|
||||||
|
var secondArcLength = arcSize - firstArcLength;
|
||||||
|
|
||||||
|
// firstArcStartingAngle = startingAngle
|
||||||
|
var secondArcStartingAngle = startingAngle + firstArcLength;
|
||||||
|
|
||||||
|
// Apply stroke cap to both arcs
|
||||||
|
// NOTE: For continuous circular indicator, it uses 0 and 1 as index to
|
||||||
|
// apply the rounded cap
|
||||||
|
var firstArcStrokeCap = roundedCap != null
|
||||||
|
? isClockwise
|
||||||
|
? roundedCap!(0, true)
|
||||||
|
: roundedCap!(1, false)
|
||||||
|
: false;
|
||||||
|
var secondArcStrokeCap = roundedCap != null
|
||||||
|
? isClockwise
|
||||||
|
? roundedCap!(1, false)
|
||||||
|
: roundedCap!(0, true)
|
||||||
|
: false;
|
||||||
|
var firstCap = firstArcStrokeCap ? StrokeCap.round : StrokeCap.butt;
|
||||||
|
var secondCap = secondArcStrokeCap ? StrokeCap.round : StrokeCap.butt;
|
||||||
|
|
||||||
|
// When clockwise, draw the second arc first and the first on top of it
|
||||||
|
// Required when stroke cap is rounded to make the selected step on top of the unselected
|
||||||
|
if (circularDirection == CircularDirection.clockwise) {
|
||||||
|
// Second arc, selected when counterclockwise, unselected otherwise
|
||||||
|
_drawArcOnCanvas(
|
||||||
|
canvas: canvas,
|
||||||
|
rect: rect,
|
||||||
|
paint: paint,
|
||||||
|
startingAngle: secondArcStartingAngle,
|
||||||
|
sweepAngle: secondArcLength,
|
||||||
|
strokeWidth: secondStepSize,
|
||||||
|
color: secondStepColor!,
|
||||||
|
strokeCap: secondCap,
|
||||||
|
);
|
||||||
|
|
||||||
|
// First arc, selected when clockwise, unselected otherwise
|
||||||
|
_drawArcOnCanvas(
|
||||||
|
canvas: canvas,
|
||||||
|
rect: rect,
|
||||||
|
paint: paint,
|
||||||
|
startingAngle: startingAngle,
|
||||||
|
sweepAngle: firstArcLength,
|
||||||
|
strokeWidth: firstStepSize,
|
||||||
|
color: firstStepColor!,
|
||||||
|
strokeCap: firstCap,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// First arc, selected when clockwise, unselected otherwise
|
||||||
|
_drawArcOnCanvas(
|
||||||
|
canvas: canvas,
|
||||||
|
rect: rect,
|
||||||
|
paint: paint,
|
||||||
|
startingAngle: startingAngle,
|
||||||
|
sweepAngle: firstArcLength,
|
||||||
|
strokeWidth: firstStepSize,
|
||||||
|
color: firstStepColor!,
|
||||||
|
strokeCap: firstCap,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Second arc, selected when counterclockwise, unselected otherwise
|
||||||
|
_drawArcOnCanvas(
|
||||||
|
canvas: canvas,
|
||||||
|
rect: rect,
|
||||||
|
paint: paint,
|
||||||
|
startingAngle: secondArcStartingAngle,
|
||||||
|
sweepAngle: secondArcLength,
|
||||||
|
strokeWidth: secondStepSize,
|
||||||
|
color: secondStepColor!,
|
||||||
|
strokeCap: secondCap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw the actual arc for a continuous indicator
|
||||||
|
void _drawArcOnCanvas({
|
||||||
|
required Canvas canvas,
|
||||||
|
required Rect rect,
|
||||||
|
required double startingAngle,
|
||||||
|
required double sweepAngle,
|
||||||
|
required Paint paint,
|
||||||
|
required Color color,
|
||||||
|
required double strokeWidth,
|
||||||
|
required StrokeCap strokeCap,
|
||||||
|
}) =>
|
||||||
|
canvas.drawArc(
|
||||||
|
rect,
|
||||||
|
startingAngle,
|
||||||
|
sweepAngle,
|
||||||
|
false /*isRadial*/,
|
||||||
|
paint
|
||||||
|
..color = color
|
||||||
|
..strokeWidth = strokeWidth
|
||||||
|
..strokeCap = strokeCap,
|
||||||
|
);
|
||||||
|
|
||||||
|
bool _isSelectedColor(int step, bool isClockwise) => isClockwise ? step < currentStep : (step + 1) > (totalSteps - currentStep);
|
||||||
|
|
||||||
|
/// Start counting indexes from the right if clockwise and on the left if counterclockwise
|
||||||
|
int _indexOfStep(int step, bool isClockwise) => isClockwise ? step : totalSteps - step - 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => oldDelegate != this;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool hitTest(Offset position) => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addListener(listener) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void removeListener(listener) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Null get semanticsBuilder => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRebuildSemantics(CustomPainter oldDelegate) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to define the [circularDirection] attribute of the [CircularStepProgressBar]
|
||||||
|
enum CircularDirection {
|
||||||
|
clockwise,
|
||||||
|
counterclockwise,
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import 'package:easy_localization/src/public_ext.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
|
||||||
|
|
||||||
|
class ConfirmDialog extends StatelessWidget {
|
||||||
|
final String? title;
|
||||||
|
final String message;
|
||||||
|
final String? okTitle;
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
|
const ConfirmDialog({Key? key, this.title, required this.message, this.okTitle, this.onTap}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
shape: const RoundedRectangleBorder(),
|
||||||
|
insetPadding: const EdgeInsets.only(left: 21, right: 21),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
title ?? LocaleKeys.confirm.tr(),
|
||||||
|
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: MyColors.darkTextColor, height: 35 / 24, letterSpacing: -0.96),
|
||||||
|
).paddingOnly(top: 16),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
color: MyColors.darkTextColor,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
message.toText16(color: MyColors.lightGrayColor),
|
||||||
|
28.height,
|
||||||
|
DefaultButton(
|
||||||
|
okTitle ?? LocaleKeys.ok.tr(),
|
||||||
|
onTap ?? () => Navigator.pop(context),
|
||||||
|
textColor: Colors.white,
|
||||||
|
//color: Ap.green,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
void showMDialog(context, {Widget? child,Color? backgroundColor,bool isDismissable=true}) async {
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: isDismissable,
|
||||||
|
builder: (context) {
|
||||||
|
return Dialog(
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
|
||||||
|
class InputWidget extends StatefulWidget {
|
||||||
|
final String labelText;
|
||||||
|
final String hintText;
|
||||||
|
final TextEditingController controller;
|
||||||
|
final VoidCallback? suffixTap;
|
||||||
|
final bool isEnable;
|
||||||
|
final bool hasSelection;
|
||||||
|
final int? lines;
|
||||||
|
final bool isInputTypeNum;
|
||||||
|
final bool isTextIsPassword;
|
||||||
|
final bool isBackgroundEnable;
|
||||||
|
final bool isEnableBorder;
|
||||||
|
final double verticalPadding;
|
||||||
|
final double horizontalPadding;
|
||||||
|
final Function(String)? onChange;
|
||||||
|
|
||||||
|
InputWidget(
|
||||||
|
this.labelText,
|
||||||
|
this.hintText,
|
||||||
|
this.controller, {
|
||||||
|
Key? key,
|
||||||
|
this.isTextIsPassword = false,
|
||||||
|
this.suffixTap,
|
||||||
|
this.isEnable = true,
|
||||||
|
this.hasSelection = false,
|
||||||
|
this.isEnableBorder = true,
|
||||||
|
this.lines = 1,
|
||||||
|
this.onChange,
|
||||||
|
this.isInputTypeNum = false,
|
||||||
|
this.isBackgroundEnable = false,
|
||||||
|
this.verticalPadding = 15,
|
||||||
|
this.horizontalPadding = 16,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_InputWidgetState createState() {
|
||||||
|
return _InputWidgetState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InputWidgetState extends State<InputWidget> {
|
||||||
|
late bool isObscureText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
isObscureText = widget.isTextIsPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(left: widget.horizontalPadding, right: widget.horizontalPadding, bottom: widget.verticalPadding, top: widget.verticalPadding),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
color: widget.isBackgroundEnable ? Color(0xffF7F7F7) : Colors.white,
|
||||||
|
border: Border.all(
|
||||||
|
color: widget.isEnableBorder ? Color(0xffefefef) : Colors.transparent,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: widget.hasSelection ? () {} : null,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.labelText,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xff2B353E),
|
||||||
|
letterSpacing: -0.44,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextField(
|
||||||
|
enabled: widget.isEnable,
|
||||||
|
scrollPadding: EdgeInsets.zero,
|
||||||
|
keyboardType: widget.isInputTypeNum ? TextInputType.number : TextInputType.text,
|
||||||
|
controller: widget.controller,
|
||||||
|
maxLines: widget.lines,
|
||||||
|
obscuringCharacter: "*",
|
||||||
|
obscureText: isObscureText,
|
||||||
|
onChanged: widget.onChange,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
height: 21 / 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Color(0xff2B353E),
|
||||||
|
letterSpacing: -0.44,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
hintText: widget.hintText,
|
||||||
|
hintStyle: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
height: 21 / 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Color(0xff575757),
|
||||||
|
letterSpacing: -0.56,
|
||||||
|
),
|
||||||
|
suffixIconConstraints: const BoxConstraints(minWidth: 50),
|
||||||
|
suffixIcon: widget.suffixTap == null ? null : IconButton(icon: const Icon(Icons.mic, color: MyColors.darkTextColor), onPressed: widget.suffixTap),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
border: InputBorder.none,
|
||||||
|
focusedBorder: InputBorder.none,
|
||||||
|
enabledBorder: InputBorder.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (widget.isTextIsPassword) ...[
|
||||||
|
16.width,
|
||||||
|
Icon(isObscureText ? Icons.visibility_rounded : Icons.visibility_off_rounded).onPress(() {
|
||||||
|
setState(() {
|
||||||
|
isObscureText = !isObscureText;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
],
|
||||||
|
if (widget.hasSelection) Icon(Icons.keyboard_arrow_down_outlined),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,150 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/itg_forms_models/itg_worklist_table_model.dart';
|
||||||
|
|
||||||
|
class ItemDetailView extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
const ItemDetailView(this.title, this.value, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"$title:".toText12(isBold: true, color: const Color(0xff2D3238)),
|
||||||
|
6.width,
|
||||||
|
(value.isEmpty ? "--" : value).toText12(color: MyColors.normalTextColor).expanded,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemDetailViewCol extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
const ItemDetailViewCol(this.title, this.value, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"$title:".toText12(isBold: true, color: const Color(0xff2BB8A6)),
|
||||||
|
4.width,
|
||||||
|
(value.isEmpty ? "--" : value).toText12(color: MyColors.normalTextColor),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemDetailViewGridItem extends StatelessWidget {
|
||||||
|
int index;
|
||||||
|
final String? title;
|
||||||
|
final String? value;
|
||||||
|
final String? type;
|
||||||
|
final bool isNeedToShowEmptyDivider;
|
||||||
|
|
||||||
|
ItemDetailViewGridItem(this.index, this.title, this.value, {Key? key, this.isNeedToShowEmptyDivider = false, this.type = ""}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(left: index % 2 != 0 ? 12 : 0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
//MyColors.lightGreyEFColor
|
||||||
|
// <--- left side
|
||||||
|
color: index % 2 != 0 ? MyColors.lightGreyEFColor : Colors.transparent,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
// <--- left side
|
||||||
|
color: index > 1 ? MyColors.lightGreyEFColor : Colors.transparent,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: isNeedToShowEmptyDivider
|
||||||
|
? Container()
|
||||||
|
: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
title != null ? Flexible(child: "$title:".toText12Auto(isBold: true, color: const Color(0xff2BB8A6))) : Container(),
|
||||||
|
4.width,
|
||||||
|
type != null
|
||||||
|
? type!.toLowerCase() == "table"
|
||||||
|
? getStringFromJSON(value!)
|
||||||
|
: Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor))
|
||||||
|
: Container(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemDetailGrid extends StatelessWidget {
|
||||||
|
Widget child1, child2;
|
||||||
|
|
||||||
|
bool isItLast;
|
||||||
|
|
||||||
|
ItemDetailGrid(this.child1, this.child2, {this.isItLast = false});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: child1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
height: double.infinity,
|
||||||
|
color: MyColors.lightGreyEFColor,
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: child2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isItLast) 1.divider,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getStringFromJSON(String jsonString) {
|
||||||
|
var body = json.decode(jsonString);
|
||||||
|
ITGWorkListTableModel itgWorkListTableModel = ITGWorkListTableModel();
|
||||||
|
if (body.length != 0) {
|
||||||
|
itgWorkListTableModel = ITGWorkListTableModel.fromJson(body[0][0]);
|
||||||
|
return Flexible(child: (itgWorkListTableModel.textvalue).toString().toText12Auto(color: MyColors.normalTextColor));
|
||||||
|
} else {
|
||||||
|
return Flexible(child: ("-").toString().toText12Auto(color: MyColors.normalTextColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
|
class LoadingDialog extends StatefulWidget {
|
||||||
|
LoadingDialog({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_LoadingDialogState createState() {
|
||||||
|
return _LoadingDialogState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoadingDialogState extends State<LoadingDialog> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
insetPadding: const EdgeInsets.symmetric(horizontal: 60.0, vertical: 24.0),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
elevation: 0,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
child: Directionality(
|
||||||
|
textDirection: TextDirection.rtl,
|
||||||
|
child: Center(
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/images/logos/loading_mohemm_logo.gif",
|
||||||
|
height: 96.0,
|
||||||
|
width: 96.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,373 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/animation.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
typedef OnDone = void Function(String text);
|
||||||
|
|
||||||
|
class ProvidedPinBoxTextAnimation {
|
||||||
|
static AnimatedSwitcherTransitionBuilder scalingTransition = (child, animation) {
|
||||||
|
return ScaleTransition(
|
||||||
|
child: child,
|
||||||
|
scale: animation,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
static AnimatedSwitcherTransitionBuilder defaultNoTransition = (Widget child, Animation<double> animation) {
|
||||||
|
return child;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class OTPWidget extends StatefulWidget {
|
||||||
|
final int maxLength;
|
||||||
|
final TextEditingController? controller;
|
||||||
|
|
||||||
|
final Color defaultBorderColor;
|
||||||
|
final Color pinBoxColor;
|
||||||
|
final double pinBoxBorderWidth;
|
||||||
|
final double pinBoxRadius;
|
||||||
|
final bool hideDefaultKeyboard;
|
||||||
|
|
||||||
|
final TextStyle? pinTextStyle;
|
||||||
|
final double pinBoxHeight;
|
||||||
|
final double pinBoxWidth;
|
||||||
|
final OnDone? onDone;
|
||||||
|
final bool hasError;
|
||||||
|
final Color errorBorderColor;
|
||||||
|
final Color textBorderColor;
|
||||||
|
final Function(String)? onTextChanged;
|
||||||
|
final bool autoFocus;
|
||||||
|
final FocusNode? focusNode;
|
||||||
|
final AnimatedSwitcherTransitionBuilder? pinTextAnimatedSwitcherTransition;
|
||||||
|
final Duration pinTextAnimatedSwitcherDuration;
|
||||||
|
final TextDirection textDirection;
|
||||||
|
final TextInputType keyboardType;
|
||||||
|
final EdgeInsets pinBoxOuterPadding;
|
||||||
|
|
||||||
|
const OTPWidget({
|
||||||
|
Key? key,
|
||||||
|
this.maxLength: 4,
|
||||||
|
this.controller,
|
||||||
|
this.pinBoxWidth: 70.0,
|
||||||
|
this.pinBoxHeight: 70.0,
|
||||||
|
this.pinTextStyle,
|
||||||
|
this.onDone,
|
||||||
|
this.defaultBorderColor: Colors.black,
|
||||||
|
this.textBorderColor: Colors.black,
|
||||||
|
this.pinTextAnimatedSwitcherTransition,
|
||||||
|
this.pinTextAnimatedSwitcherDuration: const Duration(),
|
||||||
|
this.hasError: false,
|
||||||
|
this.errorBorderColor: Colors.red,
|
||||||
|
this.onTextChanged,
|
||||||
|
this.autoFocus: false,
|
||||||
|
this.focusNode,
|
||||||
|
this.textDirection: TextDirection.ltr,
|
||||||
|
this.keyboardType: TextInputType.number,
|
||||||
|
this.pinBoxOuterPadding = const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
|
this.pinBoxColor = Colors.white,
|
||||||
|
this.pinBoxBorderWidth = 2.0,
|
||||||
|
this.pinBoxRadius = 0,
|
||||||
|
this.hideDefaultKeyboard = false,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
return OTPWidgetState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixin {
|
||||||
|
AnimationController? _highlightAnimationController;
|
||||||
|
FocusNode? focusNode;
|
||||||
|
String text = "";
|
||||||
|
int currentIndex = 0;
|
||||||
|
List<String> strList = [];
|
||||||
|
bool hasFocus = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(OTPWidget oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
focusNode = widget.focusNode ?? focusNode;
|
||||||
|
|
||||||
|
if (oldWidget.maxLength < widget.maxLength) {
|
||||||
|
setState(() {
|
||||||
|
currentIndex = text.length;
|
||||||
|
});
|
||||||
|
widget.controller?.text = text;
|
||||||
|
widget.controller?.selection = TextSelection.collapsed(offset: text.length);
|
||||||
|
} else if (oldWidget.maxLength > widget.maxLength && widget.maxLength > 0 && text.length > 0 && text.length > widget.maxLength) {
|
||||||
|
setState(() {
|
||||||
|
text = text.substring(0, widget.maxLength);
|
||||||
|
currentIndex = text.length;
|
||||||
|
});
|
||||||
|
widget.controller?.text = text;
|
||||||
|
widget.controller?.selection = TextSelection.collapsed(offset: text.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateStrList() {
|
||||||
|
if (strList.length > widget.maxLength) {
|
||||||
|
strList.length = widget.maxLength;
|
||||||
|
}
|
||||||
|
while (strList.length < widget.maxLength) {
|
||||||
|
strList.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
focusNode = widget.focusNode ?? FocusNode();
|
||||||
|
|
||||||
|
_initTextController();
|
||||||
|
calculateStrList();
|
||||||
|
widget.controller?.addListener(_controllerListener);
|
||||||
|
focusNode?.addListener(_focusListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _controllerListener() {
|
||||||
|
if (mounted == true) {
|
||||||
|
setState(() {
|
||||||
|
_initTextController();
|
||||||
|
});
|
||||||
|
var onTextChanged = widget.onTextChanged;
|
||||||
|
if (onTextChanged != null) {
|
||||||
|
onTextChanged(widget.controller?.text ?? "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _focusListener() {
|
||||||
|
if (mounted == true) {
|
||||||
|
setState(() {
|
||||||
|
hasFocus = focusNode?.hasFocus ?? false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initTextController() {
|
||||||
|
if (widget.controller == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strList.clear();
|
||||||
|
var text = widget.controller?.text ?? "";
|
||||||
|
if (text.isNotEmpty) {
|
||||||
|
if (text.length > widget.maxLength) {
|
||||||
|
throw Exception("TextEditingController length exceeded maxLength!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 0; i < text.length; i++) {
|
||||||
|
strList.add(text[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double get _width {
|
||||||
|
var width = 0.0;
|
||||||
|
for (var i = 0; i < widget.maxLength; i++) {
|
||||||
|
width += widget.pinBoxWidth;
|
||||||
|
if (i == 0) {
|
||||||
|
width += widget.pinBoxOuterPadding.left;
|
||||||
|
} else if (i + 1 == widget.maxLength) {
|
||||||
|
width += widget.pinBoxOuterPadding.right;
|
||||||
|
} else {
|
||||||
|
width += widget.pinBoxOuterPadding.left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
if (widget.focusNode == null) {
|
||||||
|
focusNode?.dispose();
|
||||||
|
} else {
|
||||||
|
focusNode?.removeListener(_focusListener);
|
||||||
|
}
|
||||||
|
_highlightAnimationController?.dispose();
|
||||||
|
widget.controller?.removeListener(_controllerListener);
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
_otpTextInput(),
|
||||||
|
_touchPinBoxRow(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _touchPinBoxRow() {
|
||||||
|
return widget.hideDefaultKeyboard
|
||||||
|
? _pinBoxRow(context)
|
||||||
|
: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: () {
|
||||||
|
if (hasFocus) {
|
||||||
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
|
Future.delayed(Duration(milliseconds: 100), () {
|
||||||
|
FocusScope.of(context).requestFocus(focusNode);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
FocusScope.of(context).requestFocus(focusNode);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: _pinBoxRow(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _otpTextInput() {
|
||||||
|
var transparentBorder = OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.transparent,
|
||||||
|
width: 0.0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return Container(
|
||||||
|
width: _width,
|
||||||
|
height: widget.pinBoxHeight,
|
||||||
|
child: TextField(
|
||||||
|
autofocus: !kIsWeb ? widget.autoFocus : false,
|
||||||
|
enableInteractiveSelection: false,
|
||||||
|
focusNode: focusNode,
|
||||||
|
controller: widget.controller,
|
||||||
|
keyboardType: widget.keyboardType,
|
||||||
|
inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null,
|
||||||
|
style: TextStyle(
|
||||||
|
height: 0.1,
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.all(0),
|
||||||
|
focusedErrorBorder: transparentBorder,
|
||||||
|
errorBorder: transparentBorder,
|
||||||
|
disabledBorder: transparentBorder,
|
||||||
|
enabledBorder: transparentBorder,
|
||||||
|
focusedBorder: transparentBorder,
|
||||||
|
counterText: null,
|
||||||
|
counterStyle: null,
|
||||||
|
helperStyle: TextStyle(
|
||||||
|
height: 0.0,
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
labelStyle: TextStyle(height: 0.1),
|
||||||
|
fillColor: Colors.transparent,
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
cursorColor: Colors.transparent,
|
||||||
|
showCursor: false,
|
||||||
|
maxLength: widget.maxLength,
|
||||||
|
onChanged: _onTextChanged,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTextChanged(text) {
|
||||||
|
var onTextChanged = widget.onTextChanged;
|
||||||
|
if (onTextChanged != null) {
|
||||||
|
onTextChanged(text);
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
this.text = text;
|
||||||
|
if (text.length >= currentIndex) {
|
||||||
|
for (int i = currentIndex; i < text.length; i++) {
|
||||||
|
strList[i] = text[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentIndex = text.length;
|
||||||
|
});
|
||||||
|
if (text.length == widget.maxLength) {
|
||||||
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
|
var onDone = widget.onDone;
|
||||||
|
if (onDone != null) {
|
||||||
|
onDone(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _pinBoxRow(BuildContext context) {
|
||||||
|
calculateStrList();
|
||||||
|
List<Widget> pinCodes = List.generate(widget.maxLength, (int i) {
|
||||||
|
return _buildPinCode(i, context);
|
||||||
|
});
|
||||||
|
return Row(children: pinCodes, mainAxisSize: MainAxisSize.min);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPinCode(int i, BuildContext context) {
|
||||||
|
Color borderColor;
|
||||||
|
Color pinBoxColor = widget.pinBoxColor;
|
||||||
|
|
||||||
|
if (widget.hasError) {
|
||||||
|
borderColor = widget.errorBorderColor;
|
||||||
|
} else if (i < text.length) {
|
||||||
|
borderColor = widget.textBorderColor;
|
||||||
|
} else {
|
||||||
|
borderColor = widget.defaultBorderColor;
|
||||||
|
pinBoxColor = widget.pinBoxColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeInsets insets;
|
||||||
|
if (i == 0) {
|
||||||
|
insets = EdgeInsets.only(
|
||||||
|
left: 0,
|
||||||
|
top: widget.pinBoxOuterPadding.top,
|
||||||
|
right: widget.pinBoxOuterPadding.right,
|
||||||
|
bottom: widget.pinBoxOuterPadding.bottom,
|
||||||
|
);
|
||||||
|
} else if (i == strList.length - 1) {
|
||||||
|
insets = EdgeInsets.only(
|
||||||
|
left: widget.pinBoxOuterPadding.left,
|
||||||
|
top: widget.pinBoxOuterPadding.top,
|
||||||
|
right: 0,
|
||||||
|
bottom: widget.pinBoxOuterPadding.bottom,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
insets = widget.pinBoxOuterPadding;
|
||||||
|
}
|
||||||
|
return Container(
|
||||||
|
key: ValueKey<String>("container$i"),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
|
||||||
|
margin: insets,
|
||||||
|
child: _animatedTextBox(strList[i], i),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: borderColor,
|
||||||
|
width: widget.pinBoxBorderWidth,
|
||||||
|
),
|
||||||
|
color: pinBoxColor,
|
||||||
|
borderRadius: BorderRadius.circular(widget.pinBoxRadius),
|
||||||
|
),
|
||||||
|
width: widget.pinBoxWidth,
|
||||||
|
height: widget.pinBoxHeight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _animatedTextBox(String text, int i) {
|
||||||
|
if (widget.pinTextAnimatedSwitcherTransition != null) {
|
||||||
|
return AnimatedSwitcher(
|
||||||
|
duration: widget.pinTextAnimatedSwitcherDuration,
|
||||||
|
transitionBuilder: widget.pinTextAnimatedSwitcherTransition ??
|
||||||
|
(Widget child, Animation<double> animation) {
|
||||||
|
return child;
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
key: ValueKey<String>("$text$i"),
|
||||||
|
style: widget.pinTextStyle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Text(
|
||||||
|
text,
|
||||||
|
key: ValueKey<String>("${strList[i]}$i"),
|
||||||
|
style: widget.pinTextStyle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
|
||||||
|
class ShowRadio extends StatelessWidget {
|
||||||
|
String title, value, groupValue;
|
||||||
|
Color selectedColor;
|
||||||
|
|
||||||
|
ShowRadio({
|
||||||
|
required this.title,
|
||||||
|
required this.value,
|
||||||
|
required this.groupValue,
|
||||||
|
this.selectedColor = Colors.black,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
border: Border.all(color: MyColors.grey98Color, width: 0.5),
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(100)),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: value == groupValue ? selectedColor : Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(100)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
12.width,
|
||||||
|
title.toText12(maxLine: 2)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,256 @@
|
|||||||
|
import 'package:easy_localization/src/public_ext.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
|
class GetAttendanceTrackingShimmer extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: const Color(0xff000000).withOpacity(.05),
|
||||||
|
blurRadius: 26,
|
||||||
|
offset: const Offset(0, -3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
// SvgPicture.asset("assets/images/"),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true).toShimmer(),
|
||||||
|
16.height,
|
||||||
|
"07:55:12".toText10(color: Colors.white, isBold: true).toShimmer(),
|
||||||
|
3.height,
|
||||||
|
LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(),
|
||||||
|
9.height,
|
||||||
|
const ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(20),
|
||||||
|
),
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
value: 0.7,
|
||||||
|
minHeight: 8,
|
||||||
|
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
|
||||||
|
backgroundColor: const Color(0xff196D73),
|
||||||
|
),
|
||||||
|
).toShimmer(),
|
||||||
|
],
|
||||||
|
).paddingOnly(top: 12, right: 15, left: 12),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer(),
|
||||||
|
],
|
||||||
|
).paddingOnly(left: 12),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
// color: Colors.blue,
|
||||||
|
padding: const EdgeInsets.only(left: 14, right: 14),
|
||||||
|
).toShimmer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MenuShimmer extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: const Color(0xff000000).withOpacity(.05),
|
||||||
|
blurRadius: 26,
|
||||||
|
offset: const Offset(0, -3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer(),
|
||||||
|
),
|
||||||
|
12.width,
|
||||||
|
SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServicesHeaderShimmer extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
"Other".tr().toText10().toShimmer(),
|
||||||
|
6.height,
|
||||||
|
LocaleKeys.services.tr().toText12(isBold: true).toShimmer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServicesMenuShimmer extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: const Color(0xff000000).withOpacity(.05),
|
||||||
|
blurRadius: 26,
|
||||||
|
offset: const Offset(0, -3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset("assets/images/monthly_attendance.svg").toShimmer(),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Attendan".toText11(isBold: false).toShimmer(),
|
||||||
|
5.height,
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
|
||||||
|
),
|
||||||
|
6.width,
|
||||||
|
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatHomeShimmer extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Shimmer.fromColors(
|
||||||
|
baseColor: Colors.white,
|
||||||
|
highlightColor: Colors.grey.shade100,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (_, __) => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
width: 48.0,
|
||||||
|
height: 48.0,
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 8.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 2.0),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 8.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 2.0),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 40.0,
|
||||||
|
height: 8.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
itemCount: 6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
// import 'dart:async';
|
||||||
|
//
|
||||||
|
// import 'package:flutter/material.dart';
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// void showNfcReader(BuildContext context, {Function onNcfScan}) {
|
||||||
|
// showModalBottomSheet(
|
||||||
|
// context: context,
|
||||||
|
// enableDrag: false,
|
||||||
|
// isDismissible: false,
|
||||||
|
// shape: RoundedRectangleBorder(
|
||||||
|
// borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)),
|
||||||
|
// ),
|
||||||
|
// backgroundColor: Colors.white,
|
||||||
|
// builder: (context) {
|
||||||
|
// return NfcLayout(
|
||||||
|
// onNcfScan: onNcfScan,
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class NfcLayout extends StatefulWidget {
|
||||||
|
// Function onNcfScan;
|
||||||
|
//
|
||||||
|
// NfcLayout({this.onNcfScan});
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// _NfcLayoutState createState() => _NfcLayoutState();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class _NfcLayoutState extends State<NfcLayout> {
|
||||||
|
// StreamSubscription<NDEFMessage> _stream;
|
||||||
|
// bool _reading = false;
|
||||||
|
// Widget mainWidget;
|
||||||
|
// String nfcId;
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// void initState() {
|
||||||
|
// super.initState();
|
||||||
|
//
|
||||||
|
// setState(() {
|
||||||
|
// // _reading = true;
|
||||||
|
// // Start reading using NFC.readNDEF()
|
||||||
|
// _stream = NFC.readNDEF(once: false, throwOnUserCancel: false, readerMode: NFCDispatchReaderMode()).listen((NDEFMessage message) {
|
||||||
|
// setState(() {
|
||||||
|
// _reading = true;
|
||||||
|
// mainWidget = doneNfc();
|
||||||
|
// });
|
||||||
|
// Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
|
// _stream?.cancel();
|
||||||
|
// widget.onNcfScan(nfcId);
|
||||||
|
// Navigator.pop(context);
|
||||||
|
// });
|
||||||
|
// print("read NDEF id: ${message.id}");
|
||||||
|
// print("NFC Record " + message.payload);
|
||||||
|
// print("NFC Record Lenght " + message.records.length.toString());
|
||||||
|
// print("NFC Record " + message.records.first.id);
|
||||||
|
// print("NFC Record " + message.records.first.payload);
|
||||||
|
// print("NFC Record " + message.records.first.data);
|
||||||
|
// print("NFC Record " + message.records.first.type);
|
||||||
|
// // widget.onNcfScan(message.id);
|
||||||
|
// nfcId = message.id;
|
||||||
|
// }, onError: (e) {
|
||||||
|
// // Check error handling guide below
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc();
|
||||||
|
// return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Widget scanNfc() {
|
||||||
|
// return Container(
|
||||||
|
// key: ValueKey(1),
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// "Ready To Scan",
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// fontSize: 24,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// Image.asset(
|
||||||
|
// "assets/images/nfc/ic_nfc.png",
|
||||||
|
// height: MediaQuery.of(context).size.width / 3,
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// "Approach an NFC Tag",
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 18,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// ButtonTheme(
|
||||||
|
// minWidth: MediaQuery.of(context).size.width / 1.2,
|
||||||
|
// height: 45.0,
|
||||||
|
// buttonColor: Colors.grey[300],
|
||||||
|
// shape: RoundedRectangleBorder(
|
||||||
|
// borderRadius: BorderRadius.circular(6),
|
||||||
|
// ),
|
||||||
|
// child: RaisedButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// _stream?.cancel();
|
||||||
|
// Navigator.pop(context);
|
||||||
|
// },
|
||||||
|
// elevation: 0,
|
||||||
|
// child: Text("CANCEL"),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Widget doneNfc() {
|
||||||
|
// return Container(
|
||||||
|
// key: ValueKey(2),
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// "Successfully Scanned",
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// fontSize: 24,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// Image.asset(
|
||||||
|
// "assets/images/nfc/ic_done.png",
|
||||||
|
// height: MediaQuery.of(context).size.width / 3,
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// "Approach an NFC Tag",
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 18,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// ButtonTheme(
|
||||||
|
// minWidth: MediaQuery.of(context).size.width / 1.2,
|
||||||
|
// height: 45.0,
|
||||||
|
// buttonColor: Colors.grey[300],
|
||||||
|
// shape: RoundedRectangleBorder(
|
||||||
|
// borderRadius: BorderRadius.circular(6),
|
||||||
|
// ),
|
||||||
|
// child: RaisedButton(
|
||||||
|
// // onPressed: () {
|
||||||
|
// // _stream?.cancel();
|
||||||
|
// // widget.onNcfScan(nfcId);
|
||||||
|
// // Navigator.pop(context);
|
||||||
|
// // },
|
||||||
|
// onPressed: null,
|
||||||
|
// elevation: 0,
|
||||||
|
// child: Text("DONE"),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 30,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
Loading…
Reference in New Issue