score
This commit is contained in:
+5
-4
@@ -23,9 +23,9 @@ class MainApp extends StatelessWidget {
|
|||||||
BlocProvider<MyUserBloc>(
|
BlocProvider<MyUserBloc>(
|
||||||
create: (context) => Injector.appInstance.get<MyUserBloc>(),
|
create: (context) => Injector.appInstance.get<MyUserBloc>(),
|
||||||
),
|
),
|
||||||
BlocProvider<ScoreBloc>(
|
// BlocProvider<ScoreBloc>(
|
||||||
create: (context) => Injector.appInstance.get(),
|
// create: (context) => Injector.appInstance.get(),
|
||||||
),
|
// ),
|
||||||
BlocProvider<ProfileBloc>(
|
BlocProvider<ProfileBloc>(
|
||||||
create: (context) => Injector.appInstance.get<ProfileBloc>(),
|
create: (context) => Injector.appInstance.get<ProfileBloc>(),
|
||||||
),
|
),
|
||||||
@@ -33,7 +33,8 @@ class MainApp extends StatelessWidget {
|
|||||||
create: (context) => Injector.appInstance.get<ProfessionalBloc>(),
|
create: (context) => Injector.appInstance.get<ProfessionalBloc>(),
|
||||||
),
|
),
|
||||||
BlocProvider<ProfessionalProfileBloc>(
|
BlocProvider<ProfessionalProfileBloc>(
|
||||||
create: (context) => Injector.appInstance.get<ProfessionalProfileBloc>(),
|
create: (context) =>
|
||||||
|
Injector.appInstance.get<ProfessionalProfileBloc>(),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
child: BlocBuilder<MyUserBloc, MyUserState>(
|
child: BlocBuilder<MyUserBloc, MyUserState>(
|
||||||
|
|||||||
@@ -3,23 +3,27 @@ import 'dart:developer';
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:score_repository/score_repository.dart';
|
import 'package:score_repository/score_repository.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:user_repository/user_repository.dart';
|
||||||
|
|
||||||
part 'score_event.dart';
|
part 'score_event.dart';
|
||||||
part 'score_state.dart';
|
part 'score_state.dart';
|
||||||
|
|
||||||
class ScoreBloc extends Bloc<ScoreEvent, ScoreState> {
|
class ScoreBloc extends Bloc<ScoreEvent, ScoreState> {
|
||||||
final FirebaseScoreRepository _firebaseScoreRepository;
|
final FirebaseScoreRepository _scoreRepository;
|
||||||
|
final UserRepository _userRepository;
|
||||||
|
|
||||||
ScoreBloc({
|
ScoreBloc({
|
||||||
required FirebaseScoreRepository firebaseScoreRepository,
|
required FirebaseScoreRepository scoreRepository,
|
||||||
}) : _firebaseScoreRepository = firebaseScoreRepository,
|
required UserRepository userRepository,
|
||||||
|
}) : _scoreRepository = scoreRepository,
|
||||||
|
_userRepository = userRepository,
|
||||||
super(ScoreInitial()) {
|
super(ScoreInitial()) {
|
||||||
try {
|
try {
|
||||||
emit(ScoreSuccess(_firebaseScoreRepository.getReputation()));
|
emit(ScoreSuccess(_scoreRepository.getReputation()));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
}
|
}
|
||||||
_firebaseScoreRepository.streamReputation().listen((event) {
|
_scoreRepository.streamReputation().listen((event) {
|
||||||
try {
|
try {
|
||||||
emit(ScoreSuccess(event));
|
emit(ScoreSuccess(event));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -29,13 +33,91 @@ class ScoreBloc extends Bloc<ScoreEvent, ScoreState> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
on<SendScoreEvent>(_onSendScoreEvent);
|
on<SendScoreEvent>(_onSendScoreEvent);
|
||||||
|
on<LoadScoresForUserEvent>(_onLoadScoresForUserEvent);
|
||||||
|
on<LoadScoresForProfessionalEvent>(_onLoadScoresForProfessionalEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSendScoreEvent(SendScoreEvent event, Emitter<ScoreState> emit) async {
|
void _onSendScoreEvent(SendScoreEvent event, Emitter<ScoreState> emit) async {
|
||||||
try {
|
try {
|
||||||
await _firebaseScoreRepository.addComment(event.comment);
|
await _scoreRepository.addComment(event.comment);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
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
|
@override
|
||||||
List<Object> get props => [comment];
|
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
|
@override
|
||||||
List<Object> get props => [reputation];
|
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/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:injector/injector.dart';
|
||||||
import 'package:prosappco/blocs/score_bloc/score_bloc.dart';
|
import 'package:prosappco/blocs/score_bloc/score_bloc.dart';
|
||||||
import 'package:score_repository/score_repository.dart';
|
import 'package:score_repository/score_repository.dart';
|
||||||
|
|
||||||
@@ -10,7 +11,9 @@ class DrawerReputation extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<ScoreBloc, ScoreState>(builder: (context, state) {
|
return BlocProvider(
|
||||||
|
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||||
|
child: BlocBuilder<ScoreBloc, ScoreState>(builder: (context, state) {
|
||||||
if (state is ScoreSuccess) {
|
if (state is ScoreSuccess) {
|
||||||
return builder(state.reputation);
|
return builder(state.reputation);
|
||||||
} else if (state is ScoreFailure) {
|
} else if (state is ScoreFailure) {
|
||||||
@@ -18,6 +21,7 @@ class DrawerReputation extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,20 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_rating_bar/flutter_rating_bar.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/my_user_bloc/my_user_bloc.dart';
|
||||||
import 'package:prosappco/blocs/professional_bloc/professional_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/drawer_reputation.dart';
|
||||||
import 'package:prosappco/components/general_drawer_header.dart';
|
import 'package:prosappco/components/general_drawer_header.dart';
|
||||||
import 'package:prosappco/components/general_drawer_item.dart';
|
import 'package:prosappco/components/general_drawer_item.dart';
|
||||||
import 'package:prosappco/screens/configuration/configuration_screen.dart';
|
import 'package:prosappco/screens/configuration/configuration_screen.dart';
|
||||||
import 'package:prosappco/screens/configuration/configuration_support_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_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_history_list_screen.dart';
|
||||||
import 'package:prosappco/screens/lists/professional_service_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_history_list_screen.dart';
|
||||||
import 'package:prosappco/screens/lists/user_service_list_screen.dart';
|
import 'package:prosappco/screens/lists/user_service_list_screen.dart';
|
||||||
import 'package:prosappco/screens/professional/professional_calendar_screen.dart';
|
import 'package:prosappco/screens/professional/professional_calendar_screen.dart';
|
||||||
@@ -47,7 +51,9 @@ class GeneralDrawer extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<MyUserBloc, MyUserState>(
|
return BlocProvider(
|
||||||
|
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||||
|
child: BlocBuilder<MyUserBloc, MyUserState>(
|
||||||
builder: (context, userState) {
|
builder: (context, userState) {
|
||||||
return BlocBuilder<ProfessionalBloc, ProfessionalState>(
|
return BlocBuilder<ProfessionalBloc, ProfessionalState>(
|
||||||
builder: (context, professionalState) {
|
builder: (context, professionalState) {
|
||||||
@@ -194,7 +200,8 @@ class GeneralDrawer extends StatelessWidget {
|
|||||||
color: const Color(0xFF2BA4EC),
|
color: const Color(0xFF2BA4EC),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
shouldProModeActive(context, professionalState)
|
shouldProModeActive(
|
||||||
|
context, professionalState)
|
||||||
? Navigator.pop(context)
|
? Navigator.pop(context)
|
||||||
: Navigator.pop(context);
|
: Navigator.pop(context);
|
||||||
},
|
},
|
||||||
@@ -203,7 +210,8 @@ class GeneralDrawer extends StatelessWidget {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
shouldProModeActive(context, professionalState)
|
shouldProModeActive(
|
||||||
|
context, professionalState)
|
||||||
? 'Solicitudes'
|
? 'Solicitudes'
|
||||||
: 'Solicitar servicio',
|
: 'Solicitar servicio',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -228,12 +236,29 @@ class GeneralDrawer extends StatelessWidget {
|
|||||||
: reputation.average;
|
: reputation.average;
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {},
|
onTap: () {
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
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(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
RatingBar.builder(
|
RatingBar.builder(
|
||||||
initialRating: calculoRating(average),
|
// initialRating: calculoRating(average),
|
||||||
|
initialRating: 3,
|
||||||
minRating: 1,
|
minRating: 1,
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
allowHalfRating: true,
|
allowHalfRating: true,
|
||||||
@@ -293,6 +318,7 @@ class GeneralDrawer extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,10 +415,6 @@ class GeneralDrawer extends StatelessWidget {
|
|||||||
'Modo profesional',
|
'Modo profesional',
|
||||||
style: TextStyle(color: Colors.white, fontSize: 18),
|
style: TextStyle(color: Colors.white, fontSize: 18),
|
||||||
),
|
),
|
||||||
|
|
||||||
// const CircularProgressIndicator(
|
|
||||||
// color: Colors.white,
|
|
||||||
// ),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ class AppDI {
|
|||||||
|
|
||||||
injector.registerSingleton<MyUserBloc>(
|
injector.registerSingleton<MyUserBloc>(
|
||||||
(() => MyUserBloc(myUserRepository: injector.get<UserRepository>())));
|
(() => MyUserBloc(myUserRepository: injector.get<UserRepository>())));
|
||||||
injector.registerSingleton(
|
|
||||||
(() => ScoreBloc(firebaseScoreRepository: injector.get())));
|
|
||||||
injector.registerSingleton<ProfileBloc>(
|
injector.registerSingleton<ProfileBloc>(
|
||||||
(() => ProfileBloc(userRepository: injector.get<UserRepository>())));
|
(() => ProfileBloc(userRepository: injector.get<UserRepository>())));
|
||||||
|
|
||||||
@@ -91,5 +90,17 @@ class AppDI {
|
|||||||
professionRepository: injector.get<FirebaseProfessionalRepository>(),
|
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!)
|
.where((element) => removeDiacritics(element.myUser.name!)
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.contains(removeDiacritics(_searchController.text.toLowerCase())))
|
.contains(removeDiacritics(_searchController.text.toLowerCase())))
|
||||||
.where((user) =>
|
// .where((user) =>
|
||||||
user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
|
// user.myUser.id != FirebaseAuth.instance.currentUser!.uid)
|
||||||
.toList();
|
.toList();
|
||||||
// } else {
|
// } else {
|
||||||
// filteredUsers = state.users
|
// filteredUsers = state.users
|
||||||
@@ -183,13 +183,20 @@ class _ProfessionalListScreenState extends State<ProfessionalListScreen> {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Row(
|
||||||
'${filteredUsers[index].myUser.name ?? ''}, ${filteredUsers[index].professionalInfo.profession}',
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
'${filteredUsers[index].myUser.name ?? ''}, ',
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Text(
|
||||||
|
filteredUsers[index].professionalInfo.profession,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
_disponibilidad(filteredUsers[index].professionalInfo),
|
_disponibilidad(filteredUsers[index].professionalInfo),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
|
|||||||
@@ -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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,9 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return BlocProvider(
|
||||||
|
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Calificación'),
|
title: const Text('Calificación'),
|
||||||
),
|
),
|
||||||
@@ -55,13 +57,17 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
children: [
|
children: [
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: _userInfoFuture,
|
future: _userInfoFuture,
|
||||||
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
|
builder:
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
(context, AsyncSnapshot<List<dynamic>> snapshot) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
if (snapshot.connectionState ==
|
||||||
|
ConnectionState.waiting) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator());
|
||||||
} else {
|
} else {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text('Error inesperado: ${snapshot.error}'),
|
child:
|
||||||
|
Text('Error inesperado: ${snapshot.error}'),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final userInfo = snapshot.data![0] as MyUser;
|
final userInfo = snapshot.data![0] as MyUser;
|
||||||
@@ -123,7 +129,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
|
|
||||||
return Positioned(
|
return Positioned(
|
||||||
top: 3,
|
top: 3,
|
||||||
right: MediaQuery.of(context).size.width *
|
right:
|
||||||
|
MediaQuery.of(context).size.width *
|
||||||
0.3,
|
0.3,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -136,8 +143,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
BorderRadius.circular(20),
|
BorderRadius.circular(20),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color:
|
color: Colors.black
|
||||||
Colors.black.withOpacity(0.1),
|
.withOpacity(0.1),
|
||||||
spreadRadius: 1,
|
spreadRadius: 1,
|
||||||
blurRadius: 2,
|
blurRadius: 2,
|
||||||
offset: const Offset(
|
offset: const Offset(
|
||||||
@@ -222,7 +229,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Text(
|
const Text(
|
||||||
'Califica el servicio',
|
'Califica el servicio',
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
style:
|
||||||
|
TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
RatingBar.builder(
|
RatingBar.builder(
|
||||||
@@ -292,14 +300,15 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
horizontal: 15,
|
horizontal: 15,
|
||||||
),
|
),
|
||||||
child: BlocBuilder<ServiceBloc, ServiceState>(
|
child: BlocBuilder<ServiceBloc, ServiceState>(
|
||||||
builder: (context, state) {
|
builder: (context, serviceState) {
|
||||||
return FilledButton(
|
return FilledButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final CommentEntity comment = widget.service.userId ==
|
final CommentEntity comment = widget.service.userId ==
|
||||||
FirebaseAuth.instance.currentUser!.uid
|
FirebaseAuth.instance.currentUser!.uid
|
||||||
? CommentEntity(
|
? CommentEntity(
|
||||||
serviceId: widget.service.id!,
|
serviceId: widget.service.id!,
|
||||||
authorId: FirebaseAuth.instance.currentUser!.uid,
|
authorId:
|
||||||
|
FirebaseAuth.instance.currentUser!.uid,
|
||||||
isFromUser: true,
|
isFromUser: true,
|
||||||
score: _rating,
|
score: _rating,
|
||||||
destinationId: widget.service.professionalId,
|
destinationId: widget.service.professionalId,
|
||||||
@@ -308,7 +317,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
)
|
)
|
||||||
: CommentEntity(
|
: CommentEntity(
|
||||||
serviceId: widget.service.id!,
|
serviceId: widget.service.id!,
|
||||||
authorId: FirebaseAuth.instance.currentUser!.uid,
|
authorId:
|
||||||
|
FirebaseAuth.instance.currentUser!.uid,
|
||||||
isFromUser: false,
|
isFromUser: false,
|
||||||
score: _rating,
|
score: _rating,
|
||||||
destinationId: widget.service.userId,
|
destinationId: widget.service.userId,
|
||||||
@@ -321,9 +331,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
|
|
||||||
if (widget.service.userId ==
|
if (widget.service.userId ==
|
||||||
FirebaseAuth.instance.currentUser!.uid) {
|
FirebaseAuth.instance.currentUser!.uid) {
|
||||||
context
|
context.read<ServiceBloc>().add(
|
||||||
.read<ServiceBloc>()
|
UpdateProfessionalScored(widget.service.id!));
|
||||||
.add(UpdateProfessionalScored(widget.service.id!));
|
|
||||||
} else {
|
} else {
|
||||||
context
|
context
|
||||||
.read<ServiceBloc>()
|
.read<ServiceBloc>()
|
||||||
@@ -357,6 +366,7 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
addComment(CommentEntity comment) async {
|
||||||
await commentsCollection.add(comment.toDocument());
|
await commentsCollection.add(comment.toDocument());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user