Files
prosappco/lib/screens/lists/professional_list_screen.dart
T

380 lines
13 KiB
Dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injector/injector.dart';
import 'package:intl_phone_field/helpers.dart';
import 'package:profession_repository/profession_repository.dart';
import 'package:professional_repository/professional_repository.dart';
import 'package:prosappco/blocs/professional_list_bloc/professional_list_bloc.dart';
import 'package:prosappco/screens/lists/city_list_screen.dart';
import 'package:prosappco/screens/user/user_calendar_screen.dart';
import 'package:prosappco/screens/user/user_view_profile_screen.dart';
import 'package:setting_repository/setting_repository.dart';
import 'package:shimmer/shimmer.dart';
class ProfessionalListScreen extends StatefulWidget {
const ProfessionalListScreen({super.key});
@override
State<ProfessionalListScreen> createState() => _ProfessionalListScreenState();
}
class _ProfessionalListScreenState extends State<ProfessionalListScreen> {
final _searchController = TextEditingController();
final professionRepository = Injector.appInstance.get<ProfessionRepository>();
final settingRepository = Injector.appInstance.get<SettingRepository>();
SettingEntity? settings;
List<String>? _professions;
List<String>? _filteredProfessions;
String? _selectedProfession;
bool _isLoading = true;
late final ProfessionalListBloc bloc;
@override
void initState() {
super.initState();
bloc = Injector.appInstance.get<ProfessionalListBloc>();
bloc.add(const ProfessionalListFetch());
_loadSettings();
_loadProfessions();
}
void _loadSettings() {
settingRepository.getSettings().then(
(value) => setState(() {
settings = value;
}),
);
}
void _loadProfessions() {
professionRepository.getProfessions().then((Professions element) {
setState(() {
_professions = element.professions;
_filteredProfessions = _professions;
_isLoading = false;
});
});
}
@override
Widget build(BuildContext context) {
return BlocProvider<ProfessionalListBloc>(
create: (context) => bloc,
child: BlocBuilder<ProfessionalListBloc, ProfessionalListState>(
builder: (context, state) {
return Scaffold(
appBar: AppBar(
actions: [
_selectedProfession != null
? IconButton(
icon: const Icon(
Icons.clear,
color: Colors.red,
size: 32,
),
onPressed: () {
setState(() {
_selectedProfession = null;
});
},
)
: Container()
],
title: _selectedProfession != null
? Text(_selectedProfession!)
: const Text('Selecciona un profesional'),
),
body: Column(
children: [
_isLoading
? _buildShimmerEffect()
: _selectedProfession == null
? Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey[400]!,
),
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
isExpanded: true,
value: _selectedProfession,
hint: const Text('Seleccione una profesión'),
items: _filteredProfessions
?.map((String profession) {
return DropdownMenuItem<String>(
value: profession,
child: Text(profession),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_selectedProfession = newValue;
});
},
),
),
)
: Container(),
_selectedProfession != null
? TextField(
controller: _searchController,
onChanged: (value) {
setState(() {
_searchController.text = value;
});
},
decoration: const InputDecoration(
hintText: 'Busca un profesional',
prefixIcon: Icon(Icons.search),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
),
)
: Container(),
Expanded(
child: _selectedProfession != null
? _body(state)
: const Center(
child: Text(
'Agrega los filtros para ver los profesionales'),
),
),
],
),
);
},
),
);
}
_body(ProfessionalListState state) {
if (state is ProfessionalListSuccess) {
final List<UserProfessional> filteredUsers;
// TODO: encaso de filtro dañado
// if (_searchController.text.isNotEmpty) {
filteredUsers = state.users
.where((element) => removeDiacritics(element.myUser.name!)
.toLowerCase()
.contains(removeDiacritics(_searchController.text.toLowerCase())))
.where((user) =>
user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
.where(
(user) => user.professionalInfo.profession == _selectedProfession)
.toList();
// } else {
// filteredUsers = state.users
// // .where((user) => user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
// .toList();
// }
if (filteredUsers.isEmpty) {
return const Center(
child: Text('Ningun profesional coincide con la busqueda'),
);
}
return ListView.builder(
itemCount: filteredUsers.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.withOpacity(0.2)),
),
),
child: ListTile(
onTap: () async {
var datos = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => UserCalendarScreen(
userProfessional: filteredUsers[index],
),
),
);
if (datos != null) {
Navigator.pop(context, datos);
}
},
trailing: GestureDetector(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => UserViewProfileScreen(
userProfessional: filteredUsers[index],
),
),
);
},
child: filteredUsers[index].professionalInfo.rate.isEmpty ||
settings?.tarifas == false
? const Icon(
Icons.keyboard_arrow_right,
color: Colors.black,
)
: Column(
children: [
const SizedBox(height: 5),
const Icon(
Icons.keyboard_arrow_right,
color: Colors.black,
),
Container(
//fondo azul
decoration: BoxDecoration(
color: Colors.blue[200],
borderRadius: BorderRadius.circular(50),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
child: Text(
'\$${filteredUsers[index].professionalInfo.rate}',
style: const TextStyle(
fontSize: 13,
),
),
),
),
],
),
),
leading: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
image: filteredUsers[index].myUser.picture == null
? null
: DecorationImage(
image: NetworkImage(
filteredUsers[index].myUser.picture ?? ''),
fit: BoxFit.contain,
),
),
child: filteredUsers[index].myUser.picture == null
? Icon(
CupertinoIcons.person,
color: Colors.grey.shade400,
size: 40,
)
: null,
),
title: Row(
children: [
Flexible(
child: Text(
'${filteredUsers[index].myUser.name ?? ''}, ',
overflow: TextOverflow.ellipsis,
),
),
Text(
filteredUsers[index].professionalInfo.profession,
overflow: TextOverflow.ellipsis,
),
],
),
subtitle: Text(
_disponibilidad(filteredUsers[index].professionalInfo),
style: const TextStyle(
fontSize: 13,
color: Colors.blue,
),
),
),
);
},
);
}
return Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: ListView.builder(
itemCount: 8,
itemBuilder: (_, __) => Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.withOpacity(0.4)),
),
),
child: ListTile(
trailing: const Icon(
Icons.keyboard_arrow_right,
color: Colors.black,
),
leading: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey.shade300,
shape: BoxShape.circle,
),
),
title: Container(
width: MediaQuery.of(context).size.width * 0.8,
height: 20.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
),
subtitle: Container(
width: MediaQuery.of(context).size.width * 0.3,
height: 15.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
),
),
),
),
);
}
String _disponibilidad(ProfessionalEntity professionalInfo) {
if (professionalInfo.locationPreferences == LocationPreferences.office) {
return 'Disponibilidad: en sitio.';
}
if (professionalInfo.locationPreferences == LocationPreferences.delivery) {
return 'Disponibilidad: domicilio.';
}
return 'Disponibilidad: domicilio, en sitio.';
}
Widget _buildShimmerEffect() {
return Expanded(
child: Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: ListView.builder(
itemCount: 8,
itemBuilder: (_, __) => const ListTileShimmer(),
),
),
);
}
}