Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions example/lib/CustomSelectionDialog/custom_selection_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import 'package:country_code_picker/country_code_picker.dart';
import 'package:flutter/material.dart';

class CustomSelectionDialog extends StatefulWidget {
/// The full list of country codes from the parent SelectionDialog.
final List<CountryCode> elements;

/// Optional favorite country codes.
final List<CountryCode>? favoriteElements;

/// Header text (if any) to show at the top.
final String? headerText;

/// Callback when a country code is selected.
final ValueChanged<CountryCode>? onSelected;

final bool hideCountryTitle;

const CustomSelectionDialog({
Key? key,
required this.elements,
this.favoriteElements,
this.headerText,
this.onSelected,
this.hideCountryTitle = false,
}) : super(key: key);

@override
_CustomSelectionDialogState createState() => _CustomSelectionDialogState();
}

class _CustomSelectionDialogState extends State<CustomSelectionDialog> {
late List<CountryCode> filteredElements;
final TextEditingController searchController = TextEditingController();

@override
void initState() {
super.initState();
filteredElements = widget.elements;
}

void _filterElements(String query) {
setState(() {
final lowerQuery = query.toLowerCase();
filteredElements = widget.elements.where((code) {
return (code.name?.toLowerCase().contains(lowerQuery) ?? false) ||
(code.dialCode?.contains(query) ?? false) ||
(code.code?.toLowerCase().contains(lowerQuery) ?? false);
}).toList();
});
}

Widget _buildOption(CountryCode code) {
return ListTile(
leading: code.flagUri != null
? ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.asset(
code.flagUri!,
package: 'country_code_picker',
width: 32,
height: 24,
fit: BoxFit.cover,
),
)
: null,
title: Text(
widget.hideCountryTitle
? code.dialCode!
: "${code.name} (${code.dialCode})",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black),
),
onTap: () {
widget.onSelected?.call(code);
Navigator.pop(context, code);
},
);
}

@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * 0.75,
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
// Header with title and close button.
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (widget.headerText != null)
Text(
widget.headerText!,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
IconButton(
icon: Icon(Icons.close,
color: Colors.black),
onPressed: () => Navigator.pop(context),
),
],
),
const SizedBox(height: 8),
// Modern search field.
TextField(
style: TextStyle(
color: Colors.black),
controller: searchController,
decoration: InputDecoration(
hintText: 'Search country',
hintStyle: TextStyle(
color: Colors.black),
prefixIcon: Icon(Icons.search,
color: Colors.black),
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.symmetric(vertical: 0, horizontal: 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide.none,
),
),
onChanged: _filterElements,
),
const SizedBox(height: 16),
// Optional favorites.
if (widget.favoriteElements != null &&
widget.favoriteElements!.isNotEmpty)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...widget.favoriteElements!.map((code) => _buildOption(code)),
const Divider(),
],
),
// List of filtered country codes.
Expanded(
child: filteredElements.isEmpty
? Center(
child: Text(
'No country found',
style: TextStyle(color: Colors.grey.shade600),
),
)
: ListView.builder(
itemCount: filteredElements.length,
itemBuilder: (context, index) {
return _buildOption(filteredElements[index]);
},
),
),
],
),
);
}
}
26 changes: 26 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:country_code_picker/country_code_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:hello_example/CustomSelectionDialog/custom_selection_dialog.dart';

void main() => runApp(const MyApp());

Expand Down Expand Up @@ -162,10 +163,35 @@ class MyAppState extends State<MyApp> {
favorite: const ['+39', 'FR'],
),
),
// With Custom Dialog
CountryCodePicker(
onChanged: print,
// Initial selection and favorite can be one of code ('IT') OR dial_code('+39')
initialSelection: 'IT',
//You can set the margin between the flag and the country name to your taste.
margin: const EdgeInsets.symmetric(horizontal: 6),
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}"),
dialogBuilder: customDialogBuilder,
),
],
),
),
),
);
}

Widget customDialogBuilder(BuildContext context,
List<CountryCode> filteredElements, SelectionDialog dialog) {
return CustomSelectionDialog(
elements: dialog.elements,
headerText: dialog.headerText,
onSelected: (code) {
// This callback is optional because the SelectionDialog
// itself handles returning the selected code.
// You can update any state here if needed.
},
);
}
}
5 changes: 5 additions & 0 deletions lib/country_code_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ class CountryCodePicker extends StatefulWidget {
///Header Text Alignment
final MainAxisAlignment headerAlignment;

///Custom dialog builder
final SelectionDialogBuilder? dialogBuilder;

const CountryCodePicker({
this.onChanged,
this.onInit,
Expand Down Expand Up @@ -159,6 +162,7 @@ class CountryCodePicker extends StatefulWidget {
this.headerTextStyle = const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
this.hideHeaderText = false,
this.topBarPadding = const EdgeInsets.symmetric(vertical: 5.0, horizontal: 20),
this.dialogBuilder,
Key? key,
}) : super(key: key);

Expand Down Expand Up @@ -348,6 +352,7 @@ class CountryCodePickerState extends State<CountryCodePicker> {
flagDecoration: widget.flagDecoration,
dialogItemPadding: widget.dialogItemPadding,
searchPadding: widget.searchPadding,
dialogBuilder: widget.dialogBuilder,
),
),
),
Expand Down
Loading