Skip to content

Commit

Permalink
ui: new_group_page: add conditional policy tile
Browse files Browse the repository at this point in the history
  • Loading branch information
dufkan authored and jjanku committed May 3, 2024
1 parent 2b417c4 commit d5b7ac8
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 7 deletions.
4 changes: 2 additions & 2 deletions lib/ui/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,8 @@ class _HomePageViewState extends State<HomePageView> {
if (res == null) return;

try {
await context.read<HomeState>().addGroup(
res.name, res.members, res.threshold, res.protocol, res.keyType);
await context.read<HomeState>().addGroup(res.name, res.members,
res.threshold, res.protocol, res.keyType, res.note);
} catch (e) {
showErrorDialog(
title: 'Group request failed',
Expand Down
5 changes: 3 additions & 2 deletions lib/ui/home_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ class HomeState with ChangeNotifier {
}

Future<void> addGroup(String name, List<Member> members, int threshold,
Protocol protocol, KeyType keyType) =>
_groupRepository.group(name, members, threshold, protocol, keyType);
Protocol protocol, KeyType keyType, String? note) =>
_groupRepository.group(name, members, threshold, protocol, keyType,
note: note);

Future<void> sign(XFile file, Group group) async {
await _fileRepository.sign(file.name, await file.readAsBytes(), group.id);
Expand Down
155 changes: 152 additions & 3 deletions lib/ui/new_group_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:math';
import 'dart:convert';

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -180,9 +181,15 @@ class _NewGroupPageState extends State<NewGroupPage> {
int _threshold = _minThreshold;
final List<Member> _members = [];
final _nameController = TextEditingController();
String? _nameErr, _memberErr;
final _policyController = TextEditingController();
String? _nameErr, _memberErr, _policyErr;
KeyType _keyType = KeyType.signPdf;
Protocol _protocol = KeyType.signPdf.supportedProtocols.first;
bool _policyAfter = false;
TimeOfDay _policyAfterTime = const TimeOfDay(hour: 8, minute: 0);
bool _policyBefore = false;
TimeOfDay _policyBeforeTime = const TimeOfDay(hour: 20, minute: 0);
bool _policyDecline = false;

int get _shareCount => _members.map((m) => m.shares).sum;

Expand All @@ -196,6 +203,13 @@ class _NewGroupPageState extends State<NewGroupPage> {
});
}
});
_policyController.addListener(() {
if (_policyErr != null) {
setState(() {
_policyErr = null;
});
}
});
}

@override
Expand All @@ -218,6 +232,9 @@ class _NewGroupPageState extends State<NewGroupPage> {
});
}

bool get _hasBot =>
_members.any((member) => member.device.kind == DeviceKind.bot);

void _selectPeer(String route) async {
// TODO: pass the current selection to the search page?
final devices = await Navigator.pushNamed(context, route);
Expand All @@ -235,7 +252,33 @@ class _NewGroupPageState extends State<NewGroupPage> {
_memberErr = "Add member";
});
}
if (_nameErr != null || _memberErr != null) return;

var policy = <String, dynamic>{};

String pad(num n) => n.toString().padLeft(2, '0');
if (_policyAfter) {
policy['after'] =
'${pad(_policyAfterTime.hour)}:${pad(_policyAfterTime.minute)}';
}
if (_policyBefore) {
policy['before'] =
'${pad(_policyBeforeTime.hour)}:${pad(_policyBeforeTime.minute)}';
}
if (_policyDecline) {
policy['decline'] = true;
}

if (_policyController.text.trim().isNotEmpty) {
try {
final customPolicy = jsonDecode(_policyController.text);
policy = {...policy, ...customPolicy};
} catch (e) {
setState(() {
_policyErr = 'Invalid JSON';
});
}
}
if (_nameErr != null || _memberErr != null || _policyErr != null) return;

Navigator.pop(
context,
Expand All @@ -246,6 +289,7 @@ class _NewGroupPageState extends State<NewGroupPage> {
_threshold,
_protocol,
_keyType,
note: _hasBot ? jsonEncode(policy) : null,
),
);
}
Expand Down Expand Up @@ -287,6 +331,96 @@ class _NewGroupPageState extends State<NewGroupPage> {

final warning = _getWarning();

final policyTile = OptionTile(
title: 'Policy',
children: [
Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 4.0),
child: Row(
children: [
Checkbox(
value: _policyAfter,
onChanged: (bool? value) {
setState(() {
_policyAfter = value!;
});
},
),
Text('Approve after ${_policyAfterTime.format(context)}'),
const Spacer(),
FilledButton.tonalIcon(
icon: const Icon(Icons.access_time),
label: const Text('Select time'),
onPressed: _policyAfter
? () async {
final value = await showTimePicker(
context: context,
initialTime: _policyAfterTime,
);
if (value != null) {
setState(() {
_policyAfterTime = value;
});
}
}
: null,
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Checkbox(
value: _policyBefore,
onChanged: (bool? value) {
setState(() {
_policyBefore = value!;
});
},
),
Text('Approve before ${_policyBeforeTime.format(context)}'),
const Spacer(),
FilledButton.tonalIcon(
icon: const Icon(Icons.access_time),
label: const Text('Select time'),
onPressed: _policyBefore
? () async {
final value = await showTimePicker(
context: context,
initialTime: _policyBeforeTime,
);
if (value != null) {
setState(() {
_policyBeforeTime = value;
});
}
}
: null,
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Checkbox(
value: _policyDecline,
onChanged: (bool? value) {
setState(() {
_policyDecline = value!;
});
},
),
const Text('Decline if the policy is not satisfied immediately'),
],
),
),
],
);

return Scaffold(
appBar: AppBar(
title: const Text('New Group'),
Expand Down Expand Up @@ -484,6 +618,7 @@ class _NewGroupPageState extends State<NewGroupPage> {
),
],
),
if (_hasBot) policyTile,
ExpansionTile(
title: const Text('Advanced options'),
collapsedTextColor:
Expand All @@ -507,7 +642,21 @@ class _NewGroupPageState extends State<NewGroupPage> {
],
),
],
)
),
if (_hasBot)
OptionTile(
title: 'Custom policy',
children: [
TextField(
controller: _policyController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
errorText: _policyErr,
),
maxLines: null,
),
],
),
],
),
],
Expand Down

0 comments on commit d5b7ac8

Please sign in to comment.