Deleted the CurrentSelectionService and moved to route parameters

This commit is contained in:
Mariano Uvalle 2019-04-06 22:53:22 -06:00
parent b39a490384
commit dd13cebb80
9 changed files with 80 additions and 87 deletions

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'screens/event_screen.dart';
import 'screens/home_screen.dart'; import 'screens/home_screen.dart';
import 'screens/initial_loading_screen.dart'; import 'screens/initial_loading_screen.dart';
import 'screens/login_screen.dart'; import 'screens/login_screen.dart';
@ -49,6 +50,7 @@ class App extends StatelessWidget {
builder: (BuildContext context) { builder: (BuildContext context) {
return TaskScreen( return TaskScreen(
isEdit: true, isEdit: true,
taskId: routeTokens[1],
); );
}, },
); );
@ -58,6 +60,14 @@ class App extends StatelessWidget {
return NewImageScreen(); return NewImageScreen();
}, },
); );
} else if (routeTokens.first == 'event') {
return MaterialPageRoute(
builder: (BuildContext context) {
return EventScreen(
eventName: routeTokens[1],
);
},
);
} }
// Default route. // Default route.
return MaterialPageRoute( return MaterialPageRoute(

View file

@ -1,18 +1,16 @@
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart';
import '../resources/firestore_provider.dart'; import '../resources/firestore_provider.dart';
import '../resources/firebase_storage_provider.dart'; import '../resources/firebase_storage_provider.dart';
import '../services/current_selection_service.dart';
/// A business logic component that manages the state for an event screen. /// A business logic component that manages the state for an event screen.
class EventBloc { class EventBloc {
/// An instance of the current selection service. /// The name of the event being shown.
final CurrentSelectionService _selectionService = currentSelectionService; final String eventName;
EventBloc({
/// The name of the event that's currently selected. @required this.eventName,
/// });
/// Read only.
String get selectedEventName => _selectionService.event.name;
/// Fetches the tasks for the current user that a part of the currently /// Fetches the tasks for the current user that a part of the currently
/// selected event. /// selected event.

View file

@ -5,7 +5,6 @@ import 'package:rxdart/rxdart.dart';
import '../models/task_model.dart'; import '../models/task_model.dart';
import '../resources/firestore_provider.dart'; import '../resources/firestore_provider.dart';
import '../services/auth_service.dart'; import '../services/auth_service.dart';
import '../services/current_selection_service.dart';
export '../services/auth_service.dart' show FirebaseUser; export '../services/auth_service.dart' show FirebaseUser;
@ -19,9 +18,6 @@ class HomeBloc {
/// An instance of the firebase repository. /// An instance of the firebase repository.
final FirestoreProvider _firestore = firestoreProvider; final FirestoreProvider _firestore = firestoreProvider;
/// An instance of the current task service.
final CurrentSelectionService _selectionService = currentSelectionService;
/// A subject of list of task model. /// A subject of list of task model.
final _tasks = BehaviorSubject<List<TaskModel>>(); final _tasks = BehaviorSubject<List<TaskModel>>();
@ -113,19 +109,6 @@ class HomeBloc {
); );
} }
/// Sets the global selected task.
void updateSelectedTask(TaskModel task) {
_selectionService.updateSelectedTask(task);
}
/// Updated the global selected event.
void updateSelectedEvent(TaskModel task) async {
final userModel = await _auth.getCurrentUserModel();
final event =
await _firestore.getEvent(userModel.id, eventName: task.event);
_selectionService.updateSelectedEvent(event);
}
/// Updates the serach box text. /// Updates the serach box text.
void updateSearchBoxText(String newText) { void updateSearchBoxText(String newText) {
_searchBoxText.add(newText); _searchBoxText.add(newText);

View file

@ -7,7 +7,6 @@ import '../models/task_model.dart';
import '../models/user_model.dart'; import '../models/user_model.dart';
import '../resources/firestore_provider.dart'; import '../resources/firestore_provider.dart';
import '../services/auth_service.dart'; import '../services/auth_service.dart';
import '../services/current_selection_service.dart';
/// Business logic component that manages the state for the task screen. /// Business logic component that manages the state for the task screen.
class TaskBloc extends Object with Validators { class TaskBloc extends Object with Validators {
@ -17,19 +16,24 @@ class TaskBloc extends Object with Validators {
/// An instance of the firebase repository. /// An instance of the firebase repository.
final FirestoreProvider _firestore = firestoreProvider; final FirestoreProvider _firestore = firestoreProvider;
/// An instance of the current task service.
final CurrentSelectionService _selectionService = currentSelectionService;
/// A subject of user model. /// A subject of user model.
///
/// Needed to access the username of the owner of the task.
final _user = BehaviorSubject<UserModel>(); final _user = BehaviorSubject<UserModel>();
/// A subject of task event name. /// A subject of task event name.
///
/// Only needed if in edit mode. This will receive updates when the task to be
/// edited is fetched.
final _eventName = BehaviorSubject<String>(); final _eventName = BehaviorSubject<String>();
/// A subject of task text. /// A subject of task text.
final _taskText = BehaviorSubject<String>(); final _taskText = BehaviorSubject<String>();
/// A subject of the text of the current global task. /// A subject of the text of the current global task.
///
/// Only needed if in edit mode. This will receive updates when the task to be
/// edited is fetched.
final _textInitialValue = BehaviorSubject<String>(); final _textInitialValue = BehaviorSubject<String>();
/// The priority of the current task. /// The priority of the current task.
@ -37,10 +41,10 @@ class TaskBloc extends Object with Validators {
/// The id of the current task. /// The id of the current task.
/// ///
/// Only to be used if editing an existing task. /// Only needed if in edit mode. Not needed by the UI.
String taskId; final String taskId;
//Stream getters. // Stream getters.
/// An observable of the current user model. /// An observable of the current user model.
Observable<UserModel> get userModelStream => _user.stream; Observable<UserModel> get userModelStream => _user.stream;
@ -48,14 +52,20 @@ class TaskBloc extends Object with Validators {
Observable<String> get eventName => _eventName.stream; Observable<String> get eventName => _eventName.stream;
/// An observable of the current task text. /// An observable of the current task text.
///
/// Emits an error if the string added is empty.
Observable<String> get taskText => Observable<String> get taskText =>
_taskText.stream.transform(validateStringNotEmpty); _taskText.stream.transform(validateStringNotEmpty);
/// An observable of the submit enabled flag. /// An observable of the submit enabled flag.
///
/// Only emits true when an event is selected and the task text is not empty.
Observable<bool> get submitEnabled => Observable<bool> get submitEnabled =>
Observable.combineLatest2(eventName, taskText, (a, b) => true); Observable.combineLatest2(eventName, taskText, (a, b) => true);
/// An observable of the text of the global selected task. /// An observable of the text of the global selected task.
///
/// Only needed in edit mode.
Observable<String> get textInitialvalue => _textInitialValue.stream; Observable<String> get textInitialvalue => _textInitialValue.stream;
//Sinks getters. //Sinks getters.
@ -65,7 +75,7 @@ class TaskBloc extends Object with Validators {
///Changes the current task text. ///Changes the current task text.
Function(String) get changeTaskText => _taskText.sink.add; Function(String) get changeTaskText => _taskText.sink.add;
TaskBloc() { TaskBloc({this.taskId}) {
setCurrentUser(); setCurrentUser();
} }
@ -76,7 +86,6 @@ class TaskBloc extends Object with Validators {
//TODO: Figure out how to update the event and user properties if needed. //TODO: Figure out how to update the event and user properties if needed.
// as in the number of pending high tasks for example. // as in the number of pending high tasks for example.
/// Saves or updates the current task in the database. /// Saves or updates the current task in the database.
Future<void> submit(isEdit) { Future<void> submit(isEdit) {
if (isEdit) { if (isEdit) {
@ -105,17 +114,11 @@ class TaskBloc extends Object with Validators {
/// Grabs the data from the current global task and pipes it to the local /// Grabs the data from the current global task and pipes it to the local
/// streams. /// streams.
void populateWithCurrentTask() { void populateWithCurrentTask() async {
// We only want the task that was just selected and stop listening final task = await _firestore.getTask(taskId);
// after receiving it. _textInitialValue.sink.add(task.text);
_selectionService.task.take(1).listen( changeEventName(task.event);
(TaskModel task) { changeTaskText(task.text);
_textInitialValue.sink.add(task.text);
changeEventName(task.event);
changeTaskText(task.text);
taskId = task.id;
},
);
} }
void dispose() { void dispose() {

View file

@ -129,7 +129,7 @@ class FirestoreProvider {
} }
/// Returns a Stream of a single task from an id. /// Returns a Stream of a single task from an id.
Observable<TaskModel> getTask(String id) { Observable<TaskModel> getTaskObservable(String id) {
final mappedStream = final mappedStream =
_firestore.collection('tasks').document(id).snapshots().map( _firestore.collection('tasks').document(id).snapshots().map(
(DocumentSnapshot snapshot) { (DocumentSnapshot snapshot) {
@ -143,6 +143,16 @@ class FirestoreProvider {
return Observable(mappedStream); return Observable(mappedStream);
} }
//TODO: Add tests for this method.
/// Returns a task from an id.
Future<TaskModel> getTask(String id) async {
final documentSnapshot = await _firestore.document('tasks/$id').get();
return TaskModel.fromFirestore(
documentSnapshot.data,
id: documentSnapshot.documentID,
);
}
/// Deletes a task from firestore. /// Deletes a task from firestore.
Future<void> deleteTask(String id) async { Future<void> deleteTask(String id) async {
try { try {

View file

@ -4,15 +4,28 @@ import '../blocs/event_bloc.dart';
import '../widgets/custom_app_bar.dart'; import '../widgets/custom_app_bar.dart';
class EventScreen extends StatefulWidget { class EventScreen extends StatefulWidget {
/// The name of the event this screenn is showing.
final String eventName;
EventScreen({
@required this.eventName,
});
_EventScreenState createState() => _EventScreenState(); _EventScreenState createState() => _EventScreenState();
} }
class _EventScreenState extends State<EventScreen> { class _EventScreenState extends State<EventScreen> {
final EventBloc bloc = EventBloc(); EventBloc bloc;
initState() {
super.initState();
bloc = EventBloc(eventName: widget.eventName);
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: '', title: widget.eventName,
), ),
); );
} }

View file

@ -93,11 +93,12 @@ class _HomeScreenState extends State<HomeScreen> {
task: task, task: task,
onDone: () => bloc.markTaskAsDone(task), onDone: () => bloc.markTaskAsDone(task),
onEventPressed: () { onEventPressed: () {
bloc.updateSelectedEvent(task); // Include the event name in the route.
Navigator.of(context).pushNamed('event/${task.event}');
}, },
onEditPressed: () { onEditPressed: () {
bloc.updateSelectedTask(task); // Include the id of the task to be edited in the route.
Navigator.of(context).pushNamed('editTask/'); Navigator.of(context).pushNamed('editTask/${task.id}');
}, },
), ),
padding: EdgeInsets.only(bottom: 12), padding: EdgeInsets.only(bottom: 12),

View file

@ -14,8 +14,15 @@ class TaskScreen extends StatefulWidget {
/// Wether the Screen is going to edit a current task or create a new one. /// Wether the Screen is going to edit a current task or create a new one.
final bool isEdit; final bool isEdit;
/// Id of the task to edit if in edit mode.
final String taskId;
/// Creates a screen capable of editing of creating a new task.
///
/// [taskId] must be provided and cannot be null if [isEdit] is set to true.
TaskScreen({ TaskScreen({
this.isEdit = false, this.isEdit = false,
this.taskId,
}); });
@override @override
@ -24,11 +31,14 @@ class TaskScreen extends StatefulWidget {
class _TaskScreenState extends State<TaskScreen> { class _TaskScreenState extends State<TaskScreen> {
/// An instance of this screen's bloc. /// An instance of this screen's bloc.
final TaskBloc bloc = TaskBloc(); TaskBloc bloc;
initState() { initState() {
if (widget.isEdit) { if (widget.isEdit) {
bloc = TaskBloc(taskId: widget.taskId);
bloc.populateWithCurrentTask(); bloc.populateWithCurrentTask();
} else {
bloc = TaskBloc();
} }
super.initState(); super.initState();
} }

View file

@ -1,35 +0,0 @@
import 'package:rxdart/rxdart.dart';
import '../models/event_model.dart';
import '../models/task_model.dart';
/// A service that keeps track of the current user selection.
///
/// When editing a task or when navigating to an event screen, the new screens
/// can grab the user selection for this service.
class CurrentSelectionService {
/// The current selected task.
final _selectedTask = BehaviorSubject<TaskModel>();
/// The current selected event.
final _selectedEvent = BehaviorSubject<EventModel>();
/// An observable of the current selected event.
Observable<TaskModel> get task => _selectedTask.stream;
/// The current selected event.
Observable<EventModel> get event => _selectedEvent.stream;
/// Updates the current selected task.
Function(TaskModel) get updateSelectedTask => _selectedTask.sink.add;
// Updates the current selected event.
Function(EventModel) get updateSelectedEvent => _selectedEvent.sink.add;
dispose() {
_selectedEvent.close();
_selectedTask.close();
}
}
final currentSelectionService = CurrentSelectionService();