Skip to content

Commit 9e849af

Browse files
committed
Add pending invites to devices page
1 parent 78804c3 commit 9e849af

5 files changed

Lines changed: 108 additions & 40 deletions

File tree

lib/screens/shockers/grouped/grouped_shockers.dart

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import 'dart:math';
33
import 'package:flutter/material.dart';
44
import 'package:shock_alarm_app/components/constrained_container.dart';
55
import 'package:shock_alarm_app/components/desktop_mobile_refresh_indicator.dart';
6+
import 'package:shock_alarm_app/components/predefined_spacing.dart';
67
import 'package:shock_alarm_app/dialogs/yes_cancel_dialog.dart';
78
import 'package:shock_alarm_app/screens/shockers/grouped/grouped_shocker_selector.dart';
89
import 'package:shock_alarm_app/screens/shockers/live/live_controls.dart';
910
import 'package:shock_alarm_app/screens/shockers/shocker_item.dart';
1011
import 'package:shock_alarm_app/dialogs/error_dialog.dart';
1112
import 'package:shock_alarm_app/screens/screen_selector.dart';
1213
import 'package:shock_alarm_app/screens/logs/logs.dart';
14+
import 'package:shock_alarm_app/screens/user_shares/invites_screen.dart';
1315
import 'package:shock_alarm_app/services/alarm_manager.dart';
1416
import 'package:shock_alarm_app/services/limits.dart';
1517
import 'package:shock_alarm_app/services/openshockws.dart';
@@ -25,8 +27,7 @@ class GroupedShockerScreen extends StatefulWidget {
2527
int confirmedNumber = -1;
2628
bool dialogShowing = false;
2729

28-
GroupedShockerScreen({Key? key, required this.manager})
29-
: super(key: key);
30+
GroupedShockerScreen({Key? key, required this.manager}) : super(key: key);
3031

3132
@override
3233
State<StatefulWidget> createState() => _GroupedShockerScreenState();
@@ -59,9 +60,9 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
5960
}
6061

6162
void executeAllLive(ControlType type, int intensity) {
62-
// Enforce the limit of the confirm ui
63+
// Enforce the limit of the confirm ui
6364
// If the hard limit is on we do not need to show the dialog. redundancy is the limit function of the Controls themselves
64-
65+
6566
// The cofirm limits check is now performed in the call to this method so it applies to everything that uses the live controls ui instead of just this view
6667
List<Control> controls = [];
6768
for (Shocker s in AlarmListManager.getInstance().getSelectedShockers()) {
@@ -74,7 +75,8 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
7475
List<Control> controls = [];
7576
for (Shocker s in AlarmListManager.getInstance().getSelectedShockers()) {
7677
controls.add(
77-
s.getLimitedControls(ControlType.stop, maxIntensity, durationInMs)..duration = min(durationInMs, OpenShockLimits.maxDuration));
78+
s.getLimitedControls(ControlType.stop, maxIntensity, durationInMs)
79+
..duration = min(durationInMs, OpenShockLimits.maxDuration));
7880
}
7981
// we create a log entry for transparency with the other user
8082
if (AlarmListManager.getInstance().settings.liveControlsLogWorkaround) {
@@ -101,7 +103,9 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
101103
for (Shocker s in AlarmListManager.getInstance().getSelectedShockers()) {
102104
if (!s.isOwn) continue;
103105
shockerCount++;
104-
OpenShockClient().setPauseStateOfShocker(s, AlarmListManager.getInstance(), pause).then((error) {
106+
OpenShockClient()
107+
.setPauseStateOfShocker(s, AlarmListManager.getInstance(), pause)
108+
.then((error) {
105109
completedShockers++;
106110
if (error != null) {
107111
ErrorDialog.show("Failed to pause shocker", error);
@@ -158,15 +162,16 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
158162
@override
159163
Widget build(BuildContext context) {
160164
AlarmListManager.getInstance().reloadAllMethod = () {
161-
if(!mounted) return;
165+
if (!mounted) return;
162166
setState(() {});
163167
};
164168
ThemeData t = Theme.of(context);
165169
bool isOwnShocker = canResume() || canPause();
166170
List<ShockerAction> actions = isOwnShocker
167171
? ShockerItem.ownShockerActions
168172
: ShockerItem.foreignShockerActions;
169-
Shocker limitedShocker = AlarmListManager.getInstance().getSelectedShockerLimits();
173+
Shocker limitedShocker =
174+
AlarmListManager.getInstance().getSelectedShockerLimits();
170175

171176
return DesktopMobileRefreshIndicator(
172177
onRefresh: () async {
@@ -176,6 +181,9 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
176181
child: Flex(
177182
direction: Axis.vertical,
178183
children: [
184+
InineInviteManager(reloadMethod: () => setState(() {
185+
186+
}),),
179187
GroupedShockerSelector(onChanged: onRebuild, onlyLive: liveEnabled),
180188
if (AlarmListManager.getInstance().selectedShockers.isNotEmpty)
181189
ConstrainedContainer(
@@ -203,8 +211,10 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
203211
onPressed: () {
204212
List<Shocker> shockers = [];
205213
for (String shockerId
206-
in AlarmListManager.getInstance().selectedShockers) {
207-
Shocker s = AlarmListManager.getInstance().shockers
214+
in AlarmListManager.getInstance()
215+
.selectedShockers) {
216+
Shocker s = AlarmListManager.getInstance()
217+
.shockers
208218
.firstWhere((x) => x.id == shockerId);
209219
if (!s.isOwn) continue;
210220
shockers.add(s);
@@ -214,7 +224,8 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
214224
MaterialPageRoute(
215225
builder: (context) => LogScreen(
216226
shockers: shockers,
217-
manager: AlarmListManager.getInstance())));
227+
manager:
228+
AlarmListManager.getInstance())));
218229
},
219230
child: Text("View logs"),
220231
),
@@ -223,12 +234,17 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
223234
itemBuilder: (context) {
224235
return [
225236
for (ShockerAction a in actions)
226-
if (AlarmListManager.getInstance().selectedShockers.length == 1 || a.allowMultipleShockers) PopupMenuItem(
227-
value: a.name,
228-
child: Row(
229-
spacing: 10,
230-
children: [a.icon, Text(a.name)],
231-
)),
237+
if (AlarmListManager.getInstance()
238+
.selectedShockers
239+
.length ==
240+
1 ||
241+
a.allowMultipleShockers)
242+
PopupMenuItem(
243+
value: a.name,
244+
child: Row(
245+
spacing: 10,
246+
children: [a.icon, Text(a.name)],
247+
)),
232248
PopupMenuItem(
233249
value: "live",
234250
child: Row(
@@ -244,13 +260,16 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
244260
},
245261
onSelected: (String value) {
246262
List<Shocker> shockers = [];
247-
for(String id in AlarmListManager.getInstance().selectedShockers) {
248-
shockers.add(AlarmListManager.getInstance().shockers.firstWhere(
249-
(x) => x.id == id));
263+
for (String id in AlarmListManager.getInstance()
264+
.selectedShockers) {
265+
shockers.add(AlarmListManager.getInstance()
266+
.shockers
267+
.firstWhere((x) => x.id == id));
250268
}
251269
for (ShockerAction a in actions) {
252270
if (a.name == value) {
253-
a.onClick(AlarmListManager.getInstance(), shockers, context, onRebuild);
271+
a.onClick(AlarmListManager.getInstance(),
272+
shockers, context, onRebuild);
254273
return;
255274
}
256275
}
@@ -263,7 +282,8 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
263282
ShockerItem.ensureSafety();
264283
liveEnabled = !liveEnabled;
265284
if (!liveEnabled) {
266-
AlarmListManager.getInstance().disconnectAllFromLiveControlGateway();
285+
AlarmListManager.getInstance()
286+
.disconnectAllFromLiveControlGateway();
267287
}
268288
});
269289
}
@@ -282,11 +302,10 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
282302
ErrorDialog.show(
283303
"Error connecting to hubs", error.error!);
284304
}
285-
setState(() {
286-
287-
});
305+
setState(() {});
288306
},
289-
hubConnected: AlarmListManager.getInstance().areSelectedShockersConnected(),
307+
hubConnected: AlarmListManager.getInstance()
308+
.areSelectedShockersConnected(),
290309
onSendLive: executeAllLive,
291310
soundAllowed: limitedShocker.soundAllowed,
292311
vibrateAllowed: limitedShocker.vibrateAllowed,
@@ -297,7 +316,8 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
297316
)
298317
: ShockingControls(
299318
manager: AlarmListManager.getInstance(),
300-
controlsContainer: AlarmListManager.getInstance().controls,
319+
controlsContainer:
320+
AlarmListManager.getInstance().controls,
301321
durationLimit: limitedShocker.durationLimit,
302322
intensityLimit: limitedShocker.intensityLimit,
303323
soundAllowed: limitedShocker.soundAllowed,
@@ -316,4 +336,4 @@ class _GroupedShockerScreenState extends State<GroupedShockerScreen> {
316336
],
317337
));
318338
}
319-
}
339+
}

lib/screens/shockers/individual/shockers.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:shock_alarm_app/dialogs/info_dialog.dart';
1515
import 'package:shock_alarm_app/dialogs/loading_dialog.dart';
1616
import 'package:shock_alarm_app/screens/screen_selector.dart';
1717
import 'package:shock_alarm_app/screens/shares/shares.dart';
18+
import 'package:shock_alarm_app/screens/user_shares/invites_screen.dart';
1819
import 'package:shock_alarm_app/services/alarm_list_manager.dart';
1920
import 'package:shock_alarm_app/services/openshock.dart';
2021
import 'package:shock_alarm_app/services/vibrations.dart';
@@ -364,6 +365,10 @@ class ShockerScreenState extends State<ShockerScreen> {
364365
child: Column(
365366
children: [
366367
Expanded(child: SingleChildScrollView(child: Column(children: [
368+
InineInviteManager(reloadMethod: () => setState(() {
369+
370+
}),),
371+
Padding(padding: PredefinedSpacing.paddingLarge()),
367372
Text(
368373
'All devices',
369374
style: t.textTheme.headlineMedium,

lib/screens/user_shares/invites_screen.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,33 @@ class InviteItem extends StatelessWidget {
193193
));
194194
}
195195
}
196+
197+
198+
class InineInviteManager extends StatefulWidget {
199+
Function() reloadMethod;
200+
201+
InineInviteManager({required this.reloadMethod});
202+
203+
@override
204+
State<StatefulWidget> createState() => _InlineInviteManagerState();
205+
}
206+
207+
class _InlineInviteManagerState extends State<InineInviteManager> {
208+
@override
209+
Widget build(BuildContext context) {
210+
// TODO: implement build
211+
Iterable<OpenShockShareInvite> incoming =
212+
AlarmListManager.getInstance().invites?.where((x) => !x.outgoing) ?? [];
213+
if(incoming.isEmpty) return SizedBox.shrink();
214+
ThemeData t = Theme.of(context);
215+
return Column(
216+
children: [
217+
Padding(padding: PredefinedSpacing.paddingLarge()),
218+
Text("Incoming invites", style: t.textTheme.headlineSmall,),
219+
...incoming.map((x) => InviteItem(
220+
invite: x,
221+
reloadMethod: widget.reloadMethod)),
222+
],
223+
);
224+
}
225+
}

lib/services/alarm_list_manager.dart

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ class AlarmListManager {
288288
updateHubList();
289289
rebuildAlarmShockers();
290290
updateShareLinks();
291+
updateInvites(incomingOnly: true);
291292
if (reloadAllMethod != null) reloadAllMethod!();
292293
if (tokenExpired) {
293294
showSessionExpired();
@@ -1126,13 +1127,17 @@ class AlarmListManager {
11261127
saveLivePatterns();
11271128
}
11281129

1129-
Future updateInvites() async {
1130+
Future updateInvites({bool incomingOnly = false}) async {
11301131
List<OpenShockShareInvite> invites = [];
11311132
OpenShockClient client = OpenShockClient();
11321133
for (Token token in getTokens()) {
1133-
invites.addAll(await client.getInvites(token));
1134+
invites.addAll(await client.getInvites(token, incomingOnly: incomingOnly));
11341135
}
1136+
if(incomingOnly) invites.addAll(this.invites?.where((x) => x.outgoing) ?? []);
11351137
this.invites = invites;
1138+
if(incomingOnly && reloadAllMethod != null) {
1139+
reloadAllMethod!();
1140+
}
11361141
saveInvites();
11371142
}
11381143

@@ -1143,7 +1148,12 @@ class AlarmListManager {
11431148

11441149
Future<String?> deleteInvite(OpenShockShareInvite invite) async {
11451150
OpenShockClient client = OpenShockClient();
1146-
return client.deleteInvite(invite);
1151+
String? error = await client.deleteInvite(invite);
1152+
if(error == null) {
1153+
invites?.remove(invite);
1154+
saveInvites();
1155+
}
1156+
return error;
11471157
}
11481158

11491159
Future<void> updateUserShares() async {

lib/services/openshock.dart

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -926,16 +926,19 @@ class OpenShockClient {
926926
return null;
927927
}
928928

929-
Future<List<OpenShockShareInvite>> getInvites(Token token) async {
930-
var response = await GetRequest(token, "/2/shares/user/invites/outgoing");
929+
Future<List<OpenShockShareInvite>> getInvites(Token token, {bool incomingOnly = false}) async {
930+
http.Response response;
931931
List<OpenShockShareInvite> invites = [];
932-
if (response.statusCode == 200) {
933-
jsonDecode(response.body).forEach((element) {
934-
OpenShockShareInvite i =
935-
OpenShockShareInvite.fromJson(element, tokenReference: token);
936-
i.outgoing = true;
937-
invites.add(i);
938-
});
932+
if(!incomingOnly) {
933+
response = await GetRequest(token, "/2/shares/user/invites/outgoing");
934+
if (response.statusCode == 200) {
935+
jsonDecode(response.body).forEach((element) {
936+
OpenShockShareInvite i =
937+
OpenShockShareInvite.fromJson(element, tokenReference: token);
938+
i.outgoing = true;
939+
invites.add(i);
940+
});
941+
}
939942
}
940943

941944
response = await GetRequest(token, "/2/shares/user/invites/incoming");

0 commit comments

Comments
 (0)