score
This commit is contained in:
+5
-4
@@ -23,9 +23,9 @@ class MainApp extends StatelessWidget {
|
||||
BlocProvider<MyUserBloc>(
|
||||
create: (context) => Injector.appInstance.get<MyUserBloc>(),
|
||||
),
|
||||
BlocProvider<ScoreBloc>(
|
||||
create: (context) => Injector.appInstance.get(),
|
||||
),
|
||||
// BlocProvider<ScoreBloc>(
|
||||
// create: (context) => Injector.appInstance.get(),
|
||||
// ),
|
||||
BlocProvider<ProfileBloc>(
|
||||
create: (context) => Injector.appInstance.get<ProfileBloc>(),
|
||||
),
|
||||
@@ -33,7 +33,8 @@ class MainApp extends StatelessWidget {
|
||||
create: (context) => Injector.appInstance.get<ProfessionalBloc>(),
|
||||
),
|
||||
BlocProvider<ProfessionalProfileBloc>(
|
||||
create: (context) => Injector.appInstance.get<ProfessionalProfileBloc>(),
|
||||
create: (context) =>
|
||||
Injector.appInstance.get<ProfessionalProfileBloc>(),
|
||||
)
|
||||
],
|
||||
child: BlocBuilder<MyUserBloc, MyUserState>(
|
||||
|
||||
@@ -3,23 +3,27 @@ import 'dart:developer';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:score_repository/score_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:user_repository/user_repository.dart';
|
||||
|
||||
part 'score_event.dart';
|
||||
part 'score_state.dart';
|
||||
|
||||
class ScoreBloc extends Bloc<ScoreEvent, ScoreState> {
|
||||
final FirebaseScoreRepository _firebaseScoreRepository;
|
||||
final FirebaseScoreRepository _scoreRepository;
|
||||
final UserRepository _userRepository;
|
||||
|
||||
ScoreBloc({
|
||||
required FirebaseScoreRepository firebaseScoreRepository,
|
||||
}) : _firebaseScoreRepository = firebaseScoreRepository,
|
||||
required FirebaseScoreRepository scoreRepository,
|
||||
required UserRepository userRepository,
|
||||
}) : _scoreRepository = scoreRepository,
|
||||
_userRepository = userRepository,
|
||||
super(ScoreInitial()) {
|
||||
try {
|
||||
emit(ScoreSuccess(_firebaseScoreRepository.getReputation()));
|
||||
emit(ScoreSuccess(_scoreRepository.getReputation()));
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
_firebaseScoreRepository.streamReputation().listen((event) {
|
||||
_scoreRepository.streamReputation().listen((event) {
|
||||
try {
|
||||
emit(ScoreSuccess(event));
|
||||
} catch (e) {
|
||||
@@ -29,13 +33,91 @@ class ScoreBloc extends Bloc<ScoreEvent, ScoreState> {
|
||||
});
|
||||
|
||||
on<SendScoreEvent>(_onSendScoreEvent);
|
||||
on<LoadScoresForUserEvent>(_onLoadScoresForUserEvent);
|
||||
on<LoadScoresForProfessionalEvent>(_onLoadScoresForProfessionalEvent);
|
||||
}
|
||||
|
||||
void _onSendScoreEvent(SendScoreEvent event, Emitter<ScoreState> emit) async {
|
||||
try {
|
||||
await _firebaseScoreRepository.addComment(event.comment);
|
||||
await _scoreRepository.addComment(event.comment);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void _onLoadScoresForUserEvent(
|
||||
LoadScoresForUserEvent event, Emitter<ScoreState> emit) async {
|
||||
try {
|
||||
final scoresStream = _scoreRepository.getScoresForUser(event.userId);
|
||||
|
||||
await for (var scores in scoresStream) {
|
||||
if (scores.isEmpty) {
|
||||
emit(const ScoresForUserLoaded([]));
|
||||
return;
|
||||
}
|
||||
final userIds = scores.map((e) => e.authorId);
|
||||
|
||||
final List<MyUser> users =
|
||||
await _userRepository.getUsersFromIds(userIds);
|
||||
|
||||
final usersDir = {for (var e in users) e.id: e};
|
||||
|
||||
final scoresInfo = scores.map((e) {
|
||||
return ScoreInfoUI(
|
||||
score: e,
|
||||
user: usersDir[e.authorId]!,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
log(scoresInfo.toString());
|
||||
|
||||
emit(ScoresForUserLoaded(scoresInfo));
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
emit(ScoreFailure());
|
||||
}
|
||||
}
|
||||
|
||||
void _onLoadScoresForProfessionalEvent(
|
||||
LoadScoresForProfessionalEvent event,
|
||||
Emitter<ScoreState> emit,
|
||||
) async {
|
||||
try {
|
||||
final scoresStream =
|
||||
_scoreRepository.getScoresForProfessional(event.userId);
|
||||
|
||||
await for (var scores in scoresStream) {
|
||||
if (scores.isEmpty) {
|
||||
emit(const ScoresForUserLoaded([]));
|
||||
return;
|
||||
}
|
||||
final userIds = scores.map((e) => e.authorId);
|
||||
|
||||
final List<MyUser> users =
|
||||
await _userRepository.getUsersFromIds(userIds);
|
||||
|
||||
final usersDir = {for (var e in users) e.id: e};
|
||||
|
||||
final scoresInfo = scores.map((e) {
|
||||
return ScoreInfoUI(
|
||||
score: e,
|
||||
user: usersDir[e.authorId]!,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
emit(ScoresForUserLoaded(scoresInfo));
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
emit(ScoreFailure());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ScoreInfoUI {
|
||||
final CommentEntity score;
|
||||
final MyUser user;
|
||||
|
||||
ScoreInfoUI({required this.score, required this.user});
|
||||
}
|
||||
|
||||
@@ -15,3 +15,21 @@ class SendScoreEvent extends ScoreEvent {
|
||||
@override
|
||||
List<Object> get props => [comment];
|
||||
}
|
||||
|
||||
class LoadScoresForUserEvent extends ScoreEvent {
|
||||
final String userId;
|
||||
|
||||
const LoadScoresForUserEvent({required this.userId});
|
||||
|
||||
@override
|
||||
List<Object> get props => [userId];
|
||||
}
|
||||
|
||||
class LoadScoresForProfessionalEvent extends ScoreEvent {
|
||||
final String userId;
|
||||
|
||||
const LoadScoresForProfessionalEvent({required this.userId});
|
||||
|
||||
@override
|
||||
List<Object> get props => [userId];
|
||||
}
|
||||
|
||||
@@ -20,3 +20,12 @@ class ScoreSuccess extends ScoreState {
|
||||
@override
|
||||
List<Object> get props => [reputation];
|
||||
}
|
||||
|
||||
class ScoresForUserLoaded extends ScoreState {
|
||||
final List<ScoreInfoUI> scores;
|
||||
|
||||
const ScoresForUserLoaded(this.scores);
|
||||
|
||||
@override
|
||||
List<Object> get props => [scores];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injector/injector.dart';
|
||||
import 'package:prosappco/blocs/score_bloc/score_bloc.dart';
|
||||
import 'package:score_repository/score_repository.dart';
|
||||
|
||||
@@ -10,14 +11,17 @@ class DrawerReputation extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<ScoreBloc, ScoreState>(builder: (context, state) {
|
||||
if (state is ScoreSuccess) {
|
||||
return builder(state.reputation);
|
||||
} else if (state is ScoreFailure) {
|
||||
return const Center(child: Text('Error'));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
});
|
||||
return BlocProvider(
|
||||
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||
child: BlocBuilder<ScoreBloc, ScoreState>(builder: (context, state) {
|
||||
if (state is ScoreSuccess) {
|
||||
return builder(state.reputation);
|
||||
} else if (state is ScoreFailure) {
|
||||
return const Center(child: Text('Error'));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+254
-232
@@ -6,16 +6,20 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
|
||||
import 'package:injector/injector.dart';
|
||||
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
|
||||
import 'package:prosappco/blocs/professional_bloc/professional_bloc.dart';
|
||||
import 'package:prosappco/blocs/score_bloc/score_bloc.dart';
|
||||
import 'package:prosappco/components/drawer_reputation.dart';
|
||||
import 'package:prosappco/components/general_drawer_header.dart';
|
||||
import 'package:prosappco/components/general_drawer_item.dart';
|
||||
import 'package:prosappco/screens/configuration/configuration_screen.dart';
|
||||
import 'package:prosappco/screens/configuration/configuration_support_screen.dart';
|
||||
import 'package:prosappco/screens/lists/professional_list_screen.dart';
|
||||
import 'package:prosappco/screens/lists/professional_score_list_screen.dart';
|
||||
import 'package:prosappco/screens/lists/professional_service_history_list_screen.dart';
|
||||
import 'package:prosappco/screens/lists/professional_service_list_screen.dart';
|
||||
import 'package:prosappco/screens/lists/user_score_list_screen.dart';
|
||||
import 'package:prosappco/screens/lists/user_service_history_list_screen.dart';
|
||||
import 'package:prosappco/screens/lists/user_service_list_screen.dart';
|
||||
import 'package:prosappco/screens/professional/professional_calendar_screen.dart';
|
||||
@@ -47,252 +51,274 @@ class GeneralDrawer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<MyUserBloc, MyUserState>(
|
||||
builder: (context, userState) {
|
||||
return BlocBuilder<ProfessionalBloc, ProfessionalState>(
|
||||
builder: (context, professionalState) {
|
||||
return Drawer(
|
||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const GeneralDrawerHeader(),
|
||||
Divider(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.1),
|
||||
thickness: 0.5,
|
||||
height: 1,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
shouldProModeActive(context, professionalState)
|
||||
? GeneralDrawerItem(
|
||||
leading: Icons.person_outline_rounded,
|
||||
label: 'Perfil profesional',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalProfileScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: const SizedBox(),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.checklist_outlined,
|
||||
label: 'Mis servicios',
|
||||
onTap: () {
|
||||
shouldProModeActive(context, professionalState)
|
||||
? Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalServiceListScreen(),
|
||||
// const UserServicesScreen(),
|
||||
),
|
||||
)
|
||||
: Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const UserServiceListScreen(),
|
||||
// const UserServicesScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.access_time_outlined,
|
||||
label: 'Historial',
|
||||
onTap: () {
|
||||
shouldProModeActive(context, professionalState)
|
||||
? Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalServiceHistoryListScreen(),
|
||||
),
|
||||
)
|
||||
: Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const UserServiceHistoryListScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
shouldProModeActive(context, professionalState)
|
||||
? GeneralDrawerItem(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalCalendarScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
label: 'Calendario',
|
||||
leading: Icons.calendar_month_outlined,
|
||||
)
|
||||
: const SizedBox(),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.settings_outlined,
|
||||
label: 'Configuración',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ConfigurationScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.help_outline,
|
||||
label: 'Soporte',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ConfigurationSupportScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.campaign_outlined,
|
||||
label: 'Sugerencias',
|
||||
onTap: () {
|
||||
if (kIsWeb) {
|
||||
_irSugerencias();
|
||||
} else {
|
||||
return BlocProvider(
|
||||
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||
child: BlocBuilder<MyUserBloc, MyUserState>(
|
||||
builder: (context, userState) {
|
||||
return BlocBuilder<ProfessionalBloc, ProfessionalState>(
|
||||
builder: (context, professionalState) {
|
||||
return Drawer(
|
||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const GeneralDrawerHeader(),
|
||||
Divider(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.1),
|
||||
thickness: 0.5,
|
||||
height: 1,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
shouldProModeActive(context, professionalState)
|
||||
? GeneralDrawerItem(
|
||||
leading: Icons.person_outline_rounded,
|
||||
label: 'Perfil profesional',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalProfileScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: const SizedBox(),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.checklist_outlined,
|
||||
label: 'Mis servicios',
|
||||
onTap: () {
|
||||
shouldProModeActive(context, professionalState)
|
||||
? Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalServiceListScreen(),
|
||||
// const UserServicesScreen(),
|
||||
),
|
||||
)
|
||||
: Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const UserServiceListScreen(),
|
||||
// const UserServicesScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.access_time_outlined,
|
||||
label: 'Historial',
|
||||
onTap: () {
|
||||
shouldProModeActive(context, professionalState)
|
||||
? Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalServiceHistoryListScreen(),
|
||||
),
|
||||
)
|
||||
: Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const UserServiceHistoryListScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
shouldProModeActive(context, professionalState)
|
||||
? GeneralDrawerItem(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ProfessionalCalendarScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
label: 'Calendario',
|
||||
leading: Icons.calendar_month_outlined,
|
||||
)
|
||||
: const SizedBox(),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.settings_outlined,
|
||||
label: 'Configuración',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return WebViewScreen(
|
||||
label: 'Sugerencias',
|
||||
link:
|
||||
'https://admin.prosapp.co/sugerencias');
|
||||
},
|
||||
builder: (context) =>
|
||||
const ConfigurationScreen(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
Container(
|
||||
color: const Color(0xFF2BA4EC),
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
shouldProModeActive(context, professionalState)
|
||||
? Navigator.pop(context)
|
||||
: Navigator.pop(context);
|
||||
},
|
||||
trailing: const Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: Colors.white,
|
||||
),
|
||||
title: Text(
|
||||
shouldProModeActive(context, professionalState)
|
||||
? 'Solicitudes'
|
||||
: 'Solicitar servicio',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.help_outline,
|
||||
label: 'Soporte',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) =>
|
||||
const ConfigurationSupportScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GeneralDrawerItem(
|
||||
leading: Icons.campaign_outlined,
|
||||
label: 'Sugerencias',
|
||||
onTap: () {
|
||||
if (kIsWeb) {
|
||||
_irSugerencias();
|
||||
} else {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return WebViewScreen(
|
||||
label: 'Sugerencias',
|
||||
link:
|
||||
'https://admin.prosapp.co/sugerencias');
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
Container(
|
||||
color: const Color(0xFF2BA4EC),
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
shouldProModeActive(
|
||||
context, professionalState)
|
||||
? Navigator.pop(context)
|
||||
: Navigator.pop(context);
|
||||
},
|
||||
trailing: const Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
title: Text(
|
||||
shouldProModeActive(
|
||||
context, professionalState)
|
||||
? 'Solicitudes'
|
||||
: 'Solicitar servicio',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
DrawerReputation(builder: (reputation) {
|
||||
final isProModeActive =
|
||||
(professionalState is LoadedModeProState) &&
|
||||
professionalState.isProModeActive;
|
||||
DrawerReputation(builder: (reputation) {
|
||||
final isProModeActive =
|
||||
(professionalState is LoadedModeProState) &&
|
||||
professionalState.isProModeActive;
|
||||
|
||||
final total = isProModeActive
|
||||
? reputation.totalPro
|
||||
: reputation.total;
|
||||
final total = isProModeActive
|
||||
? reputation.totalPro
|
||||
: reputation.total;
|
||||
|
||||
final average = isProModeActive
|
||||
? reputation.averagePro
|
||||
: reputation.average;
|
||||
final average = isProModeActive
|
||||
? reputation.averagePro
|
||||
: reputation.average;
|
||||
|
||||
return ListTile(
|
||||
onTap: () {},
|
||||
trailing: const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
||||
title: Row(
|
||||
children: [
|
||||
RatingBar.builder(
|
||||
initialRating: calculoRating(average),
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
itemCount: 5,
|
||||
itemSize: 25,
|
||||
maxRating: 5,
|
||||
itemBuilder: (context, _) => const Icon(
|
||||
Icons.star,
|
||||
color: Color(0xFF2BA4EC),
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
final isProModeActive = (professionalState
|
||||
is LoadedModeProState) &&
|
||||
professionalState.isProModeActive;
|
||||
isProModeActive
|
||||
? Navigator.push(context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) {
|
||||
return const ProfessionalScoreListScreen();
|
||||
}))
|
||||
: Navigator.push(context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) {
|
||||
return const UserScoreListScreen();
|
||||
}));
|
||||
},
|
||||
trailing: const Icon(Icons.keyboard_arrow_right,
|
||||
color: Colors.black),
|
||||
title: Row(
|
||||
children: [
|
||||
RatingBar.builder(
|
||||
// initialRating: calculoRating(average),
|
||||
initialRating: 3,
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
itemCount: 5,
|
||||
itemSize: 25,
|
||||
maxRating: 5,
|
||||
itemBuilder: (context, _) => const Icon(
|
||||
Icons.star,
|
||||
color: Color(0xFF2BA4EC),
|
||||
),
|
||||
onRatingUpdate: (rating) {},
|
||||
ignoreGestures: true,
|
||||
),
|
||||
onRatingUpdate: (rating) {},
|
||||
ignoreGestures: true,
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'${average.toStringAsFixed(1)} (${total.toString()})',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
const Divider(
|
||||
height: 1,
|
||||
thickness: 0.5,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(
|
||||
'Prosapp ® todos los derechos reservados',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.grey[700],
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'${average.toStringAsFixed(1)} (${total.toString()})',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
const Divider(
|
||||
height: 1,
|
||||
thickness: 0.5,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(
|
||||
'Prosapp ® todos los derechos reservados',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.1),
|
||||
thickness: 0.5,
|
||||
height: 1,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: buttonOfState(context, professionalState),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
Divider(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.1),
|
||||
thickness: 0.5,
|
||||
height: 1,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: buttonOfState(context, professionalState),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -389,10 +415,6 @@ class GeneralDrawer extends StatelessWidget {
|
||||
'Modo profesional',
|
||||
style: TextStyle(color: Colors.white, fontSize: 18),
|
||||
),
|
||||
|
||||
// const CircularProgressIndicator(
|
||||
// color: Colors.white,
|
||||
// ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,8 +47,7 @@ class AppDI {
|
||||
|
||||
injector.registerSingleton<MyUserBloc>(
|
||||
(() => MyUserBloc(myUserRepository: injector.get<UserRepository>())));
|
||||
injector.registerSingleton(
|
||||
(() => ScoreBloc(firebaseScoreRepository: injector.get())));
|
||||
|
||||
injector.registerSingleton<ProfileBloc>(
|
||||
(() => ProfileBloc(userRepository: injector.get<UserRepository>())));
|
||||
|
||||
@@ -91,5 +90,17 @@ class AppDI {
|
||||
professionRepository: injector.get<FirebaseProfessionalRepository>(),
|
||||
),
|
||||
);
|
||||
|
||||
injector.registerDependency<ScoreBloc>(
|
||||
() => ScoreBloc(
|
||||
scoreRepository: injector.get<FirebaseScoreRepository>(),
|
||||
userRepository: injector.get<UserRepository>(),
|
||||
),
|
||||
);
|
||||
|
||||
// injector.registerSingleton((() => ScoreBloc(
|
||||
// firebaseScoreRepository: injector.get(),
|
||||
// userRepository: injector.get<UserRepository>(),
|
||||
// )));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,8 +79,8 @@ class _ProfessionalListScreenState extends State<ProfessionalListScreen> {
|
||||
.where((element) => removeDiacritics(element.myUser.name!)
|
||||
.toLowerCase()
|
||||
.contains(removeDiacritics(_searchController.text.toLowerCase())))
|
||||
.where((user) =>
|
||||
user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
|
||||
// .where((user) =>
|
||||
// user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
|
||||
.toList();
|
||||
// } else {
|
||||
// filteredUsers = state.users
|
||||
@@ -183,12 +183,19 @@ class _ProfessionalListScreenState extends State<ProfessionalListScreen> {
|
||||
)
|
||||
: null,
|
||||
),
|
||||
title: Text(
|
||||
'${filteredUsers[index].myUser.name ?? ''}, ${filteredUsers[index].professionalInfo.profession}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
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),
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
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:prosappco/blocs/score_bloc/score_bloc.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class ProfessionalScoreListScreen extends StatefulWidget {
|
||||
const ProfessionalScoreListScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ProfessionalScoreListScreen> createState() =>
|
||||
_ProfessionalScoreListScreenState();
|
||||
}
|
||||
|
||||
class _ProfessionalScoreListScreenState
|
||||
extends State<ProfessionalScoreListScreen> {
|
||||
late final ScoreBloc scoreBloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
scoreBloc = Injector.appInstance.get<ScoreBloc>();
|
||||
|
||||
scoreBloc.add(LoadScoresForProfessionalEvent(
|
||||
userId: FirebaseAuth.instance.currentUser!.uid));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => scoreBloc,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Reputación'),
|
||||
),
|
||||
body: BlocBuilder<ScoreBloc, ScoreState>(
|
||||
builder: (context, scoreState) {
|
||||
if (scoreState is ScoresForUserLoaded) {
|
||||
return scoreState.scores.isEmpty
|
||||
? const Center(
|
||||
child: Text('No tienes calificaciones'),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: scoreState.scores.length,
|
||||
itemBuilder: (_, index) {
|
||||
final scoreInfo = scoreState.scores[index];
|
||||
final score = scoreInfo.score;
|
||||
final user = scoreInfo.user;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Colors.grey.withOpacity(0.2)),
|
||||
),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
shape: BoxShape.circle,
|
||||
image: user.picture == null
|
||||
? null
|
||||
: DecorationImage(
|
||||
image: NetworkImage(user.picture!),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
child: user.picture == null
|
||||
? Icon(
|
||||
CupertinoIcons.person,
|
||||
color: Colors.grey.shade400,
|
||||
size: 40,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
title: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
'${user.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'${score.createdAt.toDate().day}/${score.createdAt.toDate().month}/${score.createdAt.toDate().year}',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
'"${score.content.trim()}"',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
// icono de calificación
|
||||
trailing: Text(
|
||||
'⭐ ${score.score}',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: ListView.builder(
|
||||
itemCount: 10,
|
||||
itemBuilder: (_, __) => ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Colors.grey[300],
|
||||
radius: 30,
|
||||
),
|
||||
title: Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
subtitle: Container(
|
||||
height: 15,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
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/intl.dart';
|
||||
import 'package:prosappco/blocs/score_bloc/score_bloc.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class UserScoreListScreen extends StatefulWidget {
|
||||
const UserScoreListScreen({super.key});
|
||||
|
||||
@override
|
||||
State<UserScoreListScreen> createState() => _UserScoreListScreenState();
|
||||
}
|
||||
|
||||
class _UserScoreListScreenState extends State<UserScoreListScreen> {
|
||||
late final ScoreBloc scoreBloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
scoreBloc = Injector.appInstance.get<ScoreBloc>();
|
||||
|
||||
scoreBloc.add(
|
||||
LoadScoresForUserEvent(userId: FirebaseAuth.instance.currentUser!.uid));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => scoreBloc,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Reputación'),
|
||||
),
|
||||
body: BlocBuilder<ScoreBloc, ScoreState>(
|
||||
builder: (context, scoreState) {
|
||||
if (scoreState is ScoresForUserLoaded) {
|
||||
return scoreState.scores.isEmpty
|
||||
? const Center(
|
||||
child: Text('No tienes calificaciones'),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: scoreState.scores.length,
|
||||
itemBuilder: (_, index) {
|
||||
final scoreInfo = scoreState.scores[index];
|
||||
final score = scoreInfo.score;
|
||||
final user = scoreInfo.user;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Colors.grey.withOpacity(0.2)),
|
||||
),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
shape: BoxShape.circle,
|
||||
image: user.picture == null
|
||||
? null
|
||||
: DecorationImage(
|
||||
image: NetworkImage(user.picture!),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
child: user.picture == null
|
||||
? Icon(
|
||||
CupertinoIcons.person,
|
||||
color: Colors.grey.shade400,
|
||||
size: 40,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
title: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
'${user.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'${score.createdAt.toDate().day}/${score.createdAt.toDate().month}/${score.createdAt.toDate().year}',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
'"${score.content.trim()}"',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
// icono de calificación
|
||||
trailing: Text(
|
||||
'⭐ ${score.score}',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: ListView.builder(
|
||||
itemCount: 10,
|
||||
itemBuilder: (_, __) => ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Colors.grey[300],
|
||||
radius: 30,
|
||||
),
|
||||
title: Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
subtitle: Container(
|
||||
height: 15,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+306
-296
@@ -43,319 +43,329 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Calificación'),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: _userInfoFuture,
|
||||
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else {
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text('Error inesperado: ${snapshot.error}'),
|
||||
);
|
||||
return BlocProvider(
|
||||
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Calificación'),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: _userInfoFuture,
|
||||
builder:
|
||||
(context, AsyncSnapshot<List<dynamic>> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator());
|
||||
} else {
|
||||
final userInfo = snapshot.data![0] as MyUser;
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child:
|
||||
Text('Error inesperado: ${snapshot.error}'),
|
||||
);
|
||||
} else {
|
||||
final userInfo = snapshot.data![0] as MyUser;
|
||||
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 95,
|
||||
height: 95,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
shape: BoxShape.circle,
|
||||
image: userInfo.picture == null
|
||||
? null
|
||||
: DecorationImage(
|
||||
image: NetworkImage(
|
||||
userInfo.picture!),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
child: userInfo.picture == null
|
||||
? Icon(
|
||||
CupertinoIcons.person,
|
||||
color: Colors.grey.shade400,
|
||||
size: 50,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${userInfo.name}',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
GeneralReputation(
|
||||
userId: userId,
|
||||
builder: (BuildContext context,
|
||||
ReputationEntity reputation) {
|
||||
final double average;
|
||||
|
||||
if (isProfessional) {
|
||||
average = reputation.averagePro;
|
||||
} else {
|
||||
average = reputation.average;
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
top: 3,
|
||||
right: MediaQuery.of(context).size.width *
|
||||
0.3,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 3,
|
||||
),
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 95,
|
||||
height: 95,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.black.withOpacity(0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 2,
|
||||
offset: const Offset(
|
||||
0,
|
||||
1,
|
||||
),
|
||||
),
|
||||
],
|
||||
color: Colors.grey.shade300,
|
||||
shape: BoxShape.circle,
|
||||
image: userInfo.picture == null
|
||||
? null
|
||||
: DecorationImage(
|
||||
image: NetworkImage(
|
||||
userInfo.picture!),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.star,
|
||||
color: Colors.yellow,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
child: Text(
|
||||
average.toStringAsFixed(2),
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
child: userInfo.picture == null
|
||||
? Icon(
|
||||
CupertinoIcons.person,
|
||||
color: Colors.grey.shade400,
|
||||
size: 50,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${userInfo.name}',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
GeneralReputation(
|
||||
userId: userId,
|
||||
builder: (BuildContext context,
|
||||
ReputationEntity reputation) {
|
||||
final double average;
|
||||
|
||||
if (isProfessional) {
|
||||
average = reputation.averagePro;
|
||||
} else {
|
||||
average = reputation.average;
|
||||
}
|
||||
|
||||
return Positioned(
|
||||
top: 3,
|
||||
right:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.3,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black
|
||||
.withOpacity(0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 2,
|
||||
offset: const Offset(
|
||||
0,
|
||||
1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.star,
|
||||
color: Colors.yellow,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
child: Text(
|
||||
average.toStringAsFixed(2),
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
// child: ListTile(
|
||||
// leading: Container(
|
||||
// width: 60,
|
||||
// height: 60,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.grey.shade300,
|
||||
// shape: BoxShape.circle,
|
||||
// image: userInfo.picture == null
|
||||
// ? null
|
||||
// : DecorationImage(
|
||||
// image: NetworkImage(
|
||||
// userInfo.picture ?? ''),
|
||||
// fit: BoxFit.contain,
|
||||
// ),
|
||||
// ),
|
||||
// child: userInfo.picture == null
|
||||
// ? Icon(
|
||||
// CupertinoIcons.person,
|
||||
// color: Colors.grey.shade400,
|
||||
// size: 40,
|
||||
// )
|
||||
// : null,
|
||||
// ),
|
||||
// title: Text(
|
||||
// userInfo.name ?? '',
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 15,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// ),
|
||||
// ),
|
||||
// subtitle: const Text(
|
||||
// 'Rating: 5.0',
|
||||
// style: TextStyle(
|
||||
// fontSize: 13,
|
||||
// color: Colors.blue,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
// child: ListTile(
|
||||
// leading: Container(
|
||||
// width: 60,
|
||||
// height: 60,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.grey.shade300,
|
||||
// shape: BoxShape.circle,
|
||||
// image: userInfo.picture == null
|
||||
// ? null
|
||||
// : DecorationImage(
|
||||
// image: NetworkImage(
|
||||
// userInfo.picture ?? ''),
|
||||
// fit: BoxFit.contain,
|
||||
// ),
|
||||
// ),
|
||||
// child: userInfo.picture == null
|
||||
// ? Icon(
|
||||
// CupertinoIcons.person,
|
||||
// color: Colors.grey.shade400,
|
||||
// size: 40,
|
||||
// )
|
||||
// : null,
|
||||
// ),
|
||||
// title: Text(
|
||||
// userInfo.name ?? '',
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 15,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// ),
|
||||
// ),
|
||||
// subtitle: const Text(
|
||||
// 'Rating: 5.0',
|
||||
// style: TextStyle(
|
||||
// fontSize: 13,
|
||||
// color: Colors.blue,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'Califica el servicio',
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
RatingBar.builder(
|
||||
initialRating: _rating,
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
itemCount: 5,
|
||||
itemSize: 40,
|
||||
glow: false,
|
||||
maxRating: 5,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
itemBuilder: (context, _) => const Icon(
|
||||
Icons.star,
|
||||
color: Color(0xFF2BA4EC),
|
||||
},
|
||||
),
|
||||
onRatingUpdate: (rating) {
|
||||
setState(() {
|
||||
_rating = rating;
|
||||
});
|
||||
},
|
||||
ignoreGestures: false,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
customMessage(_rating),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'Califica el servicio',
|
||||
style:
|
||||
TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
RatingBar.builder(
|
||||
initialRating: _rating,
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
itemCount: 5,
|
||||
itemSize: 40,
|
||||
glow: false,
|
||||
maxRating: 5,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
itemBuilder: (context, _) => const Icon(
|
||||
Icons.star,
|
||||
color: Color(0xFF2BA4EC),
|
||||
),
|
||||
onRatingUpdate: (rating) {
|
||||
setState(() {
|
||||
_rating = rating;
|
||||
});
|
||||
},
|
||||
ignoreGestures: false,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 40, vertical: 40),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Comentario',
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
customMessage(_rating),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Color(0xFF2BA4EC),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 40, vertical: 40),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Comentario',
|
||||
style: TextStyle(
|
||||
fontSize: 20, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextFormField(
|
||||
maxLines: null,
|
||||
maxLength: 400,
|
||||
keyboardType: TextInputType.multiline,
|
||||
controller: commentController,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
thickness: 0.5,
|
||||
),
|
||||
BlocProvider<ServiceBloc>(
|
||||
create: (context) => Injector.appInstance.get<ServiceBloc>(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 15,
|
||||
),
|
||||
child: BlocBuilder<ServiceBloc, ServiceState>(
|
||||
builder: (context, serviceState) {
|
||||
return FilledButton(
|
||||
onPressed: () {
|
||||
final CommentEntity comment = widget.service.userId ==
|
||||
FirebaseAuth.instance.currentUser!.uid
|
||||
? CommentEntity(
|
||||
serviceId: widget.service.id!,
|
||||
authorId:
|
||||
FirebaseAuth.instance.currentUser!.uid,
|
||||
isFromUser: true,
|
||||
score: _rating,
|
||||
destinationId: widget.service.professionalId,
|
||||
content: commentController.text.trim(),
|
||||
createdAt: Timestamp.now(),
|
||||
)
|
||||
: CommentEntity(
|
||||
serviceId: widget.service.id!,
|
||||
authorId:
|
||||
FirebaseAuth.instance.currentUser!.uid,
|
||||
isFromUser: false,
|
||||
score: _rating,
|
||||
destinationId: widget.service.userId,
|
||||
content: commentController.text.trim(),
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
BlocProvider.of<ScoreBloc>(context)
|
||||
.add(SendScoreEvent(comment: comment));
|
||||
|
||||
if (widget.service.userId ==
|
||||
FirebaseAuth.instance.currentUser!.uid) {
|
||||
context.read<ServiceBloc>().add(
|
||||
UpdateProfessionalScored(widget.service.id!));
|
||||
} else {
|
||||
context
|
||||
.read<ServiceBloc>()
|
||||
.add(UpdateUserScored(widget.service.id!));
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: double.infinity,
|
||||
child: const Text(
|
||||
'Enviar calificación',
|
||||
style: TextStyle(
|
||||
fontSize: 20, fontWeight: FontWeight.w600),
|
||||
),
|
||||
TextFormField(
|
||||
maxLines: null,
|
||||
maxLength: 400,
|
||||
keyboardType: TextInputType.multiline,
|
||||
controller: commentController,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
thickness: 0.5,
|
||||
),
|
||||
BlocProvider<ServiceBloc>(
|
||||
create: (context) => Injector.appInstance.get<ServiceBloc>(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 15,
|
||||
),
|
||||
child: BlocBuilder<ServiceBloc, ServiceState>(
|
||||
builder: (context, state) {
|
||||
return FilledButton(
|
||||
onPressed: () {
|
||||
final CommentEntity comment = widget.service.userId ==
|
||||
FirebaseAuth.instance.currentUser!.uid
|
||||
? CommentEntity(
|
||||
serviceId: widget.service.id!,
|
||||
authorId: FirebaseAuth.instance.currentUser!.uid,
|
||||
isFromUser: true,
|
||||
score: _rating,
|
||||
destinationId: widget.service.professionalId,
|
||||
content: commentController.text.trim(),
|
||||
createdAt: Timestamp.now(),
|
||||
)
|
||||
: CommentEntity(
|
||||
serviceId: widget.service.id!,
|
||||
authorId: FirebaseAuth.instance.currentUser!.uid,
|
||||
isFromUser: false,
|
||||
score: _rating,
|
||||
destinationId: widget.service.userId,
|
||||
content: commentController.text.trim(),
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
BlocProvider.of<ScoreBloc>(context)
|
||||
.add(SendScoreEvent(comment: comment));
|
||||
|
||||
if (widget.service.userId ==
|
||||
FirebaseAuth.instance.currentUser!.uid) {
|
||||
context
|
||||
.read<ServiceBloc>()
|
||||
.add(UpdateProfessionalScored(widget.service.id!));
|
||||
} else {
|
||||
context
|
||||
.read<ServiceBloc>()
|
||||
.add(UpdateUserScored(widget.service.id!));
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: double.infinity,
|
||||
child: const Text(
|
||||
'Enviar calificación',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,26 @@ class FirebaseScoreRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Stream<List<CommentEntity>> getScoresForUser(String userId) {
|
||||
return commentsCollection
|
||||
.where('destination_id', isEqualTo: userId)
|
||||
.where('is_from_user', isEqualTo: false)
|
||||
.snapshots()
|
||||
.map((querySnapshot) => querySnapshot.docs
|
||||
.map((doc) => CommentEntity.fromDocument(doc.data()))
|
||||
.toList());
|
||||
}
|
||||
|
||||
Stream<List<CommentEntity>> getScoresForProfessional(String userId) {
|
||||
return commentsCollection
|
||||
.where('destination_id', isEqualTo: userId)
|
||||
.where('is_from_user', isEqualTo: true)
|
||||
.snapshots()
|
||||
.map((querySnapshot) => querySnapshot.docs
|
||||
.map((doc) => CommentEntity.fromDocument(doc.data()))
|
||||
.toList());
|
||||
}
|
||||
|
||||
addComment(CommentEntity comment) async {
|
||||
await commentsCollection.add(comment.toDocument());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user