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,7 +11,9 @@ class DrawerReputation extends StatelessWidget {
|
||||
|
||||
@override
|
||||
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) {
|
||||
return builder(state.reputation);
|
||||
} else if (state is ScoreFailure) {
|
||||
@@ -18,6 +21,7 @@ class DrawerReputation extends StatelessWidget {
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 +51,9 @@ class GeneralDrawer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<MyUserBloc, MyUserState>(
|
||||
return BlocProvider(
|
||||
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||
child: BlocBuilder<MyUserBloc, MyUserState>(
|
||||
builder: (context, userState) {
|
||||
return BlocBuilder<ProfessionalBloc, ProfessionalState>(
|
||||
builder: (context, professionalState) {
|
||||
@@ -194,7 +200,8 @@ class GeneralDrawer extends StatelessWidget {
|
||||
color: const Color(0xFF2BA4EC),
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
shouldProModeActive(context, professionalState)
|
||||
shouldProModeActive(
|
||||
context, professionalState)
|
||||
? Navigator.pop(context)
|
||||
: Navigator.pop(context);
|
||||
},
|
||||
@@ -203,7 +210,8 @@ class GeneralDrawer extends StatelessWidget {
|
||||
color: Colors.white,
|
||||
),
|
||||
title: Text(
|
||||
shouldProModeActive(context, professionalState)
|
||||
shouldProModeActive(
|
||||
context, professionalState)
|
||||
? 'Solicitudes'
|
||||
: 'Solicitar servicio',
|
||||
style: const TextStyle(
|
||||
@@ -228,12 +236,29 @@ class GeneralDrawer extends StatelessWidget {
|
||||
: reputation.average;
|
||||
|
||||
return ListTile(
|
||||
onTap: () {},
|
||||
trailing: const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
||||
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: calculoRating(average),
|
||||
initialRating: 3,
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
@@ -293,6 +318,7 @@ class GeneralDrawer extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,13 +183,20 @@ class _ProfessionalListScreenState extends State<ProfessionalListScreen> {
|
||||
)
|
||||
: null,
|
||||
),
|
||||
title: Text(
|
||||
'${filteredUsers[index].myUser.name ?? ''}, ${filteredUsers[index].professionalInfo.profession}',
|
||||
title: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
'${filteredUsers[index].myUser.name ?? ''}, ',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
filteredUsers[index].professionalInfo.profession,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
_disponibilidad(filteredUsers[index].professionalInfo),
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
return BlocProvider(
|
||||
create: (context) => Injector.appInstance.get<ScoreBloc>(),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Calificación'),
|
||||
),
|
||||
@@ -55,13 +57,17 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: _userInfoFuture,
|
||||
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
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}'),
|
||||
child:
|
||||
Text('Error inesperado: ${snapshot.error}'),
|
||||
);
|
||||
} else {
|
||||
final userInfo = snapshot.data![0] as MyUser;
|
||||
@@ -123,7 +129,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
|
||||
return Positioned(
|
||||
top: 3,
|
||||
right: MediaQuery.of(context).size.width *
|
||||
right:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.3,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -136,8 +143,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.black.withOpacity(0.1),
|
||||
color: Colors.black
|
||||
.withOpacity(0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 2,
|
||||
offset: const Offset(
|
||||
@@ -222,7 +229,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'Califica el servicio',
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||
style:
|
||||
TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
RatingBar.builder(
|
||||
@@ -292,14 +300,15 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
horizontal: 15,
|
||||
),
|
||||
child: BlocBuilder<ServiceBloc, ServiceState>(
|
||||
builder: (context, state) {
|
||||
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,
|
||||
authorId:
|
||||
FirebaseAuth.instance.currentUser!.uid,
|
||||
isFromUser: true,
|
||||
score: _rating,
|
||||
destinationId: widget.service.professionalId,
|
||||
@@ -308,7 +317,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
)
|
||||
: CommentEntity(
|
||||
serviceId: widget.service.id!,
|
||||
authorId: FirebaseAuth.instance.currentUser!.uid,
|
||||
authorId:
|
||||
FirebaseAuth.instance.currentUser!.uid,
|
||||
isFromUser: false,
|
||||
score: _rating,
|
||||
destinationId: widget.service.userId,
|
||||
@@ -321,9 +331,8 @@ class _ScoreScreenState extends State<ScoreScreen> {
|
||||
|
||||
if (widget.service.userId ==
|
||||
FirebaseAuth.instance.currentUser!.uid) {
|
||||
context
|
||||
.read<ServiceBloc>()
|
||||
.add(UpdateProfessionalScored(widget.service.id!));
|
||||
context.read<ServiceBloc>().add(
|
||||
UpdateProfessionalScored(widget.service.id!));
|
||||
} else {
|
||||
context
|
||||
.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 {
|
||||
await commentsCollection.add(comment.toDocument());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user