Skip to content

Instantly share code, notes, and snippets.

@OberdanBrito
Created December 30, 2022 22:28
Show Gist options
  • Save OberdanBrito/0c3f72563bd31a70da4b7fab6f1479a2 to your computer and use it in GitHub Desktop.
Save OberdanBrito/0c3f72563bd31a70da4b7fab6f1479a2 to your computer and use it in GitHub Desktop.
gerenciamento de contatos
// ignore_for_file: depend_on_referenced_packages
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:gestor_commons/data/data.dart';
import 'package:gestor_commons/images.dart';
import 'package:gestor_commons/theme.dart';
import 'package:intl/intl.dart';
import 'package:quicasa_contacts/data/schedule.dart';
import 'package:quicasa_contacts/types.dart';
import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'contact_view.dart';
import 'data/contacts.dart';
import 'data/groups.dart';
import 'data/groups_itens.dart';
import 'data/profile_type.dart';
import 'groups_list.dart';
import 'sync.dart';
class MultipleData {
List<ApContact> contacts;
List<Groups> groups;
MultipleData({required this.contacts, required this.groups});
}
class ContactsListPage extends StatefulWidget {
final Map<String, dynamic> client;
final AppTheme theme;
const ContactsListPage({super.key, required this.client, required this.theme});
@override
ContactsListState createState() => ContactsListState();
}
class ContactsListState extends State<ContactsListPage> {
final db = DataBaseHelper.db;
late AppWidgets global = AppWidgets(theme: widget.theme);
late final Widget _defaulttitle = global.titlePage(leftText: 'Meus ', centerText: 'Contatos');
late Widget _title = _defaulttitle;
late Widget _list = _awaitLoadStart();
late Icon _searchicon = const Icon(Icons.search);
late MultipleData multipleData;
TextEditingController searchController = TextEditingController();
final TextEditingController _displaynameController = TextEditingController();
late ContactProfileType doctypevalue = Types.list.first;
List<ApContact> originalList = <ApContact>[];
List<String> listdocumentstype =
Types.list.where((element) => element.onUnit == true).map<String>((ContactProfileType value) {
return value.text;
}).toList();
void _setSearchResult() {
setState(() {
_list = _makeListContent();
});
}
void _search(String query) {
List<ApContact> dummySearchList = <ApContact>[];
dummySearchList.addAll(multipleData.contacts);
if (query.isNotEmpty) {
List<ApContact> dummyListData = multipleData.contacts
.where((element) => element.displayname.toLowerCase().contains(query.toLowerCase()))
.toList();
multipleData = MultipleData(contacts: dummyListData, groups: multipleData.groups);
_setSearchResult();
return;
} else {
_setSearchResult();
}
}
void _showAddContactDialog() {
late String dropdownValue = listdocumentstype.first;
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Adicionar contato'),
content: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: _displaynameController,
decoration: const InputDecoration(labelText: 'Nome'),
),
ListTile(
dense: true,
title: const Text(
'Tipo de cadastro',
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
),
subtitle: DropdownButtonFormField<String>(
isExpanded: true,
hint: const Text(
'Selecione...',
style: TextStyle(color: Colors.grey, fontSize: 15),
),
value: dropdownValue,
onChanged: (String? value) {
setState(() {
dropdownValue = value!;
doctypevalue = Types.list.where((element) => element.text == value).first;
});
},
onSaved: (value) {
setState(() {
dropdownValue = value!;
doctypevalue = Types.itens.where((element) => element.text == value).first;
});
},
items: listdocumentstype.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
TextButton(
child: const Text('Cancelar',
style:
TextStyle(fontWeight: FontWeight.bold, color: Colors.deepOrange)),
onPressed: () {
Navigator.of(context).pop();
}),
TextButton(
child: const Text('Confirmar',
style:
TextStyle(fontWeight: FontWeight.bold, color: Colors.deepPurple)),
onPressed: () async {
Uuid uuid = const Uuid(options: {'grng': UuidUtil.cryptoRNG});
var result = await db.insert(
'contacts',
ApContact(
id: uuid.v4(),
displayname: _displaynameController.text,
peopletype: doctypevalue.id,
registrationdate: DateTime.now().toString())
.toTable());
if (kDebugMode) {
print(result);
}
setState(() {
Navigator.of(context).pop();
_list = _prepareList(_getContacts());
});
}),
],
)
],
),
),
);
},
);
}
void _onContactLongPress(int index) {
setState(() {
multipleData.contacts[index].checked = !multipleData.contacts[index].checked;
_list = _makeListContent();
});
}
Widget _listMenu() {
return PopupMenuButton(itemBuilder: (context) {
return [
PopupMenuItem<String>(
value: 'contactgroups',
child: global.iconText(
'Convidar pessoas', const Icon(FontAwesomeIcons.peopleGroup), Colors.black54)),
];
}, onSelected: (value) async {
if (value == 'contactgroups') {
List<Map<String, dynamic>> contactrows = await db.queryAllRows('contacts');
List<ApContact> contacts = [];
Future.forEach(contactrows, (contact) => {contacts.add(ApContact.fromMap(contact))});
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => ContactsGroupsPage(
onSetGroup: () {},
contacts: contacts,
client: widget.client,
theme: widget.theme,
)));
}
});
}
Widget _searchBar() {
return ListTile(
title: TextField(
onChanged: (value) {
_search(value);
},
controller: searchController,
decoration: const InputDecoration(hintText: 'pesquisar...'),
),
);
}
Widget _toggleBar() {
return Padding(
padding: const EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {
setState(() {
if (_searchicon.icon == Icons.search) {
_searchicon = const Icon(Icons.cancel);
_title = _searchBar();
originalList = multipleData.contacts;
_list = _makeListContent();
} else {
_searchicon = const Icon(Icons.search);
_title = _defaulttitle;
multipleData.contacts = originalList;
_list = _makeListContent();
}
});
},
child: _searchicon,
));
}
Widget _showPhoto(contact) {
Widget contactphoto = Icon(FontAwesomeIcons.user, size: 24, color: widget.theme.grey);
if (contact.photo != "") {
contactphoto = Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
image: MemoryImage(Images.dataFromBase64String(contact.photo)),
fit: BoxFit.cover,
),
));
}
return Stack(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.grey[300],
child: Center(
child: contactphoto,
),
),
(contact.checked == true)
? _checkedItem()
: _checkClear()
],
);
}
Widget _showName(String name, Color color) {
return Row(
children: <Widget>[
Expanded(
child: Text(name,
style: TextStyle(color: color),
softWrap: false,
maxLines: 1,
overflow: TextOverflow.ellipsis))
],
);
}
Widget _showType(contactType) {
ContactProfileType peopleType = Types.list.where((element) => element.id == contactType).first;
return global.iconText(peopleType.text, Icon(peopleType.icon), peopleType.color);
}
Widget _showAccess(String? date) {
String nextaccess = '';
if (date != null && date != "") {
nextaccess = DateFormat.yMd().format(DateTime.parse(date).toLocal());
}
return Text(nextaccess);
}
Widget _checkedItem() {
return const Positioned(
right: 0,
child: Icon(Icons.check_circle, color: Colors.green, size: 20)
);
}
Widget _checkClear() {
return const SizedBox.shrink();
}
Widget _listContacts(List<ApContact> list) {
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
ApContact contact = list[index];
Color? background = Colors.white;
Color color = Colors.black54;
if (contact.blocked == 'true') {
background = Colors.red[50];
color = Colors.red;
}
return InkWell(
onLongPress: () => _onContactLongPress(index),
onTap: () => _onContactSelect(context, contact, index),
child: ListTile(
tileColor: background,
leading: _showPhoto(contact),
title: _showName(contact.displayname, color),
subtitle: _showType(contact.peopletype),
trailing: _showAccess(contact.scheduleto),
),
);
},
childCount: list.length,
),
);
}
Widget _listGroups(List<Groups> list) {
return Container(
padding: const EdgeInsets.only(top: 80),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: list.length,
itemBuilder: (context, index) {
Groups group = list[index];
return Container(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width * 0.3,
),
child: Card(
color: Colors.white,
elevation: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {},
child: global.columnButtonIcon(
Icon(FontAwesomeIcons.users, color: widget.theme.grey), group.name))
]),
),
);
}),
);
}
Widget _makeListContent() {
return Container(
color: Colors.white,
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
snap: false,
floating: true,
expandedHeight: multipleData.groups.isNotEmpty ? 150.0 : 0,
backgroundColor: Colors.white,
title: _title,
actions: <Widget>[_toggleBar(), _listMenu()],
leading: global.backButton(context),
flexibleSpace: FlexibleSpaceBar(
background: _listGroups(multipleData.groups),
),
),
_listContacts(multipleData.contacts)
],
),
);
}
Widget _makeListEmpty() {
return Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Padding(
padding: const EdgeInsets.all(10),
child: Icon(FontAwesomeIcons.heart, size: 32, color: widget.theme.secundary),
),
const Text(
'Sua lista de contatos\nestá vazia!',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 24),
textAlign: TextAlign.center,
),
const Padding(
padding: EdgeInsets.only(top: 20, left: 30, right: 30),
child: Text(
'Para o seu conforto, você pode sincronizar os contatos do seu celular aqui mesmo!',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: TextButton.icon(
onPressed: () {
setState(() {
_list = _prepareList(_getDeviceList());
});
},
icon: const Icon(Icons.sync),
label: const Text(
"Sincronizar meus contatos",
style: TextStyle(fontSize: 15),
)))
]),
);
}
Widget _awaitLoadStart() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Aguarde enquanto\nbuscamos os seus contatos',
textAlign: TextAlign.center,
),
SizedBox(
width: 100,
height: 100,
child: Stack(
alignment: Alignment.center,
children: [
Icon(FontAwesomeIcons.heart, size: 32, color: widget.theme.secundary),
SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(widget.theme.primary),
strokeWidth: 5,
),
)
],
),
)
],
),
);
}
Widget _prepareList(Future<MultipleData>? future) {
return FutureBuilder<MultipleData>(
future: future,
builder: (BuildContext context, AsyncSnapshot<MultipleData> snapshot) {
if (snapshot.hasData) {
multipleData = snapshot.data!;
return _makeListContent();
} else {
return _awaitLoadStart();
}
},
);
}
Widget _optionAdd() {
return FloatingActionButton(
onPressed: () => _showAddContactDialog(),
child: const Icon(Icons.add),
);
}
Future _onContactSelect(context, contact, index) async {
var schendule = await db.queryRow('schedule', 'contact', contact.id);
if (schendule.isNotEmpty) {
contact.schedule = Schedule.fromMap(schendule);
}
Navigator.of(context)
.push(MaterialPageRoute(
builder: (_) => ContactPage(
contact: contact,
client: widget.client,
theme: widget.theme,
)
)
).then((val) => _checkLocalData());
}
Future<MultipleData> _getDeviceList() async {
await db.create('contacts', ApContact.model);
await db.create('schedule', Schedule.model);
await db.create('groups', Groups.model);
await db.create('groupsitens', GroupsItens.model);
List<ApContact> contacts = [];
List<Map<String, dynamic>> devicecontacts = await DeviceContacts.fetchContacts();
await Future.forEach(devicecontacts, (row) async {
await db.insert('contacts', row);
contacts.add(ApContact.fromMap(row));
});
return MultipleData(contacts: contacts, groups: []);
}
Future<MultipleData> _getContacts() async {
List<ApContact> contacts = [];
List<Groups> groups = [];
List<Map<String, dynamic>> contactrows = await db.query(
'SELECT id, displayname, peopletype, registrationdate, scheduleto, photo FROM contacts ORDER BY displayname;');
Future.forEach(contactrows, (row) => {contacts.add(ApContact.fromMap(row))});
List<Map<String, dynamic>> grouprows = await db.queryAllRows('groups');
Future.forEach(grouprows, (rows) => {groups.add(Groups.fromMap(rows))});
return MultipleData(contacts: contacts, groups: groups);
}
Future _checkLocalData() async {
bool exists = await db.tableExist('contacts');
if (exists == false) {
setState(() {
_list = _makeListEmpty();
});
} else {
setState(() {
_list = _prepareList(_getContacts());
});
}
}
@override
void initState() {
super.initState();
_checkLocalData();
}
@override
Widget build(BuildContext context) {
return Scaffold(floatingActionButton: _optionAdd(), body: _list);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment