mirror of
https://gitlab.com/comunic/comunicmobile
synced 2025-09-19 13:58:50 +00:00
Start to fix null safety migration errors
This commit is contained in:
@@ -4,14 +4,14 @@ import 'package:flutter/material.dart';
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
Future<void> alert(BuildContext context, String msg) async {
|
||||
await showDialog(context: context, builder: (c) => _AlertDialog(msg: msg));
|
||||
Future<void> alert(BuildContext context, String? msg) async {
|
||||
await showDialog(context: context, builder: (c) => _AlertDialog(msg: msg!));
|
||||
}
|
||||
|
||||
class _AlertDialog extends StatelessWidget {
|
||||
final String msg;
|
||||
|
||||
const _AlertDialog({Key key, @required this.msg})
|
||||
const _AlertDialog({Key? key, required this.msg})
|
||||
: assert(msg != null),
|
||||
super(key: key);
|
||||
|
||||
|
@@ -9,16 +9,16 @@ import 'package:video_player/video_player.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Show audio player dialog
|
||||
Future<void> showAudioPlayerDialog(BuildContext context, String url) async {
|
||||
showDialog(context: context, builder: (c) => _AudioPlayerDialog(url: url));
|
||||
Future<void> showAudioPlayerDialog(BuildContext context, String? url) async {
|
||||
showDialog(context: context, builder: (c) => _AudioPlayerDialog(url: url!));
|
||||
}
|
||||
|
||||
class _AudioPlayerDialog extends StatefulWidget {
|
||||
final String url;
|
||||
|
||||
const _AudioPlayerDialog({
|
||||
Key key,
|
||||
@required this.url,
|
||||
Key? key,
|
||||
required this.url,
|
||||
}) : assert(url != null),
|
||||
super(key: key);
|
||||
|
||||
@@ -27,16 +27,16 @@ class _AudioPlayerDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class __AudioPlayerDialogState extends State<_AudioPlayerDialog> {
|
||||
VideoPlayerController _videoPlayerController;
|
||||
ChewieAudioController _chewieAudioController;
|
||||
VideoPlayerController? _videoPlayerController;
|
||||
ChewieAudioController? _chewieAudioController;
|
||||
|
||||
Future<void> _initialize() async {
|
||||
_videoPlayerController = VideoPlayerController.network(widget.url);
|
||||
|
||||
await _videoPlayerController.initialize();
|
||||
await _videoPlayerController!.initialize();
|
||||
|
||||
_chewieAudioController = ChewieAudioController(
|
||||
videoPlayerController: _videoPlayerController,
|
||||
videoPlayerController: _videoPlayerController!,
|
||||
autoPlay: true,
|
||||
looping: false,
|
||||
);
|
||||
@@ -48,20 +48,20 @@ class __AudioPlayerDialogState extends State<_AudioPlayerDialog> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_videoPlayerController != null) _videoPlayerController.dispose();
|
||||
if (_chewieAudioController != null) _chewieAudioController.dispose();
|
||||
if (_videoPlayerController != null) _videoPlayerController!.dispose();
|
||||
if (_chewieAudioController != null) _chewieAudioController!.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("Audio Player")),
|
||||
title: Text(tr("Audio Player")!),
|
||||
content: _buildContent(),
|
||||
actions: [
|
||||
MaterialButton(
|
||||
onPressed: _closeDialog,
|
||||
child: Text(tr("Close").toUpperCase()),
|
||||
child: Text(tr("Close")!.toUpperCase()),
|
||||
)
|
||||
],
|
||||
);
|
||||
@@ -72,10 +72,10 @@ class __AudioPlayerDialogState extends State<_AudioPlayerDialog> {
|
||||
child: AsyncScreenWidget(
|
||||
onReload: _initialize,
|
||||
onBuild: _buildReadyContent,
|
||||
errorMessage: tr("Failed to initialize audio player!"),
|
||||
errorMessage: tr("Failed to initialize audio player!")!,
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildReadyContent() =>
|
||||
ChewieAudio(controller: _chewieAudioController);
|
||||
ChewieAudio(controller: _chewieAudioController!);
|
||||
}
|
||||
|
@@ -6,17 +6,17 @@ import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
Future<Color> showColorPickerDialog(
|
||||
BuildContext context, Color initialColor) async =>
|
||||
Future<Color?> showColorPickerDialog(
|
||||
BuildContext context, Color? initialColor) async =>
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (c) => _ColorPickerDialog(initialColor: initialColor),
|
||||
);
|
||||
|
||||
class _ColorPickerDialog extends StatefulWidget {
|
||||
final Color initialColor;
|
||||
final Color? initialColor;
|
||||
|
||||
const _ColorPickerDialog({Key key, @required this.initialColor})
|
||||
const _ColorPickerDialog({Key? key, required this.initialColor})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@@ -24,7 +24,7 @@ class _ColorPickerDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class __ColorPickerDialogState extends State<_ColorPickerDialog> {
|
||||
Color _newColor;
|
||||
Color? _newColor;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -42,11 +42,11 @@ class __ColorPickerDialogState extends State<_ColorPickerDialog> {
|
||||
actions: [
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.pop(context, widget.initialColor),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
),
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.pop(context, _newColor),
|
||||
child: Text(tr("Ok").toUpperCase()),
|
||||
child: Text(tr("Ok")!.toUpperCase()),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@@ -16,23 +16,23 @@ class _DeprecationDialog extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("Deprecated application version")),
|
||||
title: Text(tr("Deprecated application version")!),
|
||||
content: Text(tr(
|
||||
"This version of the Comunic application is deprecated. You might still be able to use it, but some features may not work. We recommend you to update to the latest version of the application.")),
|
||||
"This version of the Comunic application is deprecated. You might still be able to use it, but some features may not work. We recommend you to update to the latest version of the application.")!),
|
||||
actions: [
|
||||
MaterialButton(
|
||||
onPressed: () =>
|
||||
launch(ServerConfigurationHelper.config.playStoreURL),
|
||||
child: Text(tr("Go to the Play Store")),
|
||||
launch(ServerConfigurationHelper.config!.playStoreURL),
|
||||
child: Text(tr("Go to the Play Store")!),
|
||||
),
|
||||
MaterialButton(
|
||||
onPressed: () =>
|
||||
launch(ServerConfigurationHelper.config.androidDirectDownloadURL),
|
||||
child: Text(tr("Download update outside Play Store")),
|
||||
launch(ServerConfigurationHelper.config!.androidDirectDownloadURL),
|
||||
child: Text(tr("Download update outside Play Store")!),
|
||||
),
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(tr("Use the old application anyway")),
|
||||
child: Text(tr("Use the old application anyway")!),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
@@ -8,9 +8,9 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
/// Ask the user to enter a new password
|
||||
Future<String> showInputNewPassword({
|
||||
@required BuildContext context,
|
||||
@required UserInfoForPassword userInfo,
|
||||
Future<String?> showInputNewPassword({
|
||||
required BuildContext context,
|
||||
required UserInfoForPassword userInfo,
|
||||
}) async {
|
||||
assert(context != null);
|
||||
assert(userInfo != null);
|
||||
@@ -25,8 +25,8 @@ class _InputNewPasswordDialog extends StatefulWidget {
|
||||
final UserInfoForPassword userInfo;
|
||||
|
||||
const _InputNewPasswordDialog({
|
||||
Key key,
|
||||
@required this.userInfo,
|
||||
Key? key,
|
||||
required this.userInfo,
|
||||
}) : assert(userInfo != null),
|
||||
super(key: key);
|
||||
|
||||
@@ -40,16 +40,16 @@ class __InputNewPasswordDialogState extends State<_InputNewPasswordDialog> {
|
||||
final _controller2 = TextEditingController();
|
||||
final _focusScopeNode = FocusScopeNode();
|
||||
|
||||
String get _password => _controller1.currentState.value;
|
||||
String get _password => _controller1.currentState!.value;
|
||||
|
||||
bool get _input1Valid =>
|
||||
_controller1.currentState != null && _controller1.currentState.valid;
|
||||
_controller1.currentState != null && _controller1.currentState!.valid;
|
||||
|
||||
bool get _input2Valid => _controller1.currentState.value == _controller2.text;
|
||||
bool get _input2Valid => _controller1.currentState!.value == _controller2.text;
|
||||
|
||||
bool get _isValid => _input1Valid && _input2Valid;
|
||||
|
||||
void Function() get _submitAction =>
|
||||
void Function()? get _submitAction =>
|
||||
_isValid ? () => Navigator.of(context).pop(_password) : null;
|
||||
|
||||
@override
|
||||
@@ -61,16 +61,16 @@ class __InputNewPasswordDialogState extends State<_InputNewPasswordDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("New password")),
|
||||
title: Text(tr("New password")!),
|
||||
content: AutoSizeDialogContentWidget(child: _buildContent()),
|
||||
actions: <Widget>[
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
),
|
||||
MaterialButton(
|
||||
onPressed: _submitAction,
|
||||
child: Text(tr("Confirm").toUpperCase()),
|
||||
child: Text(tr("Confirm")!.toUpperCase()),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -85,7 +85,7 @@ class __InputNewPasswordDialogState extends State<_InputNewPasswordDialog> {
|
||||
NewPasswordInputWidget(
|
||||
key: _controller1,
|
||||
user: widget.userInfo,
|
||||
label: tr("Your new password"),
|
||||
label: tr("Your new password")!,
|
||||
textInputAction: TextInputAction.next,
|
||||
onSubmitted: () => _focusScopeNode.nextFocus(),
|
||||
),
|
||||
@@ -105,17 +105,17 @@ class __InputNewPasswordDialogState extends State<_InputNewPasswordDialog> {
|
||||
}
|
||||
|
||||
Widget _buildPasswordField({
|
||||
@required TextEditingController controller,
|
||||
@required String label,
|
||||
@required String errorText,
|
||||
@required TextInputAction textInputAction,
|
||||
@required void Function() onSubmitted,
|
||||
required TextEditingController controller,
|
||||
required String? label,
|
||||
required String? errorText,
|
||||
required TextInputAction textInputAction,
|
||||
required void Function()? onSubmitted,
|
||||
}) {
|
||||
return TextFormField(
|
||||
textInputAction: textInputAction,
|
||||
controller: controller,
|
||||
onChanged: (s) => setState(() {}),
|
||||
onFieldSubmitted: (s) => onSubmitted(),
|
||||
onFieldSubmitted: (s) => onSubmitted!(),
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
alignLabelWithHint: true,
|
||||
|
@@ -8,20 +8,20 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Ask the user to enter an URL
|
||||
Future<String> showInputURLDialog({
|
||||
@required BuildContext context,
|
||||
@required String title,
|
||||
String initialURL,
|
||||
Future<String?> showInputURLDialog({
|
||||
required BuildContext context,
|
||||
required String? title,
|
||||
String? initialURL,
|
||||
}) async {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
builder: (c) => SingleInputDialog(
|
||||
title: title,
|
||||
title: title!,
|
||||
icon: Icons.link,
|
||||
initialValue: initialURL,
|
||||
label: "http://...",
|
||||
checkInput: (s) => validateUrl(s),
|
||||
errorMessage: tr("Invalid URL!"),
|
||||
errorMessage: tr("Invalid URL!")!,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
enum _Status { NONE, CHECKING, ERROR }
|
||||
|
||||
Future<String> showUserPasswordDialog(BuildContext context) async {
|
||||
Future<String?> showUserPasswordDialog(BuildContext context) async {
|
||||
return await showDialog(
|
||||
context: context, builder: (c) => _InputUserPasswordDialog());
|
||||
}
|
||||
@@ -37,16 +37,16 @@ class __InputUserPasswordDialogState
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("Password required")),
|
||||
title: Text(tr("Password required")!),
|
||||
content: _buildContent(),
|
||||
actions: <Widget>[
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
),
|
||||
MaterialButton(
|
||||
onPressed: _canSubmit ? _checkPassword : null,
|
||||
child: Text(tr("Submit").toUpperCase()),
|
||||
child: Text(tr("Submit")!.toUpperCase()),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@@ -7,19 +7,19 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Ask the user to input a YouTube ID
|
||||
Future<String> showInputYouTubeIDDialog(
|
||||
BuildContext context, String initialID) async {
|
||||
Future<String?> showInputYouTubeIDDialog(
|
||||
BuildContext context, String? initialID) async {
|
||||
final value = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (b) => SingleInputDialog(
|
||||
title: tr("Input YouTube URL"),
|
||||
title: tr("Input YouTube URL")!,
|
||||
icon: Icons.ondemand_video,
|
||||
initialValue: initialID == null
|
||||
? null
|
||||
: "https://www.youtube.com/watch/?v=" + initialID,
|
||||
label: tr("https://www.youtube.com/watch/?v="),
|
||||
label: tr("https://www.youtube.com/watch/?v=")!,
|
||||
checkInput: (s) => RegExp(r'watch\/\?v=[\w\-\_]+').hasMatch(s),
|
||||
errorMessage: tr("Invalid YouTube link!"),
|
||||
errorMessage: tr("Invalid YouTube link!")!,
|
||||
));
|
||||
|
||||
if (value == null) return null;
|
||||
|
@@ -10,12 +10,12 @@ import 'package:flutter/material.dart';
|
||||
class MultiChoiceEntry<T> {
|
||||
final T id;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final String? subtitle;
|
||||
final bool hidden;
|
||||
|
||||
const MultiChoiceEntry({
|
||||
@required this.id,
|
||||
@required this.title,
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.hidden = false,
|
||||
}) : assert(id != null),
|
||||
@@ -26,16 +26,16 @@ class MultiChoiceEntry<T> {
|
||||
}
|
||||
|
||||
/// Show multiple choices dialog
|
||||
Future<T> showMultiChoicesDialog<T>({
|
||||
@required BuildContext context,
|
||||
@required List<MultiChoiceEntry<T>> choices,
|
||||
@required T defaultChoice,
|
||||
@required String title,
|
||||
Future<T?> showMultiChoicesDialog<T>({
|
||||
required BuildContext context,
|
||||
required List<MultiChoiceEntry<T>> choices,
|
||||
required T defaultChoice,
|
||||
required String? title,
|
||||
}) async {
|
||||
return await showDialog<T>(
|
||||
context: context,
|
||||
builder: (c) => _MultiChoicesEntryDialog(
|
||||
title: title,
|
||||
title: title!,
|
||||
defaultChoice: defaultChoice,
|
||||
choices: choices,
|
||||
));
|
||||
@@ -47,10 +47,10 @@ class _MultiChoicesEntryDialog<T> extends StatefulWidget {
|
||||
final List<MultiChoiceEntry<T>> choices;
|
||||
|
||||
const _MultiChoicesEntryDialog({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.defaultChoice,
|
||||
@required this.choices,
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.defaultChoice,
|
||||
required this.choices,
|
||||
}) : assert(title != null),
|
||||
assert(defaultChoice != null),
|
||||
assert(choices != null),
|
||||
@@ -63,7 +63,7 @@ class _MultiChoicesEntryDialog<T> extends StatefulWidget {
|
||||
|
||||
class __MultiChoicesEntryDialogState<T>
|
||||
extends State<_MultiChoicesEntryDialog<T>> {
|
||||
T _currChoice;
|
||||
T? _currChoice;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -86,7 +86,7 @@ class __MultiChoicesEntryDialogState<T>
|
||||
onChanged: (v) => setState(() => _currChoice = v),
|
||||
),
|
||||
title: Text(f.title),
|
||||
subtitle: f.hasSubtitle ? Text(f.subtitle) : null,
|
||||
subtitle: f.hasSubtitle ? Text(f.subtitle!) : null,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
@@ -94,12 +94,12 @@ class __MultiChoicesEntryDialogState<T>
|
||||
actions: <Widget>[
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
textColor: Colors.red,
|
||||
),
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(_currChoice),
|
||||
child: Text(tr("Confirm").toUpperCase()),
|
||||
child: Text(tr("Confirm")!.toUpperCase()),
|
||||
textColor: Colors.green,
|
||||
),
|
||||
],
|
||||
|
@@ -7,8 +7,8 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Show a dialog to prompt information about a new survey to create
|
||||
Future<NewSurvey> showNewSurveyDialog(
|
||||
{@required BuildContext context, NewSurvey initialSurvey}) async {
|
||||
Future<NewSurvey?> showNewSurveyDialog(
|
||||
{required BuildContext context, NewSurvey? initialSurvey}) async {
|
||||
return await showDialog<NewSurvey>(
|
||||
context: context,
|
||||
builder: (c) => _SurveyDialog(
|
||||
@@ -17,25 +17,25 @@ Future<NewSurvey> showNewSurveyDialog(
|
||||
}
|
||||
|
||||
class _SurveyDialog extends StatefulWidget {
|
||||
final NewSurvey initialSurvey;
|
||||
final NewSurvey? initialSurvey;
|
||||
|
||||
const _SurveyDialog({Key key, this.initialSurvey}) : super(key: key);
|
||||
const _SurveyDialog({Key? key, this.initialSurvey}) : super(key: key);
|
||||
|
||||
@override
|
||||
__SurveyDialogState createState() => __SurveyDialogState();
|
||||
}
|
||||
|
||||
class __SurveyDialogState extends State<_SurveyDialog> {
|
||||
TextEditingController _questionController;
|
||||
TextEditingController? _questionController;
|
||||
final _choiceController = TextEditingController();
|
||||
var _choices = Set<String>();
|
||||
var _allowNewChoices = false;
|
||||
|
||||
bool get canConfirm =>
|
||||
_questionController.text.length > 2 && _choices.length > 1;
|
||||
_questionController!.text.length > 2 && _choices.length > 1;
|
||||
|
||||
NewSurvey get newSurvey => NewSurvey(
|
||||
question: _questionController.text,
|
||||
question: _questionController!.text,
|
||||
answers: _choices,
|
||||
allowNewChoicesCreation: _allowNewChoices);
|
||||
|
||||
@@ -43,31 +43,31 @@ class __SurveyDialogState extends State<_SurveyDialog> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_questionController = TextEditingController(
|
||||
text: widget.initialSurvey == null ? "" : widget.initialSurvey.question,
|
||||
text: widget.initialSurvey == null ? "" : widget.initialSurvey!.question,
|
||||
);
|
||||
if (widget.initialSurvey != null) {
|
||||
_choices = widget.initialSurvey.answers;
|
||||
_allowNewChoices = widget.initialSurvey.allowNewChoicesCreation;
|
||||
_choices = widget.initialSurvey!.answers;
|
||||
_allowNewChoices = widget.initialSurvey!.allowNewChoicesCreation;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("New survey")),
|
||||
title: Text(tr("New survey")!),
|
||||
content: _buildBody(),
|
||||
actions: <Widget>[
|
||||
// Cancel
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
),
|
||||
|
||||
// Confirm
|
||||
MaterialButton(
|
||||
onPressed:
|
||||
canConfirm ? () => Navigator.of(context).pop(newSurvey) : null,
|
||||
child: Text(tr("Confirm").toUpperCase()),
|
||||
child: Text(tr("Confirm")!.toUpperCase()),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -90,7 +90,7 @@ class __SurveyDialogState extends State<_SurveyDialog> {
|
||||
),
|
||||
|
||||
Container(height: 30),
|
||||
Text(tr("Current choices:")),
|
||||
Text(tr("Current choices:")!),
|
||||
_buildCurrentChoices(),
|
||||
|
||||
Container(
|
||||
@@ -118,7 +118,7 @@ class __SurveyDialogState extends State<_SurveyDialog> {
|
||||
value: _allowNewChoices,
|
||||
onChanged: (v) => setState(() => _allowNewChoices = v),
|
||||
),
|
||||
title: Text(tr("Allow users to create new choices")),
|
||||
title: Text(tr("Allow users to create new choices")!),
|
||||
)
|
||||
]),
|
||||
),
|
||||
@@ -126,7 +126,7 @@ class __SurveyDialogState extends State<_SurveyDialog> {
|
||||
}
|
||||
|
||||
Widget _buildCurrentChoices() {
|
||||
if (_choices.length == 0) return Text(tr("No choice yet."));
|
||||
if (_choices.length == 0) return Text(tr("No choice yet.")!);
|
||||
|
||||
return Column(
|
||||
children: _choices
|
||||
|
@@ -35,10 +35,10 @@ class _PickFileOption {
|
||||
final _CanEnable canEnable;
|
||||
|
||||
const _PickFileOption({
|
||||
@required this.value,
|
||||
@required this.label,
|
||||
@required this.icon,
|
||||
@required this.canEnable,
|
||||
required this.value,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
required this.canEnable,
|
||||
}) : assert(value != null),
|
||||
assert(label != null),
|
||||
assert(icon != null),
|
||||
@@ -49,50 +49,50 @@ List<_PickFileOption> get _optionsList => [
|
||||
// Image
|
||||
_PickFileOption(
|
||||
value: _FileChoices.PICK_IMAGE,
|
||||
label: tr("Choose an image"),
|
||||
label: tr("Choose an image")!,
|
||||
icon: Icons.image,
|
||||
canEnable: (l) => l.any(isImage)),
|
||||
_PickFileOption(
|
||||
value: _FileChoices.TAKE_PICTURE,
|
||||
label: tr("Take a picture"),
|
||||
label: tr("Take a picture")!,
|
||||
icon: Icons.camera_alt,
|
||||
canEnable: (l) => l.any(isImage)),
|
||||
|
||||
// Video
|
||||
_PickFileOption(
|
||||
value: _FileChoices.PICK_VIDEO,
|
||||
label: tr("Choose a video"),
|
||||
label: tr("Choose a video")!,
|
||||
icon: Icons.video_library,
|
||||
canEnable: (l) => l.any(isVideo)),
|
||||
_PickFileOption(
|
||||
value: _FileChoices.TAKE_VIDEO,
|
||||
label: tr("Take a video"),
|
||||
label: tr("Take a video")!,
|
||||
icon: Icons.videocam,
|
||||
canEnable: (l) => l.any(isVideo)),
|
||||
|
||||
// Audio
|
||||
_PickFileOption(
|
||||
value: _FileChoices.RECORD_AUDIO,
|
||||
label: tr("Record audio"),
|
||||
label: tr("Record audio")!,
|
||||
icon: Icons.mic,
|
||||
canEnable: (l) => l.any(isAudio)),
|
||||
|
||||
// Other
|
||||
_PickFileOption(
|
||||
value: _FileChoices.PICK_OTHER_FILE,
|
||||
label: tr("Browse files"),
|
||||
label: tr("Browse files")!,
|
||||
icon: Icons.folder_open,
|
||||
canEnable: (l) =>
|
||||
l.any((el) => !isImage(el) && !isVideo(el) && !isAudio(el))),
|
||||
];
|
||||
|
||||
Future<BytesFile> showPickFileDialog({
|
||||
@required BuildContext context,
|
||||
int maxFileSize,
|
||||
List<String> allowedMimeTypes,
|
||||
int imageMaxWidth,
|
||||
int imageMaxHeight,
|
||||
CropAspectRatio aspectRatio,
|
||||
Future<BytesFile?> showPickFileDialog({
|
||||
required BuildContext context,
|
||||
int? maxFileSize,
|
||||
required List<String> allowedMimeTypes,
|
||||
int? imageMaxWidth,
|
||||
int? imageMaxHeight,
|
||||
CropAspectRatio? aspectRatio,
|
||||
}) async {
|
||||
assert(allowedMimeTypes != null);
|
||||
|
||||
@@ -118,7 +118,7 @@ Future<BytesFile> showPickFileDialog({
|
||||
|
||||
if (choice == null) return null;
|
||||
|
||||
BytesFile file;
|
||||
BytesFile? file;
|
||||
switch (choice) {
|
||||
// Pick an image
|
||||
case _FileChoices.PICK_IMAGE:
|
||||
@@ -127,8 +127,8 @@ Future<BytesFile> showPickFileDialog({
|
||||
source: choice == _FileChoices.PICK_IMAGE
|
||||
? ImageSource.gallery
|
||||
: ImageSource.camera,
|
||||
maxWidth: imageMaxWidth.toDouble(),
|
||||
maxHeight: imageMaxHeight.toDouble(),
|
||||
maxWidth: imageMaxWidth!.toDouble(),
|
||||
maxHeight: imageMaxHeight!.toDouble(),
|
||||
);
|
||||
|
||||
if (image == null) return null;
|
||||
@@ -179,11 +179,11 @@ Future<BytesFile> showPickFileDialog({
|
||||
if (file == null) return null;
|
||||
|
||||
// Check file size
|
||||
if (maxFileSize != null && file.bytes.length > maxFileSize) {
|
||||
if (maxFileSize != null && file.bytes!.length > maxFileSize) {
|
||||
showSimpleSnack(
|
||||
context,
|
||||
tr("This file could not be sent: it is too big! (Max allowed size: %1%)",
|
||||
args: {"1": filesize(file.bytes.length)}));
|
||||
args: {"1": filesize(file.bytes!.length)})!);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ class _BottomSheetPickOption extends StatelessWidget {
|
||||
final _OnOptionSelected onOptionSelected;
|
||||
|
||||
const _BottomSheetPickOption(
|
||||
{Key key, @required this.options, @required this.onOptionSelected})
|
||||
{Key? key, required this.options, required this.onOptionSelected})
|
||||
: assert(options != null),
|
||||
assert(onOptionSelected != null),
|
||||
super(key: key);
|
||||
|
@@ -13,7 +13,7 @@ import 'package:flutter/material.dart';
|
||||
/// Ask the user to pick a user
|
||||
///
|
||||
/// Returns null if no user was selected
|
||||
Future<int> showPickUserDialog(BuildContext context) async {
|
||||
Future<int?> showPickUserDialog(BuildContext context) async {
|
||||
return await showDialog(context: context, builder: (c) => _PickUserDialog());
|
||||
}
|
||||
|
||||
@@ -23,19 +23,19 @@ class _PickUserDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class __PickUserDialogState extends SafeState<_PickUserDialog> {
|
||||
User _user;
|
||||
User? _user;
|
||||
|
||||
bool get _isValid => _user != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("Choose a user")),
|
||||
title: Text(tr("Choose a user")!),
|
||||
content: _buildContent(),
|
||||
actions: <Widget>[
|
||||
CancelDialogButton(),
|
||||
ConfirmDialogButton(
|
||||
value: _isValid ? _user.id : null,
|
||||
value: _isValid ? _user!.id : null,
|
||||
enabled: _isValid,
|
||||
),
|
||||
],
|
||||
@@ -52,7 +52,7 @@ class __PickUserDialogState extends SafeState<_PickUserDialog> {
|
||||
children: <Widget>[
|
||||
PickUserWidget(
|
||||
onSelectUser: (u) => setState(() => _user = u),
|
||||
label: tr("Search user..."),
|
||||
label: tr("Search user...")!,
|
||||
onValueChange: (u) => setState(() => _user = null),
|
||||
),
|
||||
],
|
||||
|
@@ -9,9 +9,9 @@ import 'package:flutter/material.dart';
|
||||
|
||||
/// Show post visibility level picker and return selected visibility level
|
||||
Future<PostVisibilityLevel> showPostVisibilityPickerDialog({
|
||||
@required BuildContext context,
|
||||
@required PostVisibilityLevel initialLevel,
|
||||
@required bool isGroup,
|
||||
required BuildContext context,
|
||||
required PostVisibilityLevel initialLevel,
|
||||
required bool isGroup,
|
||||
}) async {
|
||||
assert(context != null);
|
||||
assert(initialLevel != null);
|
||||
@@ -30,12 +30,12 @@ Future<PostVisibilityLevel> showPostVisibilityPickerDialog({
|
||||
class _PostVisibilityPickerWidget extends StatelessWidget {
|
||||
final bool isGroup;
|
||||
|
||||
const _PostVisibilityPickerWidget({Key key, @required this.isGroup})
|
||||
const _PostVisibilityPickerWidget({Key? key, required this.isGroup})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext c) => AlertDialog(
|
||||
title: Text(tr("Select new post visibility level")),
|
||||
title: Text(tr("Select new post visibility level")!),
|
||||
|
||||
// Show all options
|
||||
content: ConstrainedBox(
|
||||
@@ -45,14 +45,14 @@ class _PostVisibilityPickerWidget extends StatelessWidget {
|
||||
// Public
|
||||
PostVisibilityLevelTile(
|
||||
level: PostVisibilityLevel.PUBLIC,
|
||||
title: tr("Public"),
|
||||
title: tr("Public")!,
|
||||
onSelect: (o) => Navigator.pop(c, o),
|
||||
),
|
||||
|
||||
// Friends only (User page only)
|
||||
PostVisibilityLevelTile(
|
||||
level: PostVisibilityLevel.FRIENDS,
|
||||
title: tr("Friends only"),
|
||||
title: tr("Friends only")!,
|
||||
onSelect: (o) => Navigator.pop(c, o),
|
||||
visible: !isGroup,
|
||||
),
|
||||
@@ -60,7 +60,7 @@ class _PostVisibilityPickerWidget extends StatelessWidget {
|
||||
// User only (User page only)
|
||||
PostVisibilityLevelTile(
|
||||
level: PostVisibilityLevel.USER,
|
||||
title: tr("Me only"),
|
||||
title: tr("Me only")!,
|
||||
onSelect: (o) => Navigator.pop(c, o),
|
||||
visible: !isGroup,
|
||||
),
|
||||
@@ -68,7 +68,7 @@ class _PostVisibilityPickerWidget extends StatelessWidget {
|
||||
// Group members only (Group page only)
|
||||
PostVisibilityLevelTile(
|
||||
level: PostVisibilityLevel.GROUP_MEMBERS,
|
||||
title: tr("Group members only"),
|
||||
title: tr("Group members only")!,
|
||||
onSelect: (o) => Navigator.pop(c, o),
|
||||
visible: isGroup,
|
||||
),
|
||||
@@ -80,7 +80,7 @@ class _PostVisibilityPickerWidget extends StatelessWidget {
|
||||
actions: <Widget>[
|
||||
// Cancel
|
||||
TextButton(
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
onPressed: () => Navigator.pop(c, null),
|
||||
),
|
||||
],
|
||||
|
@@ -18,7 +18,7 @@ import 'package:video_player/video_player.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Record audio
|
||||
Future<Uint8List> showRecordAudioDialog(BuildContext context) async {
|
||||
Future<Uint8List?> showRecordAudioDialog(BuildContext context) async {
|
||||
// Request record permission
|
||||
if (!await requestPermission(context, Permission.microphone)) {
|
||||
alert(context, tr("Did not get permission to access microphone!"));
|
||||
@@ -43,15 +43,15 @@ class _RecordAudioDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
String _recordPath;
|
||||
String? _recordPath;
|
||||
|
||||
File get _recordFile => _recordPath == null ? null : File(_recordPath);
|
||||
File? get _recordFile => _recordPath == null ? null : File(_recordPath!);
|
||||
|
||||
bool _recording = false;
|
||||
|
||||
bool get _hasRecord => !_recording && _recordPath != null;
|
||||
|
||||
VideoPlayerController _videoPlayerController;
|
||||
VideoPlayerController? _videoPlayerController;
|
||||
|
||||
bool _playing = false;
|
||||
|
||||
@@ -59,8 +59,8 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
|
||||
/// Get record data. This getter can be accessed only once
|
||||
Uint8List get _bytes {
|
||||
final bytes = _recordFile.readAsBytesSync();
|
||||
File(_recordPath).deleteSync();
|
||||
final bytes = _recordFile!.readAsBytesSync();
|
||||
File(_recordPath!).deleteSync();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
|
||||
void _disposePlayer() {
|
||||
if (_videoPlayerController != null) {
|
||||
_videoPlayerController.dispose();
|
||||
_videoPlayerController!.dispose();
|
||||
}
|
||||
_videoPlayerController = null;
|
||||
}
|
||||
@@ -81,24 +81,24 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("Audio record")),
|
||||
title: Text(tr("Audio record")!),
|
||||
content: _buildContent(),
|
||||
actions: <Widget>[
|
||||
_ActionButton(
|
||||
visible: !_recording,
|
||||
text: tr("Cancel"),
|
||||
text: tr("Cancel")!,
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
_ActionButton(
|
||||
visible: _hasRecord,
|
||||
text: tr("Send"),
|
||||
text: tr("Send")!,
|
||||
onPressed: () => Navigator.of(context).pop(_bytes),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String get _status {
|
||||
String? get _status {
|
||||
if (_recording)
|
||||
return tr("Recording...");
|
||||
else if (_paused)
|
||||
@@ -113,7 +113,7 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
|
||||
Widget _buildContent() => Row(
|
||||
children: <Widget>[
|
||||
Text(_status),
|
||||
Text(_status!),
|
||||
|
||||
Spacer(),
|
||||
|
||||
@@ -165,21 +165,21 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
|
||||
void _startRecording() async {
|
||||
try {
|
||||
if (_recordFile != null) _recordFile.deleteSync();
|
||||
if (_recordFile != null) _recordFile!.deleteSync();
|
||||
|
||||
final dir = await getTemporaryDirectory();
|
||||
|
||||
_recordPath = path.join(dir.absolute.path, "tmp-audio-record.mp3");
|
||||
|
||||
RecordMp3.instance.start(_recordPath, (fail) {
|
||||
RecordMp3.instance.start(_recordPath!, (fail) {
|
||||
print(fail);
|
||||
snack(context, tr("Failed to start recording!"));
|
||||
snack(context, tr("Failed to start recording!")!);
|
||||
});
|
||||
|
||||
setState(() => _recording = true);
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Error while recording!"));
|
||||
snack(context, tr("Error while recording!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
setState(() => _recording = false);
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Error while recording!"));
|
||||
snack(context, tr("Error while recording!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,17 +198,17 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
try {
|
||||
_disposePlayer();
|
||||
|
||||
_videoPlayerController = VideoPlayerController.file(File(_recordPath));
|
||||
await _videoPlayerController.initialize();
|
||||
_videoPlayerController = VideoPlayerController.file(File(_recordPath!));
|
||||
await _videoPlayerController!.initialize();
|
||||
|
||||
_videoPlayerController.addListener(() async {
|
||||
_videoPlayerController!.addListener(() async {
|
||||
if (_videoPlayerController == null) return;
|
||||
|
||||
if (_videoPlayerController.value.position ==
|
||||
_videoPlayerController.value.duration) _stopPlayback();
|
||||
if (_videoPlayerController!.value.position ==
|
||||
_videoPlayerController!.value.duration) _stopPlayback();
|
||||
});
|
||||
|
||||
await _videoPlayerController.play();
|
||||
await _videoPlayerController!.play();
|
||||
|
||||
setState(() {
|
||||
_playing = true;
|
||||
@@ -216,27 +216,27 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
});
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Error while playing record!"));
|
||||
snack(context, tr("Error while playing record!")!);
|
||||
}
|
||||
}
|
||||
|
||||
void _pausePlayback() async {
|
||||
try {
|
||||
await _videoPlayerController.pause();
|
||||
await _videoPlayerController!.pause();
|
||||
setState(() => _paused = true);
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Error while pausing playback!"));
|
||||
snack(context, tr("Error while pausing playback!")!);
|
||||
}
|
||||
}
|
||||
|
||||
void _resumePlayback() async {
|
||||
try {
|
||||
await _videoPlayerController.play();
|
||||
await _videoPlayerController!.play();
|
||||
setState(() => _paused = false);
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Error while resuming playback!"));
|
||||
snack(context, tr("Error while resuming playback!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ class __RecordAudioDialogState extends State<_RecordAudioDialog> {
|
||||
});
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Error while stopping playback!"));
|
||||
snack(context, tr("Error while stopping playback!")!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,13 +258,13 @@ class _RecordAction extends StatelessWidget {
|
||||
final bool visible;
|
||||
final IconData icon;
|
||||
final void Function() onTap;
|
||||
final Color color;
|
||||
final Color? color;
|
||||
|
||||
const _RecordAction({
|
||||
Key key,
|
||||
@required this.visible,
|
||||
@required this.icon,
|
||||
@required this.onTap,
|
||||
Key? key,
|
||||
required this.visible,
|
||||
required this.icon,
|
||||
required this.onTap,
|
||||
this.color,
|
||||
}) : assert(visible != null),
|
||||
assert(icon != null),
|
||||
@@ -280,12 +280,12 @@ class _RecordAction extends StatelessWidget {
|
||||
class _ActionButton extends StatelessWidget {
|
||||
final bool visible;
|
||||
final String text;
|
||||
final void Function() onPressed;
|
||||
final void Function()? onPressed;
|
||||
|
||||
const _ActionButton({
|
||||
Key key,
|
||||
this.visible,
|
||||
this.text,
|
||||
Key? key,
|
||||
required this.visible,
|
||||
required this.text,
|
||||
this.onPressed,
|
||||
}) : assert(visible != null),
|
||||
assert(text != null),
|
||||
|
@@ -11,7 +11,7 @@ import 'package:flutter/material.dart';
|
||||
///
|
||||
/// This widget automatically adapt himself if we are in tablet
|
||||
/// or in mobile mode
|
||||
Future<T> showScreenDialog<T>(BuildContext context, Widget screen) async {
|
||||
Future<T?> showScreenDialog<T>(BuildContext context, Widget screen) async {
|
||||
// TODO : add mobile support
|
||||
if (!isTablet(context)) throw Exception("Unsupported mode!");
|
||||
|
||||
@@ -20,9 +20,9 @@ Future<T> showScreenDialog<T>(BuildContext context, Widget screen) async {
|
||||
}
|
||||
|
||||
class _ScreenDialog extends StatelessWidget {
|
||||
final Widget body;
|
||||
final Widget? body;
|
||||
|
||||
const _ScreenDialog({Key key, this.body}) : super(key: key);
|
||||
const _ScreenDialog({Key? key, this.body}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@@ -7,23 +7,23 @@ import 'package:flutter/material.dart';
|
||||
|
||||
class SingleInputDialog extends StatefulWidget {
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final String initialValue;
|
||||
final IconData? icon;
|
||||
final String? initialValue;
|
||||
final String label;
|
||||
final bool Function(String) checkInput;
|
||||
final String errorMessage;
|
||||
final bool canBeEmpty;
|
||||
final int maxLines;
|
||||
final int maxLength;
|
||||
final int? maxLength;
|
||||
|
||||
const SingleInputDialog({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.icon,
|
||||
@required this.initialValue,
|
||||
@required this.label,
|
||||
@required this.checkInput,
|
||||
@required this.errorMessage,
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
required this.initialValue,
|
||||
required this.label,
|
||||
required this.checkInput,
|
||||
required this.errorMessage,
|
||||
this.canBeEmpty = false,
|
||||
this.maxLines = 1,
|
||||
this.maxLength,
|
||||
@@ -39,11 +39,11 @@ class SingleInputDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class __InputURLDialogState extends State<SingleInputDialog> {
|
||||
TextEditingController _controller;
|
||||
TextEditingController? _controller;
|
||||
|
||||
bool get _isValid =>
|
||||
(_controller.text.isEmpty && widget.canBeEmpty) ||
|
||||
(_controller.text.isNotEmpty && widget.checkInput(_controller.text));
|
||||
(_controller!.text.isEmpty && widget.canBeEmpty) ||
|
||||
(_controller!.text.isNotEmpty && widget.checkInput(_controller!.text));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -64,7 +64,7 @@ class __InputURLDialogState extends State<SingleInputDialog> {
|
||||
icon: widget.icon == null ? null : Icon(widget.icon),
|
||||
alignLabelWithHint: true,
|
||||
labelText: widget.label,
|
||||
errorText: _controller.text.isNotEmpty && !_isValid
|
||||
errorText: _controller!.text.isNotEmpty && !_isValid
|
||||
? widget.errorMessage
|
||||
: null,
|
||||
),
|
||||
@@ -72,16 +72,16 @@ class __InputURLDialogState extends State<SingleInputDialog> {
|
||||
actions: <Widget>[
|
||||
// Cancel
|
||||
MaterialButton(
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
textColor: Colors.red,
|
||||
),
|
||||
|
||||
// Confirm
|
||||
MaterialButton(
|
||||
child: Text(tr("Confirm").toUpperCase()),
|
||||
child: Text(tr("Confirm")!.toUpperCase()),
|
||||
onPressed: _isValid
|
||||
? () => Navigator.of(context).pop(_controller.text)
|
||||
? () => Navigator.of(context).pop(_controller!.text)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
|
@@ -12,11 +12,11 @@ enum VirtualDirectoryTargetType { USER, GROUP }
|
||||
|
||||
enum _CheckStatus { EMPTY, PENDING, VALID, INVALID }
|
||||
|
||||
Future<String> showVirtualDirectoryDialog({
|
||||
@required BuildContext context,
|
||||
@required String initialDirectory,
|
||||
@required int id,
|
||||
@required VirtualDirectoryTargetType type,
|
||||
Future<String?> showVirtualDirectoryDialog({
|
||||
required BuildContext context,
|
||||
required String initialDirectory,
|
||||
required int id,
|
||||
required VirtualDirectoryTargetType type,
|
||||
}) async {
|
||||
assert(context != null);
|
||||
assert(initialDirectory != null);
|
||||
@@ -35,10 +35,10 @@ class _VirtualDirectoryPicker extends StatefulWidget {
|
||||
final VirtualDirectoryTargetType type;
|
||||
|
||||
const _VirtualDirectoryPicker({
|
||||
Key key,
|
||||
@required this.initialDirectory,
|
||||
@required this.id,
|
||||
@required this.type,
|
||||
Key? key,
|
||||
required this.initialDirectory,
|
||||
required this.id,
|
||||
required this.type,
|
||||
}) : assert(initialDirectory != null),
|
||||
assert(id != null),
|
||||
assert(type != null),
|
||||
@@ -50,10 +50,10 @@ class _VirtualDirectoryPicker extends StatefulWidget {
|
||||
}
|
||||
|
||||
class __VirtualDirectoryPickerState extends SafeState<_VirtualDirectoryPicker> {
|
||||
TextEditingController _controller;
|
||||
TextEditingController? _controller;
|
||||
var _status = _CheckStatus.VALID;
|
||||
|
||||
String get _currentValue => _controller.text;
|
||||
String get _currentValue => _controller!.text;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -64,7 +64,7 @@ class __VirtualDirectoryPickerState extends SafeState<_VirtualDirectoryPicker> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(tr("Choose a virtual directory")),
|
||||
title: Text(tr("Choose a virtual directory")!),
|
||||
|
||||
// Dialog content
|
||||
content: TextField(
|
||||
@@ -89,7 +89,7 @@ class __VirtualDirectoryPickerState extends SafeState<_VirtualDirectoryPicker> {
|
||||
// Cancel
|
||||
MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
),
|
||||
|
||||
// Confirm
|
||||
@@ -98,7 +98,7 @@ class __VirtualDirectoryPickerState extends SafeState<_VirtualDirectoryPicker> {
|
||||
_status == _CheckStatus.VALID || _status == _CheckStatus.EMPTY
|
||||
? () => Navigator.of(context).pop(_currentValue)
|
||||
: null,
|
||||
child: Text(tr("Confirm").toUpperCase()),
|
||||
child: Text(tr("Confirm")!.toUpperCase()),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
Reference in New Issue
Block a user