Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented history page night selection for deletion #62

Merged
merged 9 commits into from
Nov 12, 2020
33 changes: 29 additions & 4 deletions mobile/lib/src/application/sleep_history/sleep_history_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import 'sleep_history_state.dart';
class SleepHistoryCubit extends Cubit<SleepHistoryState> {
final ISleepHistoryRepository _sleepHistoryRepository;

List<NightStats> _localHistory;
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved
StreamSubscription<List<NightStats>> _sleepHistoryStream;
// todo: remove this variable, also test that switch works correctly once UI is done
bool usingBluetooth = true;
List<NightStats> _selectedNights;
bool _selectMode = false;

SleepHistoryCubit(this._sleepHistoryRepository)
: super(SleepHistoryInitial()) {
Expand All @@ -24,10 +25,34 @@ class SleepHistoryCubit extends Cubit<SleepHistoryState> {
_sleepHistoryStream ??= _sleepHistoryRepository
.watch()
.asBroadcastStream()
.listen((history) => emit(SleepHistoryLoaded(history)));
.listen((history) => {
_localHistory = history,
emit(SleepHistoryLoaded(history, _selectedNights))
});
}

void viewNight(NightStats night) {
_sleepHistoryRepository.viewNight(night);
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved
}

void toggleSelectMode() {
_selectMode = !_selectMode;
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved

_selectedNights = _selectMode ? [] : null;

emit(SleepHistoryLoaded(_localHistory, _selectedNights));
}

void selectNight(NightStats night) {
_sleepHistoryRepository.selectNight(night);
var idx = _selectedNights.indexOf(night);

idx == -1 ? _selectedNights.add(night) : _selectedNights.remove(night);

emit(SleepHistoryLoaded(_localHistory, _selectedNights));
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved
}

void deleteSelected() {
_sleepHistoryRepository.deleteNights(_selectedNights);
toggleSelectMode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class SleepHistoryInitial extends SleepHistoryState {}

class SleepHistoryLoaded extends SleepHistoryState {
final List<NightStats> history;
final List<NightStats> selectedNights;

SleepHistoryLoaded(this.history);
SleepHistoryLoaded(this.history, this.selectedNights);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import 'night_stats.dart';
abstract class ISleepHistoryRepository {
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved
void initializeRepository();
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved

void selectNight(NightStats stat);
void viewNight(NightStats stat);

Stream<NightStats> getSelectedNight();

void deleteNights(List<NightStats> nights);

Stream<List<NightStats>> watch();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@ class SleepHistoryRepository implements ISleepHistoryRepository {
}

@override
void selectNight(NightStats stat) {
void viewNight(NightStats stat) {
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved
nightStreamController.add(stat);
}

@override
Stream<NightStats> getSelectedNight() => nightStreamController.stream;

@override
void deleteNights(List<NightStats> nights) {
for (var night in nights) {
_sleepHistoryPersistency.remove(night);
}

streamController.add(_sleepHistoryPersistency);
}

@override
Stream<List<NightStats>> watch() {
return streamController.stream;
MouradLachhab marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
35 changes: 35 additions & 0 deletions mobile/lib/src/presentation/pages/night_stats_page/app_bar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

Widget buildAppBar(var appBloc) {
return AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
title: StreamBuilder<Object>(
stream: appBloc.titleStream,
initialData: 'Night Stat',
builder: (context, snapshot) {
return Text(
snapshot.data,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
);
}),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {/* todo: Add export */},
child: Icon(
Icons.share,
size: 26.0,
),
)),
],
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:polydodo/src/application/night_stats/night_stats_cubit.dart';
import 'package:polydodo/src/application/night_stats/night_stats_state.dart';
import 'package:polydodo/src/presentation/navigation/navdrawer_tabs.dart';
import 'package:polydodo/src/presentation/navigation/navdrawer_widget.dart';
import 'package:polydodo/src/presentation/pages/night_stats_page/app_bar.dart';
import 'package:polydodo/src/presentation/pages/night_stats_page/metric_section.dart';
import 'package:polydodo/src/presentation/pages/night_stats_page/sleep_stages_section.dart';

Expand All @@ -17,36 +18,7 @@ class NightStatsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
title: StreamBuilder<Object>(
stream: appBloc.titleStream,
initialData: 'Night Stat',
builder: (context, snapshot) {
return Text(
snapshot.data,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
);
}),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {/* todo: Add export */},
child: Icon(
Icons.share,
size: 26.0,
),
)),
],
),
appBar: buildAppBar(appBloc),
drawer: NavDrawer(activeTab: NavdrawerTab.NightStats),
body: BlocConsumer<NightStatsCubit, NightStatsState>(
listener: (context, state) {
Expand Down
42 changes: 42 additions & 0 deletions mobile/lib/src/presentation/pages/sleep_history_page/app_bar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'package:flutter/material.dart';

Widget buildAppBar(var historyCubit, var appBloc) {
return AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
title: Text(
'History',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20.0, right: 20.0),
child: GestureDetector(
onTap: () => historyCubit.toggleSelectMode(),
child: _buildSelectButton(appBloc),
)),
],
);
}

Widget _buildSelectButton(var appBloc) {
return StreamBuilder<Object>(
stream: appBloc.selectStream,
initialData: 'Select',
builder: (context, snapshot) {
return Text(
snapshot.data,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: Colors.black,
),
);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:polydodo/src/presentation/navigation/routes/router.gr.dart';

Widget buildHistoryList(var context, var state, var historyCubit) {
return ListView.builder(
itemCount: state.history.length,
itemBuilder: (context, index) {
return _buildItemCard(context, state, historyCubit, index);
});
}

Widget _buildItemCard(var context, var state, var historyCubit, var index) {
var selectMode = state.selectedNights != null;

return Card(
child: ListTile(
onTap: () => {
if (selectMode)
{
historyCubit.selectNight(state.history[index]),
}
else
{
historyCubit.viewNight(state.history[index]),
ExtendedNavigator.of(context).replace(Routes.nightStatsPage)
}
},
title: Text(state.history[index].id.toString()),
trailing: _buildTrailing(state, selectMode, state.history[index]),
));
}

Widget _buildTrailing(var state, var selectMode, var night) {
if (selectMode) {
return state.selectedNights.contains(night)
? Icon(
Icons.check_circle_outline,
color: Colors.blue,
)
: Icon(Icons.check_circle_outline);
} else {
return Icon(Icons.navigate_next);
}
}
Original file line number Diff line number Diff line change
@@ -1,56 +1,68 @@
import 'package:auto_route/auto_route.dart';
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:polydodo/src/application/sleep_history/sleep_history_cubit.dart';
import 'package:polydodo/src/application/sleep_history/sleep_history_state.dart';
import 'package:polydodo/src/presentation/navigation/navdrawer_tabs.dart';
import 'package:polydodo/src/presentation/navigation/navdrawer_widget.dart';
import 'package:polydodo/src/presentation/navigation/routes/router.gr.dart';
import 'package:polydodo/src/presentation/pages/sleep_history_page/app_bar.dart';
import 'package:polydodo/src/presentation/pages/sleep_history_page/sleep_history_list.dart';

class SleepHistoryPage extends StatelessWidget {
final appBloc = AppPropertiesBloc();

@override
Widget build(BuildContext context) {
final historyCubit = BlocProvider.of<SleepHistoryCubit>(context);

return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
title: Text(
'History',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
),
drawer: NavDrawer(activeTab: NavdrawerTab.History),
body: BlocConsumer<SleepHistoryCubit, SleepHistoryState>(
listener: (context, state) {
appBar: buildAppBar(historyCubit, appBloc),
drawer: NavDrawer(activeTab: NavdrawerTab.History),
body: BlocConsumer<SleepHistoryCubit, SleepHistoryState>(
listener: (context, state) {
print(state.runtimeType);
},
builder: (context, state) {
}, builder: (context, state) {
if (state is SleepHistoryLoaded) {
return ListView.builder(
itemCount: state.history.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
onTap: () => {
BlocProvider.of<SleepHistoryCubit>(context)
.selectNight(state.history[index]),
ExtendedNavigator.of(context)
.replace(Routes.nightStatsPage)
},
title: Text(state.history[index].id.toString()),
));
});
appBloc.updateSelectText(state.selectedNights != null);

return buildHistoryList(context, state, historyCubit);
} else {
return Container();
}
},
),
);
}),
floatingActionButton: _buildFloatingActionButton(historyCubit));
}
}

class AppPropertiesBloc {
WilliamHarvey97 marked this conversation as resolved.
Show resolved Hide resolved
final StreamController<String> _select = StreamController<String>();

Stream<String> get selectStream => _select.stream;

void updateSelectText(bool selectMode) {
_select.sink.add(selectMode ? 'Done' : 'Select');
}

void dispose() {
_select.close();
}
}

Widget _buildFloatingActionButton(var historyCubit) {
return BlocConsumer<SleepHistoryCubit, SleepHistoryState>(
listener: (context, state) => {},
builder: (context, state) {
if (state is SleepHistoryLoaded) {
return Visibility(
visible: (state.selectedNights?.isNotEmpty ?? false),
child: FloatingActionButton(
onPressed: () => historyCubit.deleteSelected(),
child: Icon(Icons.delete),
backgroundColor: Colors.red,
));
} else {
return Container();
}
});
}