From 40f96bcfcaab168dd8bfec16d84db1387a87a4c1 Mon Sep 17 00:00:00 2001 From: Ruchi71 Date: Thu, 14 Dec 2023 13:59:23 +0530 Subject: [PATCH] contact screen , image picker, tag --- android/build.gradle | 2 +- lib/common_widgets.dart | 13 + lib/importexpense_screen.dart | 364 +++++++++++------- lib/personselector_screen.dart | 88 ----- lib/tags_screen.dart | 8 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 11 files changed, 266 insertions(+), 221 deletions(-) delete mode 100644 lib/personselector_screen.dart diff --git a/android/build.gradle b/android/build.gradle index 3cdaac9..b0022f8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.9.21' repositories { google() mavenCentral() diff --git a/lib/common_widgets.dart b/lib/common_widgets.dart index 29fa961..c847db4 100644 --- a/lib/common_widgets.dart +++ b/lib/common_widgets.dart @@ -200,3 +200,16 @@ InputDecoration customUnderlineInputdecoration( ), suffixIcon: suffixicon ?? const SizedBox()); } + + +// ------------------ contact ui -------------------------- + +Widget customContactUi({required Function()? onTap}){ + return InkWell( + onTap: onTap, + child: const Icon( + Icons.contact_page, + color: primaryColor, + size: 35, + )); +} diff --git a/lib/importexpense_screen.dart b/lib/importexpense_screen.dart index e63a7c4..b7cefb1 100644 --- a/lib/importexpense_screen.dart +++ b/lib/importexpense_screen.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:fluttercontactpicker/fluttercontactpicker.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:kilvish/constants/dimens_constants.dart'; import 'package:flutter/scheduler.dart'; -import 'package:kilvish/personselector_screen.dart'; import 'package:kilvish/style.dart'; +import 'package:kilvish/tags_screen.dart'; import '../common_widgets.dart'; import 'dart:io'; @@ -31,11 +33,40 @@ class _ImportExpensePageState extends State { PageController(initialPage: 0, viewportFraction: 0.95, keepPage: false); final List _galleryItems = []; int _initialIndex = 0; + PhoneContact? _phoneContact; + XFile? _imageFile; TextEditingController amountcon = TextEditingController(); - bool isPersonSelected = false; - bool isTagSelected = false; + TextEditingController namecon = TextEditingController(); String pickedname = ""; - String pickednumber = ""; + List tagList = []; + + Future _pickImage() async { + final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery); + + setState(() { + _imageFile = pickedFile; + }); + } + + + contactFetchFn() async { + bool permission = await FlutterContactPicker.requestPermission(); + if (permission) { + if (await FlutterContactPicker.hasPermission()) { + _phoneContact = await FlutterContactPicker.pickPhoneContact(); + if (_phoneContact != null) { + if (_phoneContact!.fullName!.isNotEmpty) { + setState(() { + pickedname = _phoneContact!.fullName.toString(); + namecon.text = _phoneContact!.fullName.toString(); + }); + } + + if (_phoneContact!.phoneNumber!.number!.isNotEmpty) {} + } + } + } + } @override void initState() { @@ -65,139 +96,187 @@ class _ImportExpensePageState extends State { padding: const EdgeInsets.symmetric( horizontal: DimensionConstants.leftPadding15, vertical: DimensionConstants.topPadding10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: DimensionConstants.sizedBoxHeight5), - headertext("Amount"), - SizedBox( - height: DimensionConstants.containerHeight40, - child: TextFormField( - onChanged: (val) { - amountcon.text = val; - }, - controller: amountcon, - maxLines: 1, - cursorColor: primaryColor, - decoration: customUnderlineInputdecoration( - hintText: 'Enter Amount', bordersideColor: primaryColor)), - ), - const SizedBox(height: DimensionConstants.leftPadding15), - headertext("To"), - isPersonSelected - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: DimensionConstants.sizedBoxHeight5, - ), - Container( - decoration: BoxDecoration( - color: Colors.pink[50], - border: Border.all(color: primaryColor), - borderRadius: BorderRadius.circular( - DimensionConstants.circular20)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: customText( - pickedname, primaryColor, 14, FontWeight.w500), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: DimensionConstants.sizedBoxHeight5), + headertext("Amount"), + SizedBox( + height: DimensionConstants.containerHeight40, + child: TextFormField( + onChanged: (val) { + amountcon.text = val; + }, + controller: amountcon, + maxLines: 1, + cursorColor: primaryColor, + decoration: customUnderlineInputdecoration( + hintText: 'Enter Amount', + bordersideColor: primaryColor)), + ), + const SizedBox(height: DimensionConstants.leftPadding15), + headertext("To"), + pickedname.isNotEmpty + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: DimensionConstants.sizedBoxHeight5, ), + Row( + children: [ + customSelecteData(text: pickedname, ontap: () { + setState(() { + pickedname = ""; + namecon.clear(); + }); + },), + const Spacer(), + customContactUi(onTap: contactFetchFn), + ], + ), + const SizedBox( + height: DimensionConstants.sizedBoxHeight5, + ), + Container( + width: MediaQuery.of(context).size.width, + height: 1, + color: bordercolor, + ), + ], + ) + : TextFormField( + controller: namecon, + maxLines: 1, + cursorColor: primaryColor, + decoration: customUnderlineInputdecoration( + hintText: 'Enter Name or select from contact', + bordersideColor: primaryColor, + suffixicon: customContactUi(onTap: contactFetchFn),)), + const SizedBox(height: DimensionConstants.leftPadding15), + headertext("Receipt/ Screenshot"), + const SizedBox(height: DimensionConstants.sizedBoxHeight5), + _imageFile != null?ClipRRect( + borderRadius: BorderRadius.circular(15), + + child: Stack( + children: [ + Image.file(File(_imageFile!.path), + width: MediaQuery.of(context).size.width, + height: DimensionConstants.containerHeight200,fit: BoxFit.fill,), + + Positioned( + right: 10, + top: 10, + child: InkWell( + onTap: (){ + setState(() { + _imageFile = null; + }); + }, + child: Container( + decoration: const BoxDecoration( + color: primaryColor, + shape: BoxShape.circle + ), + child: const Padding( + padding: EdgeInsets.all(5.0), + child: Icon(Icons.clear,color: kWhitecolor,), + )), + )) + ]), + ): + InkWell( + onTap: _pickImage, + child: Container( + width: MediaQuery.of(context).size.width, + height: DimensionConstants.containerHeight200, + decoration: BoxDecoration( + color: borderCustom, + borderRadius: + BorderRadius.circular(DimensionConstants.circular15), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.image, + size: DimensionConstants.containerHeight60, + color: inactiveColor, ), - const SizedBox( - height: DimensionConstants.sizedBoxHeight5, - ), - Container( - width: MediaQuery.of(context).size.width, - height: 1, - color: bordercolor, - ), + const SizedBox(height: 5,), + customText("Tap to Select Image", kTextMedium, smallFontSize, FontWeight.w400) ], - ) - : SizedBox( - height: DimensionConstants.containerHeight40, - child: TextFormField( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - PersonSelectorScreen())).then((value) { - print("val -${value}"); - pickedname = value['name']; - pickednumber = value['number']; - if (pickedname != "") { - isPersonSelected = true; - } - setState(() {}); - }); - }, - readOnly: true, - maxLines: 1, - cursorColor: primaryColor, - decoration: customUnderlineInputdecoration( - hintText: 'Select', bordersideColor: primaryColor)), ), - const SizedBox(height: DimensionConstants.leftPadding15), - headertext("Receipt/ Screenshot"), - const SizedBox(height: DimensionConstants.sizedBoxHeight5), - Container( - width: MediaQuery.of(context).size.width, - height: DimensionConstants.containerHeight200, - decoration: BoxDecoration( - color: borderCustom, - borderRadius: - BorderRadius.circular(DimensionConstants.circular15), - ), - child: const Icon( - Icons.image, - size: DimensionConstants.containerHeight60, - color: inactiveColor, + ), ), - ), - const SizedBox(height: DimensionConstants.leftPadding15), - headertext("Tags"), - isTagSelected - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: DimensionConstants.sizedBoxHeight5, - ), - Container( - decoration: BoxDecoration( - color: Colors.pink[50], - border: Border.all(color: primaryColor), - borderRadius: BorderRadius.circular( - DimensionConstants.circular20)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: customText( - pickedname, primaryColor, 14, FontWeight.w500), + const SizedBox(height: DimensionConstants.leftPadding15), + headertext("Tags"), + tagList.isNotEmpty + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: DimensionConstants.sizedBoxHeight5, ), + GridView.builder( + padding: EdgeInsets.zero, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: + const NeverScrollableScrollPhysics(), + itemCount: tagList.length, + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 8, + mainAxisSpacing: 10, + mainAxisExtent: 50), + itemBuilder: (context, index) { + var item = tagList[index]; + return customSelecteData(text: item.name, ontap: (){ + setState(() { + tagList.removeAt(index); + }); + }); + }, + ), + + const SizedBox( + height: DimensionConstants.sizedBoxHeight5, + ), + Container( + width: MediaQuery.of(context).size.width, + height: 1, + color: bordercolor, + ), + ], + ) + : SizedBox( + height: DimensionConstants.containerHeight40, + child: TextFormField( + onTap: (){ + Navigator.push(context, MaterialPageRoute(builder: (context) => const TagsPage())).then((value) { + setState(() { + if(value != null){ + tagList = value.toList(); + } + }); + }); + }, + readOnly: true, + maxLines: 1, + cursorColor: primaryColor, + decoration: customUnderlineInputdecoration( + hintText: 'Select', + bordersideColor:primaryColor) ), - const SizedBox( - height: DimensionConstants.sizedBoxHeight5, - ), - Container( - width: MediaQuery.of(context).size.width, - height: 1, - color: bordercolor, - ), - ], - ) - : SizedBox( - height: DimensionConstants.containerHeight40, - child: TextFormField( - onTap: () {}, - readOnly: true, - maxLines: 1, - cursorColor: primaryColor, - decoration: customUnderlineInputdecoration( - hintText: 'Select', bordersideColor: primaryColor)), - ), + ), - //_fullMediaPreview(context), - ], + //_fullMediaPreview(context), + ], + ), ), ), bottomNavigationBar: BottomAppBar( @@ -206,6 +285,33 @@ class _ImportExpensePageState extends State { ); } + Widget customSelecteData ({required String text,required Function() ontap}){ + return Container( + decoration: BoxDecoration( + color: Colors.pink[50], + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.circular( + DimensionConstants.circular20)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + customText(text, primaryColor, 14, + FontWeight.w500), + InkWell( + onTap:ontap, + child: const Icon( + Icons.close, + color: primaryColor, + )) + ], + ), + ), + ); + } + Widget _fullMediaPreview(BuildContext context) => Expanded( child: PageView( controller: _pageController, diff --git a/lib/personselector_screen.dart b/lib/personselector_screen.dart deleted file mode 100644 index e19f5d8..0000000 --- a/lib/personselector_screen.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:fluttercontactpicker/fluttercontactpicker.dart'; - -import '../common_widgets.dart'; -import '../constants/dimens_constants.dart'; -import '../style.dart'; - -class PersonSelectorScreen extends StatefulWidget { - const PersonSelectorScreen({Key? key}) : super(key: key); - - @override - State createState() => _PersonSelectorScreenState(); -} - -class _PersonSelectorScreenState extends State { - PhoneContact? _phoneContact; - String pickedname = ""; - String pickednumber = ""; - TextEditingController namecon = TextEditingController(); - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: appBarTitleText('Select Person'), - actions: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () { - Navigator.pop( - context, {'name': pickedname, 'number': pickednumber}); - }, - child: headertext("Done")), - ) - ], - ), - body: Padding( - padding: const EdgeInsets.symmetric( - horizontal: DimensionConstants.leftPadding15, - vertical: DimensionConstants.topPadding10), - child: Column( - children: [ - TextFormField( - controller: namecon, - maxLines: 1, - cursorColor: primaryColor, - decoration: customUnderlineInputdecoration( - hintText: 'Enter Name or select from contact', - bordersideColor: primaryColor, - suffixicon: InkWell( - onTap: () async { - bool permission = - await FlutterContactPicker.requestPermission(); - if (permission) { - if (await FlutterContactPicker.hasPermission()) { - _phoneContact = - await FlutterContactPicker.pickPhoneContact(); - if (_phoneContact != null) { - if (_phoneContact!.fullName!.isNotEmpty) { - pickedname = - _phoneContact!.fullName.toString(); - namecon.text = - _phoneContact!.fullName.toString(); - setState(() {}); - } - - if (_phoneContact! - .phoneNumber!.number!.isNotEmpty) { - pickednumber = _phoneContact! - .phoneNumber!.number - .toString(); - setState(() {}); - } - } - } - } else {} - }, - child: const Icon( - Icons.contact_page, - color: primaryColor, - size: 35, - )))), - ], - ), - ), - ); - } -} diff --git a/lib/tags_screen.dart b/lib/tags_screen.dart index 1b647e2..45a99e8 100644 --- a/lib/tags_screen.dart +++ b/lib/tags_screen.dart @@ -107,10 +107,10 @@ class _TagsPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, appBar: AppBar( - leading: const BackButton(), + //leading: const BackButton(), title: appBarSearchInput(controller: _searchController), - actions: null, ), body: Container( margin: const EdgeInsets.all(5.0), @@ -135,7 +135,9 @@ class _TagsPageState extends State { _renderTagGroup(tags: _unselectedTagsFiltered), ]), ), - bottomNavigationBar: renderMainBottomButton('Done', null), + bottomNavigationBar: BottomAppBar(child: renderMainBottomButton('Done',(){ + Navigator.pop(context,_attachedTags); + })), ); } 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..14b5f7c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import file_selector_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) } diff --git a/pubspec.yaml b/pubspec.yaml index c8f6ff8..1f60aa7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,7 @@ dependencies: jiffy: ^5.0.0 receive_sharing_intent: ^1.4.5 fluttercontactpicker: ^4.7.0 + image_picker: ^1.0.5 dev_dependencies: flutter_test: 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