diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 0ff20a05..d773213b 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -127,7 +127,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -176,6 +176,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a3..a6b826db 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ runApp(const MyApp()); class MyApp extends StatefulWidget { - const MyApp({Key key}) : super(key: key); + const MyApp({Key? key}) : super(key: key); @override MyAppState createState() => MyAppState(); @@ -93,6 +93,7 @@ class MyAppState extends State { GlobalWidgetsLocalizations.delegate, ], home: Scaffold( + backgroundColor: Colors.red, appBar: AppBar( title: const Text('CountryPicker Example'), ), @@ -101,66 +102,52 @@ class MyAppState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ CountryCodePicker( - onChanged: print, - // Initial selection and favorite can be one of code ('IT') OR dial_code('+39') - initialSelection: 'IT', - favorite: const ['+39', 'FR'], - countryFilter: const ['IT', 'FR'], - showFlagDialog: false, - comparator: (a, b) => b.name.compareTo(a.name), - //Get the country information relevant to the initial selection - onInit: (code) => debugPrint( - "on init ${code.name} ${code.dialCode} ${code.name}"), - ), - CountryCodePicker( - onChanged: print, - // Initial selection and favorite can be one of code ('IT') OR dial_code('+39') - initialSelection: 'IT', - favorite: const ['+39', 'FR'], - countryFilter: const ['IT', 'FR'], - // flag can be styled with BoxDecoration's `borderRadius` and `shape` fields - flagDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(7), - ), - ), - const SizedBox( - width: 400, - height: 60, - child: CountryCodePicker( - onChanged: print, - hideMainText: true, - showFlagMain: true, - showFlag: false, - initialSelection: 'TF', - hideSearch: true, - showCountryOnly: true, - showOnlyCountryWhenClosed: true, - alignLeft: true, - ), - ), - SizedBox( - width: 400, - height: 60, - child: CountryCodePicker( - onChanged: (element) => debugPrint(element.toLongString()), - initialSelection: 'TF', - showCountryOnly: true, - showOnlyCountryWhenClosed: true, - favorite: const ['+39', 'FR'], - ), - ), - SizedBox( - width: 100, - height: 60, - child: CountryCodePicker( - enabled: false, - onChanged: (c) => c.name, - initialSelection: 'TF', - showCountryOnly: true, - showOnlyCountryWhenClosed: true, - favorite: const ['+39', 'FR'], - ), + + showCodeOnly: false, + withoutBottomSheetheight: 0.80 , + + boxDecoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(18), + border: Border.all( + color: Colors.red, + + // Border color + width: 2.0, // Border width + ), ), + showBottomSheetheight: 0.80, + txtFieldHintTxt: "البحث", + clickableFilepicker:true, + hideLineAbovFiled:false , + textDirection: TextDirection.rtl, + + flagDecoration:BoxDecoration( + + + color: Colors.white.withOpacity(0.7), + shape: BoxShape.circle, // Make the container circular + border: Border.all(color: Colors.grey)), + + textStyle:TextStyle(color: Colors.black , fontWeight: FontWeight.bold , fontSize: 13), + + + /*flagDecoration:BoxDecoration( + + color: Colors.white.withOpacity(0.7), + shape: BoxShape.circle, // Make the container circular + border: Border.all(color: Colors.grey), + + ),*/ + onChanged: (value) { + // Handle country code change + print(value); + }, + // Initial selection and favorite country + initialSelection: 'SA', + // Add Saudi Arabia to the favorites + favorite: ['+966', 'SA'], ), + ], ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1f4d287e..ae30eab7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ version: 1.0.0+1 publish_to: none environment: - sdk: ">=2.0.0-dev.68.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: diff --git a/ios/Flutter/Generated.xcconfig b/ios/Flutter/Generated.xcconfig index 015ea0e5..053db87f 100644 --- a/ios/Flutter/Generated.xcconfig +++ b/ios/Flutter/Generated.xcconfig @@ -1,6 +1,6 @@ // This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=/Users/bezzo/flutter -FLUTTER_APPLICATION_PATH=/Users/bezzo/Desktop/CountryCodePicker +FLUTTER_ROOT=/Users/kareem/Developer/flutter +FLUTTER_APPLICATION_PATH=/Users/kareem/Documents/KareemMacFolders/Flutter_Active_Projects/CountryCodePicker COCOAPODS_PARALLEL_CODE_SIGN=true FLUTTER_TARGET=lib/main.dart FLUTTER_BUILD_DIR=build diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index 06333d0c..da94cffb 100755 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -1,7 +1,7 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/Users/bezzo/flutter" -export "FLUTTER_APPLICATION_PATH=/Users/bezzo/Desktop/CountryCodePicker" +export "FLUTTER_ROOT=/Users/kareem/Developer/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/kareem/Documents/KareemMacFolders/Flutter_Active_Projects/CountryCodePicker" export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_BUILD_DIR=build" diff --git a/lib/country_code_picker.dart b/lib/country_code_picker.dart index d962ff02..3f196442 100644 --- a/lib/country_code_picker.dart +++ b/lib/country_code_picker.dart @@ -1,5 +1,6 @@ library country_code_picker; + import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; @@ -19,7 +20,7 @@ class CountryCodePicker extends StatefulWidget { final List favorite; final TextStyle? textStyle; final EdgeInsetsGeometry padding; - final bool showCountryOnly; + final bool showCodeOnly; final InputDecoration searchDecoration; final TextStyle? searchStyle; final TextStyle? dialogTextStyle; @@ -76,7 +77,7 @@ class CountryCodePicker extends StatefulWidget { final bool hideSearch; /// Set to true if you want to hide the close icon dialog - final bool hideCloseIcon; + final bool hideLineAbovFiled; /// Set to true if you want to show drop down button final bool showDropDownButton; @@ -91,15 +92,35 @@ class CountryCodePicker extends StatefulWidget { final EdgeInsetsGeometry dialogItemPadding; final EdgeInsetsGeometry searchPadding; + String txtFieldHintTxt; + bool clickableFilepicker; + double showBottomSheetheight; + double withoutBottomSheetheight; + TextDirection textDirection; + Color txtFieldColor; + Color containerBorderColor; + + + + + CountryCodePicker({ + this.containerBorderColor=Colors.red, + + this.txtFieldColor=Colors.red, - const CountryCodePicker({ + this.textDirection=TextDirection.rtl, + this.clickableFilepicker=true, + this.showBottomSheetheight= 0.75, + this.withoutBottomSheetheight=0.70, + + this.txtFieldHintTxt="search", this.onChanged, this.onInit, this.initialSelection, this.favorite = const [], this.textStyle, this.padding = const EdgeInsets.all(8.0), - this.showCountryOnly = false, + this.showCodeOnly = false, this.searchDecoration = const InputDecoration(), this.searchStyle, this.dialogTextStyle, @@ -121,7 +142,7 @@ class CountryCodePicker extends StatefulWidget { this.comparator, this.countryFilter, this.hideSearch = false, - this.hideCloseIcon = false, + this.hideLineAbovFiled = false, this.showDropDownButton = false, this.dialogSize, this.dialogBackgroundColor, @@ -175,7 +196,100 @@ class CountryCodePickerState extends State { child: widget.builder!(selectedItem), ); } else { - internalWidget = TextButton( + internalWidget = + + widget.clickableFilepicker? + TextButton( + onPressed: widget.enabled ? showCountryCodePickerDialog : null, + child: Padding( + padding: widget.padding, + child: Flex( + direction: Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showFlagMain != null + ? widget.showFlagMain! + : widget.showFlag) + Flexible( + flex: widget.alignLeft ? 0 : 1, + fit: widget.alignLeft ? FlexFit.tight : FlexFit.loose, + child: Container( + clipBehavior: widget.flagDecoration == null + ? Clip.none + : Clip.hardEdge, + decoration: widget.flagDecoration, + margin: widget.alignLeft + ? const EdgeInsets.only(right: 16.0, left: 8.0) + : const EdgeInsets.only(right: 0.0), + child: Image.asset( + selectedItem!.flagUri!, + package: 'country_code_picker', + width: widget.flagWidth, + ), + ), + ), + if (!widget.hideMainText) + Flexible( + fit: widget.alignLeft ? FlexFit.tight : FlexFit.loose, + child: Text( + widget.showOnlyCountryWhenClosed + ? selectedItem!.toCountryStringOnly() + : selectedItem.toString(), + style: widget.textStyle ?? + Theme.of(context).textTheme.labelLarge, + overflow: widget.textOverflow, + ), + ), + if (widget.showDropDownButton) + Flexible( + flex: widget.alignLeft ? 0 : 1, + fit: widget.alignLeft ? FlexFit.tight : FlexFit.loose, + child: Padding( + padding: widget.alignLeft + ? const EdgeInsets.only(right: 16.0, left: 8.0) + : const EdgeInsets.only(right: 16.0), + child: Icon( + Icons.arrow_drop_down, + color: Colors.grey, + size: widget.flagWidth, + )), + ), + ], + ), + ), + ) : + SelectionDialog( + widget.containerBorderColor, + widget.txtFieldColor, + widget.clickableFilepicker, + widget.textDirection, + + widget.withoutBottomSheetheight, + + widget.txtFieldHintTxt, + elements, + favoriteElements, + showCodeOnly: widget.showCodeOnly, + emptySearchBuilder: widget.emptySearchBuilder, + searchDecoration: widget.searchDecoration, + searchStyle: widget.searchStyle, + textStyle: widget.dialogTextStyle, + boxDecoration: widget.boxDecoration, + showFlag: widget.showFlagDialog ?? widget.showFlag, + flagWidth: widget.flagWidth, + size: widget.dialogSize, + backgroundColor: widget.dialogBackgroundColor, + barrierColor: widget.barrierColor, + hideSearch: widget.hideSearch, + hideLineAbovFiled: widget.hideLineAbovFiled, + closeIcon: widget.closeIcon, + flagDecoration: widget.flagDecoration, + dialogItemPadding: widget.dialogItemPadding, + searchPadding: widget.searchPadding, + ); + + + /*TextButton( onPressed: widget.enabled ? showCountryCodePickerDialog : null, child: Padding( padding: widget.padding, @@ -233,7 +347,7 @@ class CountryCodePickerState extends State { ], ), ), - ); + );*/ } return internalWidget; } @@ -295,36 +409,71 @@ class CountryCodePickerState extends State { } void showCountryCodePickerDialog() async { - final item = await showDialog( - barrierColor: widget.barrierColor ?? Colors.grey.withOpacity(0.5), + final item = await + + + showModalBottomSheet( context: context, - builder: (context) => Center( - child: Dialog( - child: SelectionDialog( - elements, - favoriteElements, - showCountryOnly: widget.showCountryOnly, - emptySearchBuilder: widget.emptySearchBuilder, - searchDecoration: widget.searchDecoration, - searchStyle: widget.searchStyle, - textStyle: widget.dialogTextStyle, - boxDecoration: widget.boxDecoration, - showFlag: widget.showFlagDialog ?? widget.showFlag, - flagWidth: widget.flagWidth, - size: widget.dialogSize, - backgroundColor: widget.dialogBackgroundColor, - barrierColor: widget.barrierColor, - hideSearch: widget.hideSearch, - hideCloseIcon: widget.hideCloseIcon, - closeIcon: widget.closeIcon, - flagDecoration: widget.flagDecoration, - dialogItemPadding: widget.dialogItemPadding, - searchPadding: widget.searchPadding, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Container( + height: MediaQuery.of(context).size.height * widget.showBottomSheetheight, + decoration: new BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: new BorderRadius.only( + topLeft: const Radius.circular(25.0), + topRight: const Radius.circular(25.0), + ), + ), + child: Center( + child: Column( + children: [ + + Expanded( + child: SelectionDialog( + widget.containerBorderColor, + + widget.txtFieldColor, + widget.clickableFilepicker, + + widget.textDirection, + widget.withoutBottomSheetheight, + + widget.txtFieldHintTxt, + elements, + favoriteElements, + showCodeOnly: widget.showCodeOnly, + emptySearchBuilder: widget.emptySearchBuilder, + searchDecoration: widget.searchDecoration, + searchStyle: widget.searchStyle, + textStyle: widget.dialogTextStyle, + boxDecoration: widget.boxDecoration, + showFlag: widget.showFlagDialog ?? widget.showFlag, + flagWidth: widget.flagWidth, + size: widget.dialogSize, + backgroundColor: widget.dialogBackgroundColor, + barrierColor: widget.barrierColor, + hideSearch: widget.hideSearch, + hideLineAbovFiled: widget.hideLineAbovFiled, + closeIcon: widget.closeIcon, + // flagDecoration: widget.flagDecoration, + dialogItemPadding: widget.dialogItemPadding, + searchPadding: widget.searchPadding, + ), + ), + ], ), ), ), ); + + + + + + + if (item != null) { setState(() { selectedItem = item; diff --git a/lib/src/country_code.dart b/lib/src/country_code.dart index b8a38634..67959ed8 100644 --- a/lib/src/country_code.dart +++ b/lib/src/country_code.dart @@ -64,6 +64,8 @@ class CountryCode { String toString() => "$dialCode"; String toLongString() => "$dialCode ${toCountryStringOnly()}"; + String codeOnlyString() => "$dialCode"; + String toCountryStringOnly() { return '$_cleanName'; diff --git a/lib/src/selection_dialog.dart b/lib/src/selection_dialog.dart index 6f932fee..ae3150ad 100644 --- a/lib/src/selection_dialog.dart +++ b/lib/src/selection_dialog.dart @@ -6,7 +6,7 @@ import 'country_localizations.dart'; /// selection dialog used for selection of the country code class SelectionDialog extends StatefulWidget { final List elements; - final bool? showCountryOnly; + final bool? showCodeOnly; final InputDecoration searchDecoration; final TextStyle? searchStyle; final TextStyle? textStyle; @@ -17,7 +17,7 @@ class SelectionDialog extends StatefulWidget { final Decoration? flagDecoration; final Size? size; final bool hideSearch; - final bool hideCloseIcon; + final bool hideLineAbovFiled; final Icon? closeIcon; /// Background color of SelectionDialog @@ -32,12 +32,24 @@ class SelectionDialog extends StatefulWidget { final EdgeInsetsGeometry dialogItemPadding; final EdgeInsetsGeometry searchPadding; + String? txtFieldHintTxt="search"; + double height =0.70; + TextDirection textDirection; + bool clickableFilepicker; + Color txtFieldBorderColor; + Color containerBorderColor; SelectionDialog( + this.containerBorderColor, + this.txtFieldBorderColor, + this.clickableFilepicker, + this.textDirection, + this.height, + this.txtFieldHintTxt, this.elements, this.favoriteElements, { Key? key, - this.showCountryOnly, + this.showCodeOnly, this.emptySearchBuilder, InputDecoration searchDecoration = const InputDecoration(), this.searchStyle, @@ -50,7 +62,7 @@ class SelectionDialog extends StatefulWidget { this.backgroundColor, this.barrierColor, this.hideSearch = false, - this.hideCloseIcon = false, + this.hideLineAbovFiled = false, this.closeIcon, this.dialogItemPadding = const EdgeInsets.symmetric(horizontal: 24, vertical: 8), this.searchPadding = const EdgeInsets.symmetric(horizontal: 24), @@ -69,84 +81,154 @@ class _SelectionDialogState extends State { @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.all(0.0), + padding: const EdgeInsets.all(5.0), child: Container( clipBehavior: Clip.hardEdge, width: widget.size?.width ?? MediaQuery.of(context).size.width, - height: - widget.size?.height ?? MediaQuery.of(context).size.height * 0.85, + height: widget.size?.height ?? MediaQuery.of(context).size.height * widget.height, decoration: widget.boxDecoration ?? BoxDecoration( color: widget.backgroundColor ?? Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - boxShadow: [ - BoxShadow( - color: widget.barrierColor ?? Colors.grey.withOpacity(1), - spreadRadius: 5, - blurRadius: 7, - offset: const Offset(0, 3), // changes position of shadow + borderRadius: const BorderRadius.all(Radius.circular(20.0)), + border: Border.all( + color: widget.containerBorderColor, + width: 1, ), + boxShadow: [ ], ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (!widget.hideCloseIcon) - IconButton( + // if (!widget.hideCloseIcon) + /* IconButton( padding: const EdgeInsets.all(0), iconSize: 20, icon: widget.closeIcon!, onPressed: () => Navigator.pop(context), - ), + ),*/ + + SizedBox(height:10,) , + + widget.hideLineAbovFiled? + SizedBox(): + Center( + child: Padding( + padding: const EdgeInsets.all(3.0), + child: Container( + decoration: BoxDecoration( + color: Colors.black, // Set line color + borderRadius: BorderRadius.all( + Radius.circular(20) + + ), + ), + height: 4.0, // Set line thickness + width: 100.0, // Set line length + ), + ), + ), + + + SizedBox(height:25,) , if (!widget.hideSearch) Padding( padding: widget.searchPadding, - child: TextField( - style: widget.searchStyle, - decoration: widget.searchDecoration, - onChanged: _filterElements, + child: Directionality( + textDirection: widget.textDirection, + + child: TextField( + + + + decoration: InputDecoration( + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide( + color: widget.txtFieldBorderColor,// Change the border color as needed + width: 2.0, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide( + color: widget.txtFieldBorderColor, // Change the border color as needed + width: 1.0, + ), + ), + + + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide( + color: widget.txtFieldBorderColor, // Change the border color as needed + width: 1.0, // Adjust the border width + ), + ), + hintText: widget.txtFieldHintTxt, + suffixIcon: Icon(Icons.search , color: Colors.grey ,), + ), + style: widget.searchStyle, + //decoration: widget.searchDecoration, + onChanged: _filterElements, + ), ), ), - Expanded( - child: ListView( - children: [ - widget.favoriteElements.isEmpty - ? const DecoratedBox(decoration: BoxDecoration()) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...widget.favoriteElements.map( - (f) => InkWell( - onTap: () { - _selectItem(f); - }, - child: Padding( - padding: widget.dialogItemPadding, - child: _buildOption(f), - ) - ) + SizedBox(height:10,) , + + Directionality( + textDirection: TextDirection.ltr, + + child: Expanded( + child: Padding( + padding: const EdgeInsets.all(0.0), + child: ListView( + children: [ + widget.favoriteElements.isEmpty + ? const DecoratedBox(decoration: BoxDecoration()) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...widget.favoriteElements.map( + (f) => InkWell( + onTap: () { + widget.clickableFilepicker? + _selectItem(f) : + debugPrint(""); + }, + child: Padding( + padding: widget.dialogItemPadding, + child: _buildOption(f), + ) + ) + ), + Divider(color: Theme.of(context).colorScheme.surface,thickness: 0.2,), + ], ), - const Divider(), - ], + if (filteredElements.isEmpty) + _buildEmptySearchWidget(context) + else + ...filteredElements.map( + (e) => InkWell( + onTap: () { + widget.clickableFilepicker? + _selectItem(e) : + debugPrint(""); + }, + child: Padding( + padding: widget.dialogItemPadding, + child: _buildOption(e), + ) + ) ), - if (filteredElements.isEmpty) - _buildEmptySearchWidget(context) - else - ...filteredElements.map( - (e) => InkWell( - onTap: () { - _selectItem(e); - }, - child: Padding( - padding: widget.dialogItemPadding, - child: _buildOption(e), - ) - ) - ), - ], + ], + ), + ), ), ), + ], ), ), @@ -162,24 +244,35 @@ class _SelectionDialogState extends State { Flexible( child: Container( margin: const EdgeInsets.only(right: 16.0), - decoration: widget.flagDecoration, - clipBehavior: - widget.flagDecoration == null ? Clip.none : Clip.hardEdge, - child: Image.asset( - e.flagUri!, - package: 'country_code_picker', - width: widget.flagWidth, + // decoration: widget.flagDecoration, + /*clipBehavior: + widget.flagDecoration == null ? Clip.none : Clip.hardEdge,*/ + child: ClipRRect( + borderRadius: BorderRadius.circular(5.0), // Set the circular border radius + + child: Image.asset( + e.flagUri!, + package: 'country_code_picker', + width: 40, + + //widget.flagWidth, + fit: BoxFit.cover, // Adjust the BoxFit as needed + + ), ), ), ), + + + Expanded( flex: 4, child: Text( - widget.showCountryOnly! - ? e.toCountryStringOnly() + widget.showCodeOnly! + ? e.codeOnlyString() : e.toLongString(), overflow: TextOverflow.fade, - style: widget.textStyle, + style: TextStyle(fontWeight: FontWeight.w700), ), ), ],