-
Notifications
You must be signed in to change notification settings - Fork 0
/
select_certificate_screen.dart
384 lines (348 loc) · 12.9 KB
/
select_certificate_screen.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
import 'package:eidmsdk/types.dart' show Certificate;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
import '../../bloc/get_document_signature_type_cubit.dart';
import '../../bloc/select_signing_certificate_cubit.dart';
import '../../certificate_extensions.dart';
import '../../data/document_signing_type.dart';
import '../../data/settings.dart';
import '../../data/signature_type.dart';
import '../../di.dart';
import '../../oids.dart';
import '../../strings_context.dart';
import '../app_theme.dart';
import '../fragment/select_signing_certificate_fragment.dart';
import '../widgets/error_content.dart';
import '../widgets/loading_content.dart';
import '../widgets/signature_type_picker.dart';
import 'sign_document_screen.dart';
/// Screen for
/// - loading and presenting [Certificate]
/// - and then selecting the [SignatureType] using [SignatureTypePicker].
///
/// Uses [SelectSigningCertificateCubit] and [GetDocumentSignatureTypeCubit].
///
/// Consumes [Settings].
///
/// Navigates next to [SignDocumentScreen].
class SelectCertificateScreen extends StatelessWidget {
final String documentId;
final DocumentSigningType signingType;
const SelectCertificateScreen({
super.key,
required this.documentId,
required this.signingType,
});
@override
Widget build(BuildContext context) {
return BlocProvider<SelectSigningCertificateCubit>(
create: (context) {
final settings = context.read<Settings>();
final signingCertificate = settings.signingCertificate;
return getIt.get<SelectSigningCertificateCubit>(
param1: signingCertificate,
)..getCertificates();
},
child: BlocBuilder<SelectSigningCertificateCubit,
SelectSigningCertificateState>(
builder: (context, state) {
final showTitle = state is! SelectSigningCertificateLoadingState;
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: showTitle,
title: showTitle
? Text(context.strings.selectCertificateTitle)
: null,
),
body: _Body(
state: state,
signingType: signingType,
documentId: documentId,
onSignDocumentRequested: (certificate, signatureType) {
_onSignDocumentRequested(
context: context,
certificate: certificate,
signatureType: signatureType,
);
},
onReloadCertificatesRequested: () {
_onReloadCertificatesRequested(context);
},
),
);
},
),
);
}
Future<void> _onSignDocumentRequested({
required BuildContext context,
required Certificate certificate,
required SignatureType signatureType,
}) {
context.read<Settings>().signingCertificate.value = certificate;
final screen = SignDocumentScreen(
documentId: documentId,
certificate: certificate,
signatureType: signatureType,
signingType: signingType,
);
final route = MaterialPageRoute(builder: (_) => screen);
return Navigator.of(context).push(route);
}
Future<void> _onReloadCertificatesRequested(BuildContext context) {
return context
.read<SelectSigningCertificateCubit>()
.getCertificates(refresh: true);
}
}
/// [SelectCertificateScreen] body.
class _Body extends StatelessWidget {
final SelectSigningCertificateState state;
final DocumentSigningType signingType;
final String documentId;
final void Function(Certificate certificate, SignatureType signatureType)?
onSignDocumentRequested;
final VoidCallback? onReloadCertificatesRequested;
const _Body({
required this.state,
this.signingType = DocumentSigningType.local,
this.documentId = '',
this.onSignDocumentRequested,
this.onReloadCertificatesRequested,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: kScreenMargin,
child: _getChild(context),
);
}
Widget _getChild(BuildContext context) {
return SelectSigningCertificateFragment(
state: state,
successBuilder: (context, certificate) {
return _SelectSignatureTypeContent(
certificate: certificate,
signingType: signingType,
documentId: documentId,
onSignDocumentRequested: (final SignatureType signatureType) {
onSignDocumentRequested?.call(certificate, signatureType);
},
onReloadCertificatesRequested: onReloadCertificatesRequested,
);
},
);
}
}
/// Success content where [Certificate] was loaded.
/// Only thing is to determine [SignatureType] for given Document, either when:
/// - [DocumentSigningType.local] - from [Settings.signatureType]
/// - [DocumentSigningType.remote] - by calling [GetDocumentSignatureTypeCubit.getDocumentSignatureType]
///
/// Uses [GetDocumentSignatureTypeCubit].
///
/// Consumes [Settings].
class _SelectSignatureTypeContent extends StatefulWidget {
final String? subject;
final DocumentSigningType signingType;
final String documentId;
final ValueSetter<SignatureType>? onSignDocumentRequested;
final VoidCallback? onReloadCertificatesRequested;
_SelectSignatureTypeContent({
required Certificate certificate,
required this.signingType,
required this.documentId,
required this.onSignDocumentRequested,
required this.onReloadCertificatesRequested,
}) : subject = certificate.tbsCertificate.subject[X500Oids.cn];
@override
State<_SelectSignatureTypeContent> createState() =>
_SelectSignatureTypeContentState();
}
class _SelectSignatureTypeContentState
extends State<_SelectSignatureTypeContent> {
SignatureType? _signatureType;
@override
void initState() {
super.initState();
if (widget.signingType == DocumentSigningType.local) {
_signatureType = context.read<Settings>().signatureType.value;
}
}
@override
Widget build(BuildContext context) {
final strings = context.strings;
final body = BlocProvider<GetDocumentSignatureTypeCubit>(
create: (context) {
final cubit = getIt.get<GetDocumentSignatureTypeCubit>();
switch (widget.signingType) {
// TODO Refactor this flow; Need to work with Settings in cubit ctor
// And refactor this widget to be Stateful and work only with Cubit state
case DocumentSigningType.local:
cubit.setSignatureType(_signatureType);
break;
case DocumentSigningType.remote:
cubit.getDocumentSignatureType(widget.documentId);
break;
}
return cubit;
},
child: BlocConsumer<GetDocumentSignatureTypeCubit,
GetDocumentSignatureTypeState>(
listener: (context, state) {
if (state is GetDocumentSignatureTypeSuccessState) {
setState(() {
_signatureType =
(state.signatureType ?? SignatureType.withoutTimestamp);
});
}
},
builder: (context, state) {
return switch (state) {
GetDocumentSignatureTypeInitialState _ => const LoadingContent(),
GetDocumentSignatureTypeLoadingState _ => const LoadingContent(),
GetDocumentSignatureTypeErrorState state => ErrorContent(
title: strings.signatureTypeErrorHeading,
error: state.error,
),
GetDocumentSignatureTypeSuccessState state => SignatureTypePicker(
// TODO Check why not passing state.signatureType
value: _signatureType,
canChange: (widget.signingType == DocumentSigningType.local),
onValueChanged: (final SignatureType value) {
setState(() {
_signatureType = value;
});
},
),
};
},
),
);
return Column(
children: [
Expanded(
child: body,
),
// Primary button
FilledButton(
style: FilledButton.styleFrom(
minimumSize: kPrimaryButtonMinimumSize,
),
onPressed:
(_signatureType == null || _signatureType == SignatureType.unset
? null
: () {
widget.onSignDocumentRequested?.call(_signatureType!);
}),
child:
Text(strings.buttonSignWithCertificateLabel("${widget.subject}")),
// Extract data
),
const SizedBox(height: kButtonSpace),
// Secondary button
TextButton(
style: TextButton.styleFrom(
minimumSize: kPrimaryButtonMinimumSize,
),
onPressed: widget.onReloadCertificatesRequested,
child: Text(strings.buttonSignWithDifferentCertificateLabel),
),
],
);
}
}
@widgetbook.UseCase(
path: '[Screens]',
name: 'loading',
type: SelectCertificateScreen,
)
Widget previewLoadingSelectCertificateScreen(BuildContext context) {
return const _Body(
state: SelectSigningCertificateLoadingState(),
);
}
@widgetbook.UseCase(
path: '[Screens]',
name: 'canceled',
type: SelectCertificateScreen,
)
Widget previewCanceledSelectCertificateScreen(BuildContext context) {
return const _Body(
state: SelectSigningCertificateCanceledState(),
);
}
@widgetbook.UseCase(
path: '[Screens]',
name: 'no certificate',
type: SelectCertificateScreen,
)
Widget previewNoCertificateSelectCertificateScreen(BuildContext context) {
return const _Body(
state: SelectSigningCertificateNoCertificateState(),
);
}
@widgetbook.UseCase(
path: '[Screens]',
name: 'error',
type: SelectCertificateScreen,
)
Widget previewErrorSelectCertificateScreen(BuildContext context) {
return const _Body(
state: SelectSigningCertificateErrorState("Error message!"),
);
}
@widgetbook.UseCase(
path: '[Screens]',
name: 'success',
type: SelectCertificateScreen,
)
Widget previewSuccessSelectCertificateScreen(BuildContext context) {
const aliceCert = """
MIIGJzCCBA+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjELMAkGA1UEBhMCRlIx
DzANBgNVBAgMBkFsc2FjZTETMBEGA1UEBwwKU3RyYXNib3VyZzEYMBYGA1UECgwP
d3d3LmZyZWVsYW4ub3JnMRAwDgYDVQQLDAdmcmVlbGFuMS0wKwYDVQQDDCRGcmVl
bGFuIFNhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIjAgBgkqhkiG9w0BCQEW
E2NvbnRhY3RAZnJlZWxhbi5vcmcwHhcNMTIwNDI3MTAzMTE4WhcNMjIwNDI1MTAz
MTE4WjB+MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGQWxzYWNlMRgwFgYDVQQKDA93
d3cuZnJlZWxhbi5vcmcxEDAOBgNVBAsMB2ZyZWVsYW4xDjAMBgNVBAMMBWFsaWNl
MSIwIAYJKoZIhvcNAQkBFhNjb250YWN0QGZyZWVsYW4ub3JnMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEA3W29+ID6194bH6ejLrIC4hb2Ugo8v6ZC+Mrc
k2dNYMNPjcOKABvxxEtBamnSaeU/IY7FC/giN622LEtV/3oDcrua0+yWuVafyxmZ
yTKUb4/GUgafRQPf/eiX9urWurtIK7XgNGFNUjYPq4dSJQPPhwCHE/LKAykWnZBX
RrX0Dq4XyApNku0IpjIjEXH+8ixE12wH8wt7DEvdO7T3N3CfUbaITl1qBX+Nm2Z6
q4Ag/u5rl8NJfXg71ZmXA3XOj7zFvpyapRIZcPmkvZYn7SMCp8dXyXHPdpSiIWL2
uB3KiO4JrUYvt2GzLBUThp+lNSZaZ/Q3yOaAAUkOx+1h08285Pi+P8lO+H2Xic4S
vMq1xtLg2bNoPC5KnbRfuFPuUD2/3dSiiragJ6uYDLOyWJDivKGt/72OVTEPAL9o
6T2pGZrwbQuiFGrGTMZOvWMSpQtNl+tCCXlT4mWqJDRwuMGrI4DnnGzt3IKqNwS4
Qyo9KqjMIPwnXZAmWPm3FOKe4sFwc5fpawKO01JZewDsYTDxVj+cwXwFxbE2yBiF
z2FAHwfopwaH35p3C6lkcgP2k/zgAlnBluzACUI+MKJ/G0gv/uAhj1OHJQ3L6kn1
SpvQ41/ueBjlunExqQSYD7GtZ1Kg8uOcq2r+WISE3Qc9MpQFFkUVllmgWGwYDuN3
Zsez95kCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT
TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFlfyRO6G8y5qEFKikl5
ajb2fT7XMB8GA1UdIwQYMBaAFCNsLT0+KV14uGw+quK7Lh5sh/JTMA0GCSqGSIb3
DQEBBQUAA4ICAQAT5wJFPqervbja5+90iKxi1d0QVtVGB+z6aoAMuWK+qgi0vgvr
mu9ot2lvTSCSnRhjeiP0SIdqFMORmBtOCFk/kYDp9M/91b+vS+S9eAlxrNCB5VOf
PqxEPp/wv1rBcE4GBO/c6HcFon3F+oBYCsUQbZDKSSZxhDm3mj7pb67FNbZbJIzJ
70HDsRe2O04oiTx+h6g6pW3cOQMgIAvFgKN5Ex727K4230B0NIdGkzuj4KSML0NM
slSAcXZ41OoSKNjy44BVEZv0ZdxTDrRM4EwJtNyggFzmtTuV02nkUj1bYYYC5f0L
ADr6s0XMyaNk8twlWYlYDZ5uKDpVRVBfiGcq0uJIzIvemhuTrofh8pBQQNkPRDFT
Rq1iTo1Ihhl3/Fl1kXk1WR3jTjNb4jHX7lIoXwpwp767HAPKGhjQ9cFbnHMEtkro
RlJYdtRq5mccDtwT0GFyoJLLBZdHHMHJz0F9H7FNk2tTQQMhK5MVYwg+LIaee586
CQVqfbscp7evlgjLW98H+5zylRHAgoH2G79aHljNKMp9BOuq6SnEglEsiWGVtu2l
hnx8SB3sVJZHeer8f/UQQwqbAO+Kdy70NmbSaqaVtp8jOxLiidWkwSyRTsuU6D8i
DiH5uEqBXExjrj0FslxcVKdVj5glVcSmkLwZKbEU1OKwleT/iXFhvooWhQ==
""";
const certificate = Certificate(
slot: "1",
supportedSchemes: [],
isQualified: true,
certIndex: 1,
certData: aliceCert,
);
return _Body(
state: const SelectSigningCertificateSuccessState(certificate),
onReloadCertificatesRequested: () {},
);
}