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

feat: Allow leader to change beacon duration, and deactivate the beacon. #97

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion lib/components/beacon_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class BeaconCustomWidgets {
TextSpan(
text: 'in ',
style: TextStyle(
color: const Color(0xffb6b2df),
color: Color(0xffb6b2df),
fontSize: 14.0,
fontWeight: FontWeight.w400),
),
Expand Down
6 changes: 3 additions & 3 deletions lib/components/create_join_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import 'package:sizer/sizer.dart';
class CreateJoinBeaconDialog {
static Future createHikeDialog(BuildContext context, HomeViewModel model) {
model.resultingDuration = Duration(minutes: 30);
model.durationController = new TextEditingController();
model.startsAtDate = new TextEditingController();
model.startsAtTime = new TextEditingController();
model.durationController = TextEditingController();
model.startsAtDate = TextEditingController();
model.startsAtTime = TextEditingController();
return showDialog(
context: context,
builder: (context) => Dialog(
Expand Down
171 changes: 145 additions & 26 deletions lib/components/dialog_boxes.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:beacon/components/hike_button.dart';
import 'package:beacon/locator.dart';
import 'package:beacon/utilities/constants.dart';
import 'package:beacon/view_model/hike_screen_model.dart';
import 'package:flutter/material.dart';
import 'package:sizer/sizer.dart';

Expand Down Expand Up @@ -45,48 +46,166 @@ class DialogBoxes {
);
}

static Future changeDurationDialog(BuildContext context) {
static Future<DateTime> changeDurationDialog(
BuildContext context,
HikeScreenViewModel model,
) {
DateTime dateTime;
TimeOfDay timeOfDay;
var startsAtDate = TextEditingController();
var startsAtTime = TextEditingController();
return showDialog(
context: context,
builder: (context) => Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Container(
height: 500,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Container(
color: kLightBlue,
child: Column(
children: <Widget>[
Text(
'Change Beacon Duration',
style: TextStyle(color: kYellow, fontSize: 14.0),
SizedBox(
height: 2.h,
),
Container(
child: Text(
'Choose End Date-Time',
style: TextStyle(color: kYellow, fontSize: 15.0),
),
),
SizedBox(
height: 2.h,
),
Container(
color: kLightBlue,
height: 10.h,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: InkWell(
onTap: () async {
dateTime = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
);
startsAtDate.text =
dateTime.toString().substring(0, 10);
},
child: TextFormField(
enabled: false,
controller: startsAtDate,
onChanged: (value) {
startsAtDate.text =
dateTime.toString().substring(0, 10);
},
decoration: InputDecoration(
alignLabelWithHint: true,
errorStyle: TextStyle(color: Colors.red[800]),
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: 'End Date',
labelStyle:
TextStyle(fontSize: labelsize, color: kYellow),
hintStyle:
TextStyle(fontSize: hintsize, color: hintColor),
hintText: 'Choose end date',
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
),
SizedBox(
height: 2.h,
),
Container(
height: 10.h,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: InkWell(
onTap: () async {
timeOfDay = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
startsAtTime.text =
timeOfDay.toString().substring(10, 15);
},
child: TextFormField(
enabled: false,
controller: startsAtTime,
onChanged: (value) {
startsAtTime.text =
timeOfDay.toString().substring(10, 15);
},
decoration: InputDecoration(
alignLabelWithHint: true,
errorStyle: TextStyle(color: Colors.red[800]),
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: 'End Time',
labelStyle:
TextStyle(fontSize: labelsize, color: kYellow),
hintStyle:
TextStyle(fontSize: hintsize, color: hintColor),
hintText: 'Choose End time',
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
],
),
),
),
color: kLightBlue,
),
SizedBox(
height: 3.h,
height: 4.h,
),
HikeButton(
buttonWidth: optbwidth,
text: 'Done',
textSize: 18.0,
textColor: Colors.white,
buttonColor: kYellow,
onTap: () async {
if (dateTime == null || timeOfDay == null) {
navigationService.showSnackBar("Enter date and time");
return;
}
dateTime = DateTime(
dateTime.year,
dateTime.month,
dateTime.day,
timeOfDay.hour,
timeOfDay.minute,
);
// localNotif.scheduleNotification();
if (DateTime.fromMillisecondsSinceEpoch(
model.beacon.startsAt)
.isAfter(dateTime)) {
navigationService
.showSnackBar("Enter a valid date and time!!");
return;
}
// DateTime newTime =
// DateTime.now().add(newDuration);
// update time
await databaseFunctions.init();
final updatedBeacon =
await databaseFunctions.changeBeaconDuration(
model.beacon.id,
dateTime.millisecondsSinceEpoch,
);
if (updatedBeacon != null) {
model.updateBeaconDuration(
dateTime.millisecondsSinceEpoch);
}
Navigator.pop(context, dateTime);
},
),
Flexible(
child: HikeButton(
buttonWidth: optbwidth,
text: 'Done',
textSize: 18.0,
textColor: Colors.white,
buttonColor: kYellow,
onTap: () {
// DateTime newTime =
// DateTime.now().add(newDuration);
// update time
Navigator.pop(context);
}),
SizedBox(
height: 2.h,
),
],
),
Expand Down
2 changes: 1 addition & 1 deletion lib/components/hike_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class HikeButton extends StatelessWidget {
style: ElevatedButton.styleFrom(
primary: buttonColor,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(50.0),
borderRadius: BorderRadius.circular(50.0),
side: BorderSide(color: borderColor)),
),
child: Padding(
Expand Down
11 changes: 6 additions & 5 deletions lib/components/hike_screen_widget.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';

import 'package:beacon/components/dialog_boxes.dart';
import 'package:beacon/components/hike_button.dart';
import 'package:beacon/locator.dart';
import 'package:beacon/models/beacon/beacon.dart';
Expand Down Expand Up @@ -244,14 +245,14 @@ class HikeScreenWidget {
trailing: model.hikers[index].id == model.beacon.leader.id
? GestureDetector(
onDoubleTap: () {
Aadeesh11 marked this conversation as resolved.
Show resolved Hide resolved
isLeader
!isLeader
? Fluttertoast.showToast(
msg:
'Only beacon holder has access to change the duration')
//TODO: enable this once backend has updated.
//Commented, since we dont have the neccessary mutation atm on backend to change the duration.
// : DialogBoxes.changeDurationDialog(context);
: Container();
: DialogBoxes.changeDurationDialog(
context,
model,
);
},
child: Icon(
Icons.room,
Expand Down
34 changes: 34 additions & 0 deletions lib/queries/beacon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,40 @@ class BeaconQueries {
''';
}

String changeBeaconDuration(String id, int newExpiresAt) {
return '''
mutation{
changeBeaconDuration(newExpiresAt: $newExpiresAt, beaconID: "$id")
{
_id
title
shortcode
leader {
_id
name
}
location{
lat
lon
}
followers {
_id
name
}
startsAt
expiresAt
landmarks {
title
location {
lat
lon
}
}
}
}
''';
}

String updateLeaderLoc(String id, String lat, String lon) {
return '''
mutation {
Expand Down
32 changes: 32 additions & 0 deletions lib/services/database_mutation_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class DataBaseMutationFunctions {
const GraphQLError(message: 'Email address already exists');
GraphQLError wrongCredentials =
const GraphQLError(message: 'Invalid credentials');
GraphQLError beaconHasAlreadyExpired = const GraphQLError(
message: 'Beacon can not expire before it has started.');

bool encounteredExceptionOrError(OperationException exception,
{bool showSnackBar = true}) {
Expand Down Expand Up @@ -64,6 +66,12 @@ class DataBaseMutationFunctions {
.showSnackBar("Account with this email already registered");
}
return false;
} else if (exception.graphqlErrors[i].message ==
beaconHasAlreadyExpired.message) {
if (showSnackBar) {
navigationService.showSnackBar(beaconHasAlreadyExpired.message);
}
return false;
}
}
print("Something went wrong");
Expand Down Expand Up @@ -246,6 +254,30 @@ class DataBaseMutationFunctions {
return null;
}

Future<Beacon> changeBeaconDuration(String id, int newExpiresAt) async {
final QueryResult result = await clientAuth.mutate(
MutationOptions(
Aadeesh11 marked this conversation as resolved.
Show resolved Hide resolved
document: gql(
_beaconQuery.changeBeaconDuration(
id,
newExpiresAt,
),
),
),
);
if (result.hasException) {
navigationService.showSnackBar(
"Something went wrong: ${result.exception.graphqlErrors.first.message}");
print("Something went wrong: ${result.exception}");
} else if (result.data != null && result.isConcrete) {
final Beacon beacon = Beacon.fromJson(
result.data['changeBeaconDuration'] as Map<String, dynamic>,
);
return beacon;
}
return null;
}

Future<Location> updateLeaderLoc(String id, LatLng latLng) async {
final QueryResult result = await clientAuth.mutate(MutationOptions(
document: gql(_beaconQuery.updateLeaderLoc(
Expand Down
2 changes: 1 addition & 1 deletion lib/splash_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class _SplashScreenState extends State<SplashScreen> {
return Scaffold(
key: const Key('SplashScreenScaffold'),
body: Center(
child: new Image(image: new AssetImage('images/hikers_group.png')),
child: Image(image: AssetImage('images/hikers_group.png')),
),
);
}
Expand Down
15 changes: 7 additions & 8 deletions lib/utilities/indication_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class TabIndicationPainter extends CustomPainter {
this.dy = 25.0,
this.pageController})
: super(repaint: pageController) {
painter = new Paint()
painter = Paint()
..color = kBlue
..style = PaintingStyle.fill;
}
Expand All @@ -33,16 +33,15 @@ class TabIndicationPainter extends CustomPainter {
double pageOffset = pos.extentBefore / fullExtent;

bool left2right = dxEntry < dxTarget;
Offset entry = new Offset(left2right ? dxEntry : dxTarget, dy);
Offset target = new Offset(left2right ? dxTarget : dxEntry, dy);
Offset entry = Offset(left2right ? dxEntry : dxTarget, dy);
Offset target = Offset(left2right ? dxTarget : dxEntry, dy);

Path path = new Path();
Path path = Path();
path.addArc(
new Rect.fromCircle(center: entry, radius: radius), 0.5 * pi, 1 * pi);
path.addRect(
new Rect.fromLTRB(entry.dx, dy - radius, target.dx, dy + radius));
Rect.fromCircle(center: entry, radius: radius), 0.5 * pi, 1 * pi);
path.addRect(Rect.fromLTRB(entry.dx, dy - radius, target.dx, dy + radius));
path.addArc(
new Rect.fromCircle(center: target, radius: radius), 1.5 * pi, 1 * pi);
Rect.fromCircle(center: target, radius: radius), 1.5 * pi, 1 * pi);

canvas.translate(size.width * pageOffset, 0.0);
canvas.drawShadow(path, kLightBlue, 3.0, true);
Expand Down
Loading