diff --git a/android/app/build.gradle b/android/app/build.gradle index 3bcb0fb..0393bbb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion flutter.compileSdkVersion + compileSdkVersion 33 ndkVersion flutter.ndkVersion compileOptions { @@ -39,7 +39,7 @@ android { applicationId "com.example.capture" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion + minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1bb93f9..1d583ff 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,11 @@ + + + + + + createState() => _MedicineCaptureState(); +} + +class _MedicineCaptureState extends State { + bool isLoading = false; + bool isSereverIssue = false; + List medicinesList = []; + List FilteredList = []; + SwiperController _controller = SwiperController(); + SwiperControl _control = SwiperControl(color: Colors.white); + double get _width => MediaQuery.of(context).size.width; + double get _height => MediaQuery.of(context).size.height; + bool inFirstPage = true; + bool inLastPage = false; + int currentIndex = 0; + List uiMedicineImages = []; + String reportsPictureId = ''; + Map reports={}; + final ImagePicker _picker = ImagePicker(); + + Future getAllMedicines() async { + isLoading = true; + + try { + var pharmacyResponse = await AppSettings.getAllMedicinesData(); + + setState(() { + medicinesList = ((jsonDecode(pharmacyResponse)['medicine']) as List) + .map((dynamic model) { + return MedicinesDataModel.fromJson(model); + }).toList(); + + isLoading = false; + }); + } catch (e) { + setState(() { + isLoading = false; + isSereverIssue = true; + }); + } + } + + Widget captureMedicineUi() { + if (medicinesList.length != 0) { + return Column( + children: [ + Container( + //color: Colors.red, + child: Row( + children: [ + Visibility( + visible: !inFirstPage, + child: TextButton( + child: const Text( + 'Previous', + style: TextStyle( + fontSize: 15, + color: primaryColor, + decoration: TextDecoration.underline, + ), + ), + onPressed: () { + _controller.previous(); + }, + ), + ), + Spacer(), + Visibility( + visible: !inLastPage, + child: TextButton( + child: const Text( + 'More Tanks ----> Next', + style: TextStyle( + fontSize: 15, + color: primaryColor, + decoration: TextDecoration.underline, + ), + ), + onPressed: () { + _controller.next(); + }, + ), + ) + ], + ), + ), + Expanded( + child: Container( + color: Colors.white, + child: Swiper( + controller: _controller, + //control:_control, + loop: false, + + scrollDirection: Axis.horizontal, + itemCount: medicinesList.length, + onIndexChanged: (value) { + if (value == medicinesList.length - 1) + setState(() { + inLastPage = true; + }); + else if (value == 0) + setState(() { + inFirstPage = true; + }); + else { + setState(() { + inFirstPage = false; + inLastPage = false; + }); + } + + }, + + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.fromLTRB(10, 10, 10, 10), + child: Center( + child: Row( + children: [ + Container( + height: MediaQuery.of(context).size.height * .18, + width: MediaQuery.of(context).size.width * .35, + decoration: BoxDecoration( + //color: medicinesList[index].cardColor, + border: Border.all( + width: 0, + color: screenBackgroundColor, + ), + borderRadius: BorderRadius.circular( + 20, + )), + child: Padding( + padding: EdgeInsets.fromLTRB(20, 20, 30, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + medicinesList[index] + .medicine_name + .toString() + .toUpperCase(), + style: valuesTextStyle()), + + ], + ), + )), + ], + )), + ); + }, + ), + ), + ), + ], + ); + } else { + return Center( + child: Padding( + padding: EdgeInsets.fromLTRB(0, 40, 0, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * .25, + ), + Text('No medicines available'), + SizedBox( + height: 20, + ), + CircleAvatar( + backgroundColor: primaryColor, + radius: 40, + child: IconButton( + iconSize: 40, + icon: const Icon( + Icons.add, + color: Colors.white, + ), + onPressed: () async { + // Navigator.pop(context); + // await Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => AddTanks()), + // ); + }, + ), + ) + ], + ), + )); + } + } + + void displayNextItem() { + setState(() { + if (currentIndex < medicinesList.length - 1) { + currentIndex++; + } + }); + } + + Future takeImageFromCameraForMedicines() async { + try { + final image = await _picker.pickImage(source: ImageSource.camera); + if (image == null) return; + final imageTemp = File(image.path); + AppSettings.preLoaderDialog(context); + var res = await AppSettings.uploadMedicinesCamera(image); + print(jsonDecode(res)); + Navigator.of(context, rootNavigator: true).pop(); + setState(() { + uiMedicineImages = jsonDecode(res)['previewUrls']; + /*reports=jsonDecode(res)['reportsPictureUpload']; + reportsPictureId=jsonDecode(res)['reportsPictureUpload']['reportsPictureId'];*/ + }); + } on PlatformException catch (e) { + print('Failed to pick image: $e'); + } + } + + @override + void initState() { + // TODO: implement initState + getAllMedicines(); + super.initState(); + } + + Widget _medicinesUI(){ + if(medicinesList.length!=0){ + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: Text( + medicinesList[currentIndex].medicine_name, + style: TextStyle(fontSize: 24), + ), + ), + GestureDetector( + child: Icon( + Icons.camera_alt_outlined, + size: 100, + color: primaryColor, + ), + onTap: () async { + await takeImageFromCameraForMedicines(); + }, + ), + SizedBox(height: 20), + ElevatedButton( + onPressed: () { + displayNextItem(); + }, + child: Text('Next Item'), + ), + ], + ); + } + else{ + return Center( + child: Padding( + padding: EdgeInsets.fromLTRB(0, 40, 0, 0), + child: isSereverIssue + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image( + image: AssetImage('images/serverissue.png'), + // height: MediaQuery.of(context).size.height * .10, + ), + SizedBox( + height: 20, + ), + Text( + 'There is an issue at server please try after some time', + style: serverIssueTextStyle(), + ), + ], + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + /*Image( + image: AssetImage('images/resourceblue.pngs'), + // height: MediaQuery.of(context).size.height * .10, + ),*/ + Icon( + Icons.info, + color: primaryColor, + size: 40, + ), + SizedBox( + height: 20, + ), + Text( + 'No Medicines available', + style: TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold, + ), + ), + ], + ))); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppSettings.appBar('Medicine'), + body: Container( + child: isLoading + ? Center( + child: CircularProgressIndicator( + color: primaryColor, + strokeWidth: 5.0, + ), + ) + : _medicinesUI(), + ), + ); + } +} diff --git a/lib/common/dashboard.dart b/lib/common/dashboard.dart new file mode 100644 index 0000000..15869b9 --- /dev/null +++ b/lib/common/dashboard.dart @@ -0,0 +1,304 @@ +import 'package:capture/capture/cpature_images.dart'; +import 'package:capture/common/settings.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:dots_indicator/dots_indicator.dart'; + + +class Dashboard extends StatefulWidget { + const Dashboard({Key? key}) : super(key: key); + + @override + State createState() => _DashboardState(); +} + +class _DashboardState extends State { + final List imgList = [ + 'images/mobilebg.png', + 'images/mobilebg2.png', + 'images/mobilebg3.png' + ]; + + bool isTablet = false; + bool isPhone = true; + int currentIndex = 0; + + Widget _newDashboard() { + return Container( + color: secondaryColor, + child: Column(children: [ + /* CarouselSlider( + options: CarouselOptions( + height: MediaQuery.of(context).size.height * .250, + aspectRatio: 16 / 9, + viewportFraction: 0.8, + initialPage: 0, + enableInfiniteScroll: true, + reverse: false, + autoPlay: true, + autoPlayInterval: Duration(seconds: 3), + autoPlayAnimationDuration: Duration(milliseconds: 800), + autoPlayCurve: Curves.ease, + enlargeCenterPage: true, + onPageChanged: (index, reason) { + setState(() { + currentIndex = index; + }); + }, + enlargeFactor: 0.2, + scrollDirection: Axis.horizontal, + ), + items: imgList.map((i) { + return Builder( + builder: (BuildContext context) { + return Container( + height: MediaQuery.of(context).size.height * .250, + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(0), + ), + //color: Colors.red, + child: FittedBox( + child: Image( + image: AssetImage(i), + ), + fit: BoxFit.fill, + )); + }, + ); + }).toList(), + ), + DotsIndicator( + dotsCount: imgList.length, + position: currentIndex, + axis: Axis.horizontal, + decorator: DotsDecorator( + color: Colors.white, + activeColor: buttonColors + ) + //decorator: decorator, + ),*/ + Padding( + padding: EdgeInsets.all(10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + children: [ + GestureDetector( + child: Container( + width: MediaQuery.of(context).size.width * .20, + height: MediaQuery.of(context).size.height * .15, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + "images/seekopinion.png"), // picked file + fit: BoxFit.fitWidth)), + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const MedicineCapture()), + ); + }, + ), + Text( + 'Capture Medicines', + style: dashboardTextStyle(), + ), + ], + ), + ], + ), + ), + ])); + } + + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + final shouldPop = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Do you want to exit app?', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + actionsAlignment: MainAxisAlignment.spaceBetween, + actions: [ + TextButton( + onPressed: () { + SystemNavigator.pop(); + }, + child: const Text('Yes', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: const Text('No', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + ), + ], + ); + }, + ); + return shouldPop!; + }, + child: Scaffold( + backgroundColor: primaryColor, + resizeToAvoidBottomInset: false, + appBar: AppSettings.appBar('Health Care'), + drawer: Drawer( + backgroundColor: primaryColor, + child: ListView( + padding: EdgeInsets.zero, + children: [ + DrawerHeader( + decoration: const BoxDecoration( + color: buttonColors, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded(child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + GestureDetector( + child: Container( + width: MediaQuery.of(context).size.width * .20, + height: + MediaQuery.of(context).size.height * .15, + decoration: BoxDecoration( + + shape: BoxShape.circle, + image: DecorationImage( + image: (AppSettings.profilePictureUrl != + '' && + AppSettings.profilePictureUrl != + 'null') + ? NetworkImage(AppSettings + .profilePictureUrl) + as ImageProvider + : AssetImage( + "images/profile_pic.png"), + + fit:BoxFit.fitWidth // picked file + ), + ), + ), + onTap: () { + }, + ), + ], + ),), + Text( + AppSettings.userName, + style: drawerHeaderTextStyleNew(), + ), + Text( + AppSettings.phoneNumber, + style: drawerHeaderTextStyleNew(), + ), + Visibility( + visible: AppSettings.email != '', + child: Text( + AppSettings.email, + style: drawerHeaderTextStyleNew(), + ), + ), + Row( + children: [ + Visibility( + visible: AppSettings.age != '', + child: Text( + AppSettings.age + ' Yrs, ', + style: drawerHeaderTextStyleNew(), + ), + ), + Visibility( + visible: AppSettings.gender != '', + child: Text( + AppSettings.gender, + style: drawerHeaderTextStyleNew(), + ), + ), + ], + ) + ], + ),), + ListTile( + title: Row( + children: [ + Image( + image: const AssetImage('images/editprofile.png'), + height: 25, + width: 25, + fit: BoxFit.fill), + const SizedBox( + width: 10, + ), + const SizedBox( + width: 10, + ), + Text('Edit Profile', style: drawerListItemsTextStyle()), + ], + ), + onTap: () { + /* Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const UpdateProfile()), + );*/ + }, + ), + Divider( + color: Colors.grey, + ), + ListTile( + title: Row( + children: [ + Image( + image: const AssetImage('images/logout.png'), + height: 25, + width: 25, + fit: BoxFit.fill), + const SizedBox( + width: 10, + ), + const SizedBox( + width: 10, + ), + Text('Logout', style: drawerListItemsTextStyle()), + ], + ), + onTap: () { + // showLogoutAlertDialog(context); + }, + ), + ], + ), + ), + body: _newDashboard(), + ), + ); + } +} diff --git a/lib/common/login.dart b/lib/common/login.dart new file mode 100644 index 0000000..6037be5 --- /dev/null +++ b/lib/common/login.dart @@ -0,0 +1,288 @@ +import 'package:capture/common/dashboard.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:capture/common/settings.dart'; +import 'package:capture/common/signup.dart'; +import 'package:path/path.dart' as Path; + +class Login extends StatefulWidget { + const Login({super.key}); + + @override + State createState() => _LoginState(); +} + +class _LoginState extends State { + + bool isObscureText=true; + TextEditingController mobileNumberController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + + + @override + void initState() { + isObscureText=true; + super.initState(); + } + + Future onWillPop() async { + final shouldPop = await showDialog(context: context, builder: (context) { + return AlertDialog( + title: const Text('Do you want to exit app?', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + actionsAlignment: MainAxisAlignment.spaceBetween, + actions: [ + TextButton( + onPressed: () { + SystemNavigator.pop(); + }, + child: const Text('Yes', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: const Text('No', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + ), + ], + ); + }, + ); + return shouldPop!; + } + + @override + Widget build(BuildContext context) { + String lastInputValue=""; + + return WillPopScope( + onWillPop: () async => onWillPop(), + child: Scaffold( + + backgroundColor: primaryColor, + body: Stack( + children: [ + /*Container( + decoration: const BoxDecoration( + image: DecorationImage(image: AssetImage("images/background.png"), fit: BoxFit.cover,), + ), + ),*/ + GestureDetector( + onTap: () { + FocusManager.instance.primaryFocus?.unfocus(); + }, + child: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + const SizedBox( + height: 15, + ), + Container( + //width: double.infinity, + child: Image( + image: const AssetImage('images/logo.png'), + height: MediaQuery.of(context).size.height * .25, + )), + SizedBox( + height:MediaQuery.of(context).size.height * .05, + ), + Container( + child: TextFormField( + cursorColor: Colors.white, + style: TextStyle(color: Colors.white), + controller: mobileNumberController, + keyboardType: TextInputType.number, + decoration: textFormFieldDecoration(Icons.phone,'Enter MobileNumber'), + + ), + ), + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Container( + child: TextFormField( + cursorColor: Colors.white, + style: TextStyle(color: Colors.white), + obscureText: isObscureText, + controller: passwordController, + decoration: InputDecoration( + fillColor: primaryColor, + filled: true, + labelText: 'Password', + prefixIcon: const Icon(Icons.password, color: Colors.white,), + labelStyle: const TextStyle( + color: Colors.white, //<-- SEE HERE + ), + border: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white)), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), + ), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), + ), + suffixIcon: IconButton( + icon: Icon( + Icons.visibility_off_outlined, + color: isObscureText==true?buttonColors:Colors.white, + ), + onPressed: () { + + print("show password"); + setState(() { + isObscureText = !isObscureText; + }); + }, + ), + + ), + + ), + ), + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Align( + alignment: Alignment.bottomRight, + child: Padding(padding: const EdgeInsets.fromLTRB(0, 0, 0,0), + child: TextButton( + onPressed: () { + /* Navigator.push( + context, + MaterialPageRoute(builder: (context) => OtpScreencForgotPassword()), + );*/ + }, + child: const Text( + 'Forgot Password?', + style: TextStyle( + color: Colors.white, + decoration: TextDecoration.underline, + + ), + ), + ),), + ), + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Container( + width:double.infinity, + height: MediaQuery.of(context).size.height * .06, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + primary: buttonColors, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () async{ + + if (mobileNumberController.text != '' && + passwordController.text != '') { + AppSettings.preLoaderDialog(context); + + bool isOnline = await AppSettings.internetConnectivity(); + + if(isOnline){ + var payload = new Map(); + payload["phone"] = mobileNumberController.text.toString(); + payload["password"] = passwordController.text.toString(); + + bool signinStatus = await AppSettings.login(payload); + + try{ + if (signinStatus) { + Navigator.of(context,rootNavigator: true).pop(); + + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const Dashboard()), + ); + AppSettings.longSuccessToast("Logged in Successfully"); + mobileNumberController.text=''; + passwordController.text=''; + + } else { + Navigator.of(context,rootNavigator: true).pop(); + AppSettings.longFailedToast("Please enter valid details"); + } + } + catch(exception){ + Navigator.of(context,rootNavigator: true).pop(); + print(exception); + } + } + else{ + Navigator.of(context,rootNavigator: true).pop(); + AppSettings.longFailedToast("Please Check internet"); + } + + + } + else{ + + AppSettings.longFailedToast("Please enter valid details"); + } + + }, + child: const Text('Login'), + )), + Padding(padding: const EdgeInsets.fromLTRB(10, 10,10,10), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Not a Member Yet?', + style: TextStyle( + color: Colors.white, + ), + ), + TextButton( + child: const Text( + 'Sign Up', + style: TextStyle(decoration: TextDecoration.underline,color: Colors.white), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SignUp()), + ); + //signup screen + }, + ) + ], + ),) + ], + ), + ) + )), + ), + ], + ) + /*bottomNavigationBar: Container( + padding: EdgeInsets.only(bottom: 13), + height: 38, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + child: Image( + image: AssetImage('images/logo_btm.png'), + width: 90, + )), + ], + ), + ),*/ + ), + ); + } +} diff --git a/lib/common/preloader.dart b/lib/common/preloader.dart new file mode 100644 index 0000000..4fa501c --- /dev/null +++ b/lib/common/preloader.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:capture/common/settings.dart'; + +class Dialogs { + static Future showLoadingDialog(BuildContext context, GlobalKey key) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new WillPopScope( + onWillPop: () async => false, + child: SimpleDialog( + key: key, + backgroundColor: Colors.white, + children: [ + Center( + child: Column(children: [ + CircularProgressIndicator( + valueColor: new AlwaysStoppedAnimation(AppBarGradient_1), + ), + SizedBox( + height: 10, + ), + Text( + AppSettings.preloadText, + style: PreloaderText(), + ), + ]), + ) + ])); + }); + } +} \ No newline at end of file diff --git a/lib/common/settings.dart b/lib/common/settings.dart new file mode 100644 index 0000000..fa5efc6 --- /dev/null +++ b/lib/common/settings.dart @@ -0,0 +1,618 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:flutter/services.dart'; +import 'package:capture/common/preloader.dart'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:intl/intl.dart'; +import 'dart:async'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:path/path.dart' as path; + +//const Color primaryColor = Color(0XFF1786A3); +const Color primaryColor = Color(0XFF68A85D); +const Color secondaryColor = Color(0XFFA0C899); +const Color buttonColors = Color(0XFFFFAC1C); +const Color greyColor = Color(0XFF8F8E8E); +const Color textFieldStartColor = Colors.grey; +const Color screenBackgroundColor = Color(0XFFEAF6FF); +const Color screenBackgroundColord = Colors.black12; +const Color dashboardbackground = Color(0XFFF5F5F5); + +//Color AppBarGradient_1 = Color(0XFF1258F6); +Color AppBarGradient_1 = Color(0XFF68A85D); + +TextStyle PreloaderText() { + return TextStyle(color: Color(0XFF68A85D)); +} + +TextStyle labelTextStyle() { + return TextStyle(color: primaryColor, fontSize: 12); +} + +TextStyle labelTextStyleOrderMedicine() { + return TextStyle(color: primaryColor, fontSize: 12,fontWeight: FontWeight.bold); +} + +TextStyle haveMotorTextStyle() { + return TextStyle( + color: Colors.red, fontSize: 12, fontWeight: FontWeight.bold); +} + +TextStyle textButtonStyle() { + return TextStyle(color: primaryColor, fontSize: 15); +} + +TextStyle textButtonStyleReports() { + return TextStyle(color: Colors.white, fontSize: 12); +} + +TextStyle iconBelowTextStyle() { + return TextStyle(fontSize: 10, color: primaryColor); +} + +TextStyle valuesTextStyle() { + return TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ); +} + +TextStyle recordDetailsHeading() { + return TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ); +} + +TextStyle problemTextStyle() { + return TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.red + ); +} + +TextStyle headingsTextStyle() { + return TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: primaryColor + ); +} + +TextStyle startAndStopHeading() { + return TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: primaryColor, + ); +} + +Text capacitySuffixText() { + return Text('in Ltrs.'); +} + +Text dimensionSuffixText() { + return Text('in fts'); +} + +TextStyle dashboardTextStyle() { + return TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ); +} + +TextStyle labelTextStyleBold() { + return TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold, + ); +} + +TextStyle serverIssueTextStyle() { + return TextStyle(color: Colors.red, fontSize: 15); +} + +TextStyle bottomSheetValuesTextStyle() { + return TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + overflow: TextOverflow.ellipsis, + ); +} + +TextStyle wrapTextStyle() { + return TextStyle( + color: primaryColor, + fontSize: 12, + fontWeight: FontWeight.bold, + overflow: TextOverflow.ellipsis, + ); +} + +TextStyle wrapTextStyleBlack() { + return TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.bold, + overflow: TextOverflow.ellipsis, + ); +} + +TextStyle withoutWrapTextStyle() { + return TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ); +} + +TextStyle bmiTextStyle() { + return TextStyle( + color: primaryColor, + fontSize: 16, + fontWeight: FontWeight.bold, + ); +} + +TextStyle drawerListItemsTextStyle() { + return TextStyle(color: Colors.white); +} + +TextStyle drawerHeaderTextStyle() { + return TextStyle(color: Colors.white, fontSize: 15); +} + +TextStyle drawerHeaderTextStyleNew() { + return TextStyle(color: Colors.black, fontSize: 15); +} +TextStyle radioHeadingTextStyle() { + return TextStyle(color: Colors.white); +} +TextStyle radioItemsTextStyle() { + return TextStyle(color: Colors.white,fontSize: 11); +} + + + +InputDecoration textFormFieldDecoration(IconData icon, var text) { + return InputDecoration( + filled: true, + fillColor: primaryColor, + prefixIcon: Icon( + icon, + color: Colors.white, + ), + border: OutlineInputBorder(borderSide: BorderSide(color: Colors.white)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), + ), + labelText: text, + labelStyle: TextStyle( + color: Colors.white, //<-- SEE HERE + ), + ); +} + + +InputDecoration textFormFieldDecorationGrey(IconData icon, var text) { + return InputDecoration( + prefixIcon: Icon( + icon, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: text, + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ); +} + + +InputDecoration textFormFieldDecorationBMI(IconData icon, var text) { + return InputDecoration( + //filled: true, + //fillColor: Colors.white, + prefixIcon: Icon( + icon, + color: primaryColor, + ), + border: OutlineInputBorder(borderSide: BorderSide(color: primaryColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: primaryColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: primaryColor), + ), + labelText: text, + labelStyle: TextStyle( + color: Colors.grey, //<-- SEE HERE + ), + ); +} + +final GlobalKey preloaderWindowKey = new GlobalKey(); +Future preloaderWindow(BuildContext context) async { + try { + Dialogs.showLoadingDialog(context, preloaderWindowKey); + } catch (error) {} +} + +class AppSettings { + static SharedPreferences sharedPreferences = + SharedPreferences.getInstance() as SharedPreferences; + static String userName = ''; + static String userAddress = ''; + static String detailedAddress = ''; + static String emergencyContactNumber1 = ''; + static String emergencyContactNumber2 = ''; + static String emergencyRelation1 = ''; + static String emergencyRelation2 = ''; + static String emergencyRelationName1 = ''; + static String emergencyRelationName2 = ''; + static String bloodGroup = ''; + static String email = ''; + static String age = ''; + static String gender = ''; + static String phoneNumber = ''; + static String accessToken = ''; + static String customerId = ''; + static double userLatitude = 0; + static double userLongitude = 0; + static String customerIdsign = ''; + static String profileImage = ''; + static List storedPreferenceValidKeys = ['username', 'access_token']; + static String preloadText = 'Please wait'; + static String latitude = ''; + static String longitude = ''; + static bool servicestatus = false; + static bool haspermission = false; + static String fcmId = ''; + static String originalQrCode = ''; + static String qrCode = ''; + static String serverToken = + 'AAAAA66BLaA:APA91bHcmbyiNN8hCL-t-M9oH-u7ZMOl74fcImMM2DQZLgdyY98Wu9XxME-CTPcjpjU6Yy48ouxISrOMb9lpa3PJofh8qciUKMNxV2al-bDvGvPP_VVaH0mrTHzR56hdkGy1Zl-0frDO'; + + //api urls + //static String host = 'http://35.200.129.165:4000/api/'; + static String host = 'http://cloudh.in:4000/api/'; + static String loginUrl = host + 'dataCaptureAdminlogin'; + static String signUpUrl = host + 'adminDataCaptureSignup'; + static String getAllMedicinesDataUrl = host + 'getAllMedicineData'; + static String resetTokenUrl = host + 'reset_token'; + static String medicinesUploadPicUrl = host + 'uploads-dataCapture'; + + + static File? updatedImage; + static String image = ''; + static String profilePictureUrl = ''; + static String bloodGroupPictureUrl = ''; + static var api = { + 'signIn': host + '/login', + }; + + /*Formatter*/ + static String formNum(String s) { + var comma = NumberFormat('#,##,###', 'en_IN'); + return comma.format( + int.parse(s), + ); + } + + static String formDouble(String s) { + var comma = NumberFormat('#,##,###.##', 'en_IN'); + return comma.format( + double.parse(s), + ); + } + + /* Preloader */ + static GlobalKey preLoaderKey = new GlobalKey(); + static Future preLoaderDialog(BuildContext context) async { + try { + preLoaderKey = new GlobalKey(); + Dialogs.showLoadingDialog(context, preLoaderKey); + } catch (error) {} + } + + ////request headers with content type + static Future> buildRequestHeaders() async { + Map _headers = new Map(); + _headers[HttpHeaders.contentTypeHeader] = 'application/json'; + _headers['Authorization'] = accessToken; + return _headers; + } + + //request headers without content type + static Future> buildPutRequestHeaders() async { + Map _headers = new Map(); + _headers['Authorization'] = accessToken; + return _headers; + } + + static Future> + buildPutRequestHeadersForResetToken() async { + Map _headers = new Map(); + return _headers; + } + + // Shared preferences save,get and clear data + static saveData(String _key, _value, type) async { + sharedPreferences = await SharedPreferences.getInstance(); + + if (type == 'STRING') { + await sharedPreferences.setString(_key, _value.toString()); + } else if (type == 'INTEGER') { + await sharedPreferences.setInt(_key, _value); + } else if (type == 'BOOL') { + await sharedPreferences.setBool(_key, _value); + } else if (type == 'DOUBLE') { + await sharedPreferences.setDouble(_key, _value); + } + } + + static getData(String _key, type) async { + sharedPreferences = await SharedPreferences.getInstance(); + if (type == 'STRING') { + return sharedPreferences.getString(_key) ?? ''; + } else if (type == 'INTEGER') { + return sharedPreferences.getInt(_key) ?? -1; + } else if (type == 'BOOL') { + return sharedPreferences.getBool(_key) ?? -1; + } else if (type == 'DOUBLE') { + return sharedPreferences.getDouble(_key) ?? -1; + } + } + + static clearSharedPrefeences() async { + sharedPreferences = await SharedPreferences.getInstance(); + await sharedPreferences.clear(); + } + + /*Sign in check*/ + static Future isSigIn() async { + bool isSignInCheck = true; + for (var eachKey in storedPreferenceValidKeys) { + if (await getData(eachKey, 'STRING') == '') { + isSignInCheck = false; + } + } + return isSignInCheck; + } + + static Future internetConnectivity() async { + try { + final result = await InternetAddress.lookup('google.com'); + if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { + return true; + } + } on SocketException catch (_) { + return false; + } + return false; + } + + /*Apis Starts here*/ + + static Future login(payload) async { + var response = await http.post(Uri.parse(loginUrl), + body: json.encode(payload), + headers: {'Content-type': 'application/json'}); + + if (response.statusCode == 200) { + try { + var _response = json.decode(response.body); + + await saveAvailableReportAndLocationsInMemory(_response); + //await saveProfilePic(_response); + return true; + + } catch (e) { + // display error toast + return false; + } + } else { + return false; + } + } + + static Future signUp(payload) async { + var response = await http.post(Uri.parse(signUpUrl), + body: json.encode(payload), + headers: {'Content-type': 'application/json'}); + + if (response.statusCode == 200) { + try { + var _response = json.decode(response.body); + //customerIdsign = _response['armintahealthdata']['customerId']; + print(_response); + return true; + } catch (e) { + // display error toast + return false; + } + } else { + return false; + } + } + + static Future getAllMedicinesData() async { + var uri = Uri.parse(getAllMedicinesDataUrl+'/'+userName.toString().toLowerCase()); + + var response = await http.get(uri, headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return response.body; + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.get(uri, headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return response.body; + } else { + return ''; + } + } else { + return ''; + } + } else { + return ''; + } + } + + static Future resetToken() async { + var uri = Uri.parse(resetTokenUrl + '/' + customerId); + + try { + // var response = await http.get(uri, headers: await buildPutRequestHeaders()); + var response = await http.get(uri, + headers: await buildPutRequestHeadersForResetToken()); + if (response.statusCode == 200) { + print(response.body); + var res = jsonDecode(response.body); + print(res); + + accessToken = res['access_token']; + return true; + } else { + return false; + } + } catch (e) { + print(e); + return false; + } + } + + static Future uploadMedicinesCamera(file) async { + var request = http.MultipartRequest('POST', Uri.parse(medicinesUploadPicUrl + '/' + customerId)); + request.files.add(await http.MultipartFile.fromPath('picture', file.path)); + var res = await request.send(); + var response = await http.Response.fromStream(res); + return response.body; + } + + + /*Apis ends here*/ + + //save data local + static Future saveAvailableReportAndLocationsInMemory( + dynamic input) async { + // save login name information + await saveData('username', input['Data']['name'], 'STRING'); + await saveData( + 'access_token', input['token'], 'STRING'); + await saveData('phone', input['Data']['phone'], 'STRING'); + await saveData('email', input['Data']['emails'][0]['email']??'', 'STRING'); + await saveData('customerId', input['Data']['accountId'], 'STRING'); + //latitude,longitude + await loadDataFromMemory(); + } + + /* static Future saveProfile(dynamic image) async { + // save login name information + await saveData('profile', image.toString(), 'STRING'); + //await loadDataFromMemory(); + }*/ + + static Uint8List convertBase64Image(String base64String) { + return Base64Decoder().convert(base64String.split(',').last); + } + + static Future loadDataFromMemory() async { + userName = await getData('username', 'STRING'); + accessToken = await getData('access_token', 'STRING'); + email = await getData('email', 'STRING'); + phoneNumber = await getData('phone', 'STRING'); + customerId = await getData('customerId', 'STRING'); + + } + + + static void longSuccessToast(String message) { + Fluttertoast.showToast( + msg: message, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + timeInSecForIosWeb: 1, + backgroundColor: Colors.green, + textColor: Colors.white, + fontSize: 16.0); + } + + static void longSuccessToast1(String message) { + Fluttertoast.showToast( + msg: message, + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.CENTER, + timeInSecForIosWeb: 1, + backgroundColor: Colors.green, + textColor: Colors.white, + fontSize: 16.0); + } + + static void longFailedToast(String message) { + Fluttertoast.showToast( + msg: message, + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.BOTTOM, + timeInSecForIosWeb: 1, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 16.0); + } + + static Widget noDataUI(String _tabName) { + _tabName = _tabName ?? ''; + return Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image( + image: AssetImage('images/no_data.png'), + width: 200, + ), + SizedBox( + height: 8, + ), + Text( + 'There is no data to show you right now.', + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + fontFamily: 'Swis2', + ), + ), + SizedBox( + height: 5, + ), + Text( + _tabName, + style: TextStyle(fontSize: 15, fontFamily: 'Swis1'), + ), + ], + ), + ); + } + + static appBar(String title) { + title = title ?? ''; + return AppBar( + backgroundColor: primaryColor, + title: Text(title), + ); + } + +} diff --git a/lib/common/signup.dart b/lib/common/signup.dart new file mode 100644 index 0000000..6af1e08 --- /dev/null +++ b/lib/common/signup.dart @@ -0,0 +1,482 @@ +import 'package:flutter/material.dart'; +import 'package:capture/common/login.dart'; +import 'package:capture/common/settings.dart'; +import 'package:flutter/services.dart'; +import 'dart:io' show File, Platform; + + + + +class SignUp extends StatefulWidget { + const SignUp({super.key}); + + @override + State createState() => _SignUpState(); +} + +class _SignUpState extends State { + bool isPwdObscureText=true; + bool isConfirmPwdObscureText = true; + TextEditingController nameController = TextEditingController(); + TextEditingController custmerid = TextEditingController(); + TextEditingController buildingNameController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + TextEditingController mobileNumberController = TextEditingController(); + TextEditingController userAddressDescriptionController = TextEditingController(); + TextEditingController userAddressCapturingController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + TextEditingController confirmPasswordController = TextEditingController(); + var genderUnitItems = [ + 'Male', + 'Female', + 'Other', + ]; + var genderUnit = 'Male'; + + + String _currentAddress =''; + String address1 = ''; + String address2 = ''; + String city = ''; + String state = ''; + String zip = ''; + String country = ''; + double lat=0; + double lng=0; + + + + + + @override + void initState() { + isPwdObscureText = true; + isConfirmPwdObscureText = true; + super.initState(); + } + + + + + + + Future onWillPop() async { + final shouldPop = await showDialog(context: context, builder: (context) { + return AlertDialog( + title: const Text('Do you want to exit app?', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + actionsAlignment: MainAxisAlignment.spaceBetween, + actions: [ + TextButton( + onPressed: () { + SystemNavigator.pop(); + }, + child: const Text('Yes', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: const Text('No', + style: TextStyle( + color: primaryColor, + fontSize: 20, + )), + ), + ], + ); + }, + ); + return shouldPop!; + } + + + + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop:()async=>onWillPop(), + child: Scaffold( + backgroundColor: primaryColor, + body: Stack(children: [ + /* Container( + decoration: const BoxDecoration( + image: DecorationImage(image: AssetImage("images/background.png"), fit: BoxFit.cover,), + ), + ),*/ + GestureDetector( + onTap: () { + FocusManager.instance.primaryFocus?.unfocus(); + }, + child: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(10), + child: Column( + children: [ + + SizedBox( + height: 20, + ), + Container( + //width: double.infinity, + child: Image( + image: const AssetImage('images/logo.png'), + height: MediaQuery.of(context).size.height * .18, + )), + + SizedBox( + height:MediaQuery.of(context).size.height * .05, + ), + Container( + child: TextFormField( + cursorColor: Colors.white, + style: TextStyle(color: Colors.white), + controller: nameController, + textCapitalization: TextCapitalization.words, + decoration: textFormFieldDecoration(Icons.person,'Enter Name'), + + ), + ), //name + + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Container( + child: TextFormField( + cursorColor: Colors.white, + style: TextStyle(color: Colors.white), + controller: mobileNumberController, + keyboardType: TextInputType.phone, + maxLength: 10, + decoration: textFormFieldDecoration(Icons.phone_android,'Enter Mobile Number'), + ), + ), //mobile + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Container( + child: TextFormField( + cursorColor: Colors.white, + style: TextStyle(color: Colors.white), + controller: emailController, + keyboardType: TextInputType.emailAddress, + decoration: textFormFieldDecoration(Icons.plagiarism_outlined,'Enter email'), + + ), + ),//address description + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Container( + child: TextFormField( + cursorColor: Colors.white, + style: TextStyle(color: Colors.white), + obscureText: isPwdObscureText, + controller: passwordController, + decoration: InputDecoration( + fillColor: primaryColor, + filled: true, + labelText: 'Create Password', + prefixIcon: const Icon( + Icons.lock, + color: Colors.white, + ), + labelStyle: const TextStyle( + color: Colors.white, //<-- SEE HERE + ), + border: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white)), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), + ), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), + ), + suffixIcon: IconButton( + icon: Icon( + Icons.visibility_off_outlined, + color: isPwdObscureText?buttonColors:Colors.white, + ), + onPressed: () { + setState(() { + isPwdObscureText = !isPwdObscureText; + }); + }, + ), + ), + ), + ), //pwd + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Container( + width:double.infinity, + height: MediaQuery.of(context).size.height * .06, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + primary: buttonColors, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () async { + if (nameController.text != '' && + passwordController.text != '' && + mobileNumberController.text != '') { + AppSettings.preLoaderDialog(context); + + var payload = new Map(); + payload["name"] = nameController.text.toString(); + payload["password"] = + passwordController.text.toString(); + payload["phone"] = + mobileNumberController.text.toString(); + payload["emails"] = [ + {"email": emailController.text.toString()} + ]; + + /* payload["gender"] = genderUnit.toString();*/ + + bool signUpStatus = await AppSettings.signUp(payload); + + try { + if (signUpStatus) { + Navigator.of(context, rootNavigator: true).pop(); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const Login()), + ); + } + else { + Navigator.of(context, rootNavigator: true).pop(); + AppSettings.longFailedToast( + "Mobile number already exists"); + } + } catch (exception) { + print(exception); + Navigator.of(context, rootNavigator: true).pop(); + AppSettings.longFailedToast("Please enter valid details"); + } + } + else { + AppSettings.longFailedToast("details should not be empty"); + } + }, + child: Text('Sign Up'), + )),//login button + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Are you a Member?', + style: TextStyle( + color: Colors.white, + ), + ), + TextButton( + child: const Text( + 'Login?', + style: TextStyle( + fontSize: 20, + color: Colors.white, + decoration: TextDecoration.underline, + ), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const Login()), + ); + }, + ) + ], + ), + ], + ), + ) + )), + ), + ])), ); + } + + + showUserSignUSuccessDialog() async { + + custmerid.text=AppSettings.customerIdsign; + + return showDialog( + context: context, + barrierDismissible: false, + useSafeArea: true, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return AlertDialog( + title: const Text('User SignUp Successfully!!'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Container( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), + child: TextFormField( + cursorColor: greyColor, + readOnly: true, + controller: nameController, + decoration: const InputDecoration( + prefixIcon: Icon( + Icons.person, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: 'User Name', + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ), + ), + ), + + + Container( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), + child: TextFormField( + cursorColor: greyColor, + readOnly: true, + controller:custmerid, + decoration: const InputDecoration( + prefixIcon: Icon( + Icons.person, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: 'User Id', + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ), + ), + ), + + // AppSettings.saveAvailableReportAndLocationsInMemorysignup('customerId'); + const SizedBox( + height:10, + ), + Container( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), + child: TextFormField( + cursorColor: greyColor, + readOnly: true, + controller: buildingNameController, + decoration: const InputDecoration( + prefixIcon: Icon( + Icons.home_filled, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: 'Building Name', + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ), + ), + ), + const SizedBox( + height:10, + ), + Container( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), + child: TextFormField( + cursorColor: greyColor, + readOnly: true, + controller: emailController, + decoration: const InputDecoration( + prefixIcon: Icon( + Icons.email, + color: greyColor, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: greyColor)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: greyColor), + ), + labelText: 'Email', + labelStyle: TextStyle( + color: greyColor, //<-- SEE HERE + ), + ), + ), + ), + ], + ), + ), + actions: [ + + Container( + width: 400, + height: 50, + padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + child: ElevatedButton( + style: ElevatedButton.styleFrom( + primary: primaryColor, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () async{ + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const Login()), + ); + + }, + child: const Text('OK'), + )), + + + /* Padding( + // padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16 ), + padding: EdgeInsets.only(left:75, bottom: 20, right: 70, top:10), + child: TextFormField( + cursorColor: greyColor, + controller: nameController, + decoration: const InputDecoration( + border: UnderlineInputBorder(), + labelText: 'Enter your username', + ), + ), + ),*/ + + + ], + ); + }); + }, + ); + } + + +} diff --git a/lib/common/splash_screen.dart b/lib/common/splash_screen.dart new file mode 100644 index 0000000..2dcf875 --- /dev/null +++ b/lib/common/splash_screen.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:capture/common/dashboard.dart'; +import 'package:capture/common/settings.dart'; +import 'package:capture/common/signup.dart'; + +void main() async{ + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + //FirebaseMessaging.onBackgroundMessage(_messageHandler); + runApp(new Splash()); +} + + +class Splash extends StatelessWidget { + + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Medicinne Capture', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new SplashScreen(), + ); + } +} + +class SplashScreen extends StatefulWidget { + const SplashScreen({ super.key }); + + @override + State createState() => _SplashScreenState(); +} +class _SplashScreenState extends State { + + + Widget _defaultHome = new SignUp(); + + + void loginCheck()async{ + + bool _result = await AppSettings.isSigIn(); + + if (_result) { + await AppSettings.loadDataFromMemory(); + AppSettings.fcmId=await AppSettings.getData('FCM_TOKEN', 'STRING'); + // await AppSettings.getProfile(); + _defaultHome = new Dashboard(); + } + } + + + + @override + void initState() { + + loginCheck(); + super.initState(); + Future.delayed( + const Duration(seconds: 5), + () => Navigator.push( + context, + MaterialPageRoute(builder: (context) => _defaultHome), + )); + } + @override + Widget build(BuildContext context) { + return Scaffold( + body: Stack( + children: [ + Container( + decoration: const BoxDecoration( + image: DecorationImage(image: AssetImage("images/splashscreen.png"), fit: BoxFit.fill,), + ), + ), + + ], + ) + ); + } + +} \ No newline at end of file diff --git a/lib/common/zoom_image.dart b/lib/common/zoom_image.dart new file mode 100644 index 0000000..c458ee3 --- /dev/null +++ b/lib/common/zoom_image.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:capture/common/settings.dart'; +import 'package:photo_view/photo_view.dart'; +class ImageZoomPage extends StatefulWidget { + var imageName; + var imageDetails; + ImageZoomPage({this.imageName,this.imageDetails}); + + + @override + State createState() => _ImageZoomPageState(); +} + +class _ImageZoomPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar:AppBar( + backgroundColor: primaryColor, + title: Text(widget.imageName), + actions: [ + IconButton( + onPressed: () { + + Navigator.pop(context); + }, + icon: Icon( + Icons.cancel, + color: Colors.red, + size: 30, + ), + ), + ], + ), + body: Container( + //width: MediaQuery.of(context).size.width * .10, + //height: MediaQuery.of(context).size.height * .50, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding(padding:EdgeInsets.fromLTRB(10,10,10,0), + child: Text('Use two fingers to zoom/double tap',style: TextStyle(color: Colors.black,fontSize: 12),),), + SizedBox(height:MediaQuery.of(context).size.height * .02,), + Expanded( + child: PhotoView( + imageProvider: NetworkImage(widget.imageDetails) as ImageProvider, + maxScale: PhotoViewComputedScale.contained * 4.0, + minScale: PhotoViewComputedScale.contained, + initialScale: PhotoViewComputedScale.contained, + basePosition: Alignment.center, + + ), + ) + ], + ) + ), + + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index e016029..854d4df 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,115 +1,23 @@ import 'package:flutter/material.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headline4, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); - } -} +import 'package:sizer/sizer.dart'; +import 'package:flutter/services.dart'; +import 'common/splash_screen.dart'; + +void main () async { + // Set default home. + Widget _defaultHome = Splash(); + WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) + .then((_) { + runApp(Sizer( + builder: (context, orientation, deviceType) { + return MaterialApp( + title: 'Medicine Capture', + theme: ThemeData.light(), + home:_defaultHome, + debugShowCheckedModeBanner: false, + ); + }, + )); + }); +} \ No newline at end of file diff --git a/lib/models/medicinesdata_model.dart b/lib/models/medicinesdata_model.dart new file mode 100644 index 0000000..dd0e7d1 --- /dev/null +++ b/lib/models/medicinesdata_model.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class MedicinesDataModel { + String medicine_name = ''; + int id = 0; + + + MedicinesDataModel(); + + factory MedicinesDataModel.fromJson(Map json){ + MedicinesDataModel rtvm = new MedicinesDataModel(); + + rtvm.medicine_name = json['name'] ?? ''; + rtvm.id = json['Id'] ?? 0; + + return rtvm; + } + +} \ No newline at end of file diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..64a0ece 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..2db3c22 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..ab1fdba 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,10 @@ import FlutterMacOS import Foundation +import file_selector_macos +import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index b6fd1d8..2a85463 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,6 +15,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + card_swiper: + dependency: "direct main" + description: + name: card_swiper + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + carousel_slider: + dependency: "direct main" + description: + name: carousel_slider + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.1" characters: dependency: transitive description: @@ -36,6 +50,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + cross_file: + dependency: transitive + description: + name: cross_file + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.3+4" cupertino_icons: dependency: "direct main" description: @@ -43,6 +64,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" + dots_indicator: + dependency: "direct main" + description: + name: dots_indicator + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" fake_async: dependency: transitive description: @@ -50,6 +78,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.3+1" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.3" flutter: dependency: "direct main" description: flutter @@ -62,11 +132,114 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.15" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + url: "https://pub.dartlang.org" + source: hosted + version: "8.2.4" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.5" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.9" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.7+4" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.9.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + intl: + dependency: "direct main" + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" lints: dependency: transitive description: @@ -95,6 +268,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" path: dependency: transitive description: @@ -102,6 +282,111 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + photo_view: + dependency: "direct main" + description: + name: photo_view + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0" + pinch_zoom: + dependency: "direct main" + description: + name: pinch_zoom + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.5" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.3" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + sizer: + dependency: "direct main" + description: + name: sizer + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.15" sky_engine: dependency: transitive description: flutter @@ -149,6 +434,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.12" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" vector_math: dependency: transitive description: @@ -156,5 +455,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" sdks: dart: ">=2.18.5 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 1d0f361..87b2dc6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,91 +1,38 @@ name: capture description: A new Flutter project. -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: '>=2.18.5 <3.0.0' -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + sizer: ^2.0.11 + fluttertoast: ^8.2.2 + photo_view: ^0.14.0 + pinch_zoom: ^1.0.0 + http: ^0.13.5 + shared_preferences: ^2.0.15 + intl: ^0.17.0 + dots_indicator: ^3.0.0 + carousel_slider: ^4.2.1 + card_swiper: ^3.0.1 + image_picker: ^0.8.6+1 dev_dependencies: flutter_test: sdk: flutter - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. flutter_lints: ^2.0.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true + assets: + - images/ - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/test/widget_test.dart b/test/widget_test.dart index 4c09320..d6c29d3 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -5,6 +5,7 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:capture/common/splash_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -13,7 +14,7 @@ import 'package:capture/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); + await tester.pumpWidget( Splash()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..77ab7a0 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..a423a02 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST