mirror of
https://gitlab.com/comunic/comunicmobile
synced 2025-06-20 08:45:17 +00:00
Start to fix null safety migration errors
This commit is contained in:
@ -15,9 +15,9 @@ class FriendshipStatusWidget extends StatefulWidget {
|
||||
final void Function() onFriendshipUpdated;
|
||||
|
||||
const FriendshipStatusWidget({
|
||||
Key key,
|
||||
@required this.status,
|
||||
@required this.onFriendshipUpdated,
|
||||
Key? key,
|
||||
required this.status,
|
||||
required this.onFriendshipUpdated,
|
||||
}) : assert(status != null),
|
||||
assert(onFriendshipUpdated != null),
|
||||
super(key: key);
|
||||
@ -48,7 +48,7 @@ class _FriendshipStatusWidgetState extends State<FriendshipStatusWidget> {
|
||||
// No request sent yet
|
||||
if (widget.status.noRequestExchanged) {
|
||||
return ElevatedButton(
|
||||
child: Text(tr("Send request").toUpperCase()),
|
||||
child: Text(tr("Send request")!.toUpperCase()),
|
||||
onPressed: () =>
|
||||
executeRequest(() => _friendsHelper.sendRequest(friendID)),
|
||||
);
|
||||
@ -58,7 +58,7 @@ class _FriendshipStatusWidgetState extends State<FriendshipStatusWidget> {
|
||||
if (widget.status.sentRequest) {
|
||||
return ElevatedButton(
|
||||
child: Text(
|
||||
tr("Cancel request").toUpperCase(),
|
||||
tr("Cancel request")!.toUpperCase(),
|
||||
style: WhiteTextColorStyle,
|
||||
),
|
||||
style:
|
||||
@ -74,7 +74,7 @@ class _FriendshipStatusWidgetState extends State<FriendshipStatusWidget> {
|
||||
children: <Widget>[
|
||||
ElevatedButton(
|
||||
child: Text(
|
||||
tr("Accept request").toUpperCase(),
|
||||
tr("Accept request")!.toUpperCase(),
|
||||
style: WhiteTextColorStyle,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
@ -84,7 +84,7 @@ class _FriendshipStatusWidgetState extends State<FriendshipStatusWidget> {
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text(
|
||||
tr("Reject request").toUpperCase(),
|
||||
tr("Reject request")!.toUpperCase(),
|
||||
style: WhiteTextColorStyle,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
@ -98,7 +98,7 @@ class _FriendshipStatusWidgetState extends State<FriendshipStatusWidget> {
|
||||
|
||||
// The two users are friends, offers to follow him
|
||||
return ElevatedButton(
|
||||
child: Text((widget.status.following ? tr("Following") : tr("Follow"))
|
||||
child: Text((widget.status.following ? tr("Following") : tr("Follow"))!
|
||||
.toUpperCase()),
|
||||
onPressed: () => executeRequest(() =>
|
||||
_friendsHelper.setFollowing(friendID, !widget.status.following)),
|
||||
@ -110,7 +110,7 @@ class _FriendshipStatusWidgetState extends State<FriendshipStatusWidget> {
|
||||
setSentRequest(true);
|
||||
|
||||
if (!await func())
|
||||
showSimpleSnack(context, tr("Could not update your membership!"));
|
||||
showSimpleSnack(context, tr("Could not update your membership!")!);
|
||||
|
||||
widget.onFriendshipUpdated();
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ class AccountImageWidget extends StatelessWidget {
|
||||
final double width;
|
||||
|
||||
const AccountImageWidget({
|
||||
Key key,
|
||||
this.user,
|
||||
Key? key,
|
||||
required this.user,
|
||||
this.width = 35.0,
|
||||
}) : assert(user != null),
|
||||
super(key: key);
|
||||
@ -23,7 +23,7 @@ class AccountImageWidget extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: user.accountImageURL,
|
||||
imageUrl: user.accountImageURL!,
|
||||
width: width,
|
||||
height: width,
|
||||
fit: BoxFit.cover,
|
||||
|
@ -31,18 +31,18 @@ class AsyncScreenWidget extends StatefulWidget {
|
||||
/// Widget to use while we are refreshing
|
||||
///
|
||||
/// This widget is optional
|
||||
final Widget loadingWidget;
|
||||
final Widget? loadingWidget;
|
||||
|
||||
/// Widget to use in case of error
|
||||
///
|
||||
/// This widget is optional
|
||||
final Widget errorWidget;
|
||||
final Widget? errorWidget;
|
||||
|
||||
const AsyncScreenWidget({
|
||||
Key key,
|
||||
@required this.onReload,
|
||||
@required this.onBuild,
|
||||
@required this.errorMessage,
|
||||
Key? key,
|
||||
required this.onReload,
|
||||
required this.onBuild,
|
||||
required this.errorMessage,
|
||||
this.showOldDataWhileUpdating = false,
|
||||
this.loadingWidget,
|
||||
this.errorWidget,
|
||||
@ -76,7 +76,7 @@ class AsyncScreenWidgetState extends SafeState<AsyncScreenWidget> {
|
||||
MaterialButton(
|
||||
textColor: Colors.white,
|
||||
onPressed: () => refresh(),
|
||||
child: Text(tr("Try again").toUpperCase()),
|
||||
child: Text(tr("Try again")!.toUpperCase()),
|
||||
)
|
||||
]);
|
||||
|
||||
|
@ -10,14 +10,14 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
bool _bannerDismissed = false;
|
||||
|
||||
class BannerWidget extends StatefulWidget {
|
||||
const BannerWidget({Key key}) : super(key: key);
|
||||
const BannerWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BannerWidgetState createState() => _BannerWidgetState();
|
||||
}
|
||||
|
||||
class _BannerWidgetState extends State<BannerWidget> {
|
||||
Timer _timer;
|
||||
Timer? _timer;
|
||||
|
||||
bool get _shouldShowBanner => showBanner && !_bannerDismissed;
|
||||
|
||||
@ -26,22 +26,22 @@ class _BannerWidgetState extends State<BannerWidget> {
|
||||
}
|
||||
|
||||
void _openLink() {
|
||||
launch(srvConfig.banner.link);
|
||||
launch(srvConfig!.banner!.link!);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
if (_shouldShowBanner && srvConfig.banner.expire != null) {
|
||||
if (_shouldShowBanner && srvConfig!.banner!.expire != null) {
|
||||
_timer = Timer(
|
||||
Duration(seconds: srvConfig.banner.expire - time()), _hideBanner);
|
||||
Duration(seconds: srvConfig!.banner!.expire! - time()), _hideBanner);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_timer != null) _timer.cancel();
|
||||
if (_timer != null) _timer!.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class _BannerWidgetState extends State<BannerWidget> {
|
||||
Widget build(BuildContext context) {
|
||||
if (!_shouldShowBanner) return Container();
|
||||
|
||||
final banner = srvConfig.banner;
|
||||
final banner = srvConfig!.banner!;
|
||||
return Card(
|
||||
color: banner.nature == BannerNature.Information
|
||||
? Colors.blue
|
||||
@ -72,8 +72,8 @@ class _BannerWidgetState extends State<BannerWidget> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
banner.message.containsKey(shortLang)
|
||||
? banner.message[shortLang]
|
||||
: banner.message["en"],
|
||||
? banner.message[shortLang]!
|
||||
: banner.message["en"]!,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
@ -95,16 +95,16 @@ class _BannerWidgetState extends State<BannerWidget> {
|
||||
}
|
||||
|
||||
class BannerButton extends StatelessWidget {
|
||||
final Function() onPressed;
|
||||
final Widget icon;
|
||||
final Function()? onPressed;
|
||||
final Widget? icon;
|
||||
|
||||
const BannerButton({this.onPressed, this.icon, Key key}) : super(key: key);
|
||||
const BannerButton({this.onPressed, this.icon, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: onPressed,
|
||||
icon: icon,
|
||||
icon: icon!,
|
||||
color: Colors.white,
|
||||
disabledColor: Colors.white,
|
||||
padding: EdgeInsets.all(1.0),
|
||||
|
@ -19,9 +19,9 @@ class ConversationFileWidget extends StatefulWidget {
|
||||
final ConversationMessageFile file;
|
||||
|
||||
const ConversationFileWidget({
|
||||
Key key,
|
||||
@required this.messageID,
|
||||
@required this.file,
|
||||
Key? key,
|
||||
required this.messageID,
|
||||
required this.file,
|
||||
}) : assert(messageID != null),
|
||||
assert(file != null),
|
||||
super(key: key);
|
||||
@ -44,7 +44,7 @@ class _ConversationFileWidgetState extends State<ConversationFileWidget> {
|
||||
: Opacity(
|
||||
opacity: 0.8,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: file.thumbnail,
|
||||
imageUrl: file.thumbnail!,
|
||||
width: _AreaWidth,
|
||||
height: _AreaHeight,
|
||||
fit: BoxFit.cover,
|
||||
@ -64,7 +64,7 @@ class _ConversationFileWidgetState extends State<ConversationFileWidget> {
|
||||
case ConversationMessageFileType.IMAGE:
|
||||
return Center(
|
||||
child: NetworkImageWidget(
|
||||
url: file.url,
|
||||
url: file.url!,
|
||||
thumbnailURL: file.thumbnail,
|
||||
allowFullScreen: true,
|
||||
),
|
||||
@ -83,9 +83,9 @@ class _ConversationFileWidgetState extends State<ConversationFileWidget> {
|
||||
Icon(file.icon, color: Colors.white),
|
||||
Spacer(),
|
||||
Text(
|
||||
file.name.length < 23
|
||||
? file.name
|
||||
: file.name.substring(0, 20) + "...",
|
||||
file.name!.length < 23
|
||||
? file.name!
|
||||
: file.name!.substring(0, 20) + "...",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
@ -112,15 +112,15 @@ class _ConversationFileWidgetState extends State<ConversationFileWidget> {
|
||||
break;
|
||||
|
||||
case ConversationMessageFileType.VIDEO:
|
||||
MainController.of(context).push(
|
||||
VideoPlayerRoute(url: file.url),
|
||||
MainController.of(context)!.push(
|
||||
VideoPlayerRoute(url: file.url!),
|
||||
hideNavBar: true,
|
||||
canShowAsDialog: true,
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
launch(file.url);
|
||||
launch(file.url!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,13 +14,13 @@ class ConversationImageWidget extends StatelessWidget {
|
||||
final Conversation conversation;
|
||||
final UsersList users;
|
||||
final double size;
|
||||
final Group group;
|
||||
final bool noUserImage;
|
||||
final Group? group;
|
||||
final bool? noUserImage;
|
||||
|
||||
const ConversationImageWidget({
|
||||
Key key,
|
||||
@required this.conversation,
|
||||
@required this.users,
|
||||
Key? key,
|
||||
required this.conversation,
|
||||
required this.users,
|
||||
this.group,
|
||||
this.size = 30,
|
||||
this.noUserImage,
|
||||
@ -42,26 +42,26 @@ class ConversationImageWidget extends StatelessWidget {
|
||||
Widget _buildIcon() {
|
||||
if (conversation.logoURL != null)
|
||||
return CachedNetworkImage(
|
||||
imageUrl: conversation.logoURL,
|
||||
imageUrl: conversation.logoURL!,
|
||||
width: size,
|
||||
);
|
||||
|
||||
if (group != null) {
|
||||
return CachedNetworkImage(
|
||||
imageUrl: group.iconURL,
|
||||
imageUrl: group!.iconURL,
|
||||
width: size,
|
||||
);
|
||||
}
|
||||
|
||||
if (noUserImage == true) return Container(width: size);
|
||||
|
||||
if (conversation.members.length < 2)
|
||||
if (conversation.members!.length < 2)
|
||||
return Icon(
|
||||
Icons.lock,
|
||||
size: size,
|
||||
);
|
||||
|
||||
if (conversation.members.length == 2)
|
||||
if (conversation.members!.length == 2)
|
||||
return AccountImageWidget(
|
||||
width: size,
|
||||
user: users.getUser(conversation.otherMembersID.first),
|
||||
@ -80,9 +80,9 @@ class MultipleAccountImagesWidget extends StatelessWidget {
|
||||
final double size;
|
||||
|
||||
const MultipleAccountImagesWidget({
|
||||
Key key,
|
||||
@required this.users,
|
||||
@required this.size,
|
||||
Key? key,
|
||||
required this.users,
|
||||
required this.size,
|
||||
}) : assert(users != null),
|
||||
assert(size != null),
|
||||
assert(size > 0),
|
||||
|
@ -18,7 +18,7 @@ class CopyIcon extends StatelessWidget {
|
||||
icon: Icon(Icons.content_copy),
|
||||
onPressed: () {
|
||||
FlutterClipboard.copy(value);
|
||||
snack(context, tr("'%c%' was copied to clipboard", args: {"c": value}));
|
||||
snack(context, tr("'%c%' was copied to clipboard", args: {"c": value})!);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ class CountdownWidget extends StatefulWidget {
|
||||
final int endTime;
|
||||
|
||||
const CountdownWidget({
|
||||
Key key,
|
||||
@required this.startTime,
|
||||
@required this.endTime,
|
||||
Key? key,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
}) : assert(startTime != null),
|
||||
assert(endTime != null),
|
||||
super(key: key);
|
||||
@ -29,7 +29,7 @@ class _CountdownWidgetState extends State<CountdownWidget> {
|
||||
|
||||
int get totalDuration => (widget.endTime - widget.startTime).abs();
|
||||
|
||||
String get remainingTimeStr {
|
||||
String? get remainingTimeStr {
|
||||
final remaining = Duration(seconds: remainingTime.abs());
|
||||
|
||||
return tr(
|
||||
@ -67,7 +67,7 @@ class _CountdownWidgetState extends State<CountdownWidget> {
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(remainingTimeStr),
|
||||
child: Text(remainingTimeStr!),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
|
@ -17,7 +17,7 @@ import 'new_password_input_widget.dart';
|
||||
class CreateAccountWidget extends StatefulWidget {
|
||||
final void Function() onCreated;
|
||||
|
||||
const CreateAccountWidget({Key key, @required this.onCreated})
|
||||
const CreateAccountWidget({Key? key, required this.onCreated})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@ -30,28 +30,28 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordInputKey = GlobalKey<NewPasswordInputWidgetState>();
|
||||
final _verifyPasswordController = TextEditingController();
|
||||
bool _acceptedTOS = false;
|
||||
bool? _acceptedTOS = false;
|
||||
|
||||
bool _isCreating = false;
|
||||
CreateAccountResult _createAccountResult;
|
||||
CreateAccountResult? _createAccountResult;
|
||||
|
||||
bool _showErrors = false;
|
||||
|
||||
bool get _isFirstNameValid =>
|
||||
_firstNameController.text.length >=
|
||||
srvConfig.accountInformationPolicy.minFirstNameLength;
|
||||
srvConfig!.accountInformationPolicy.minFirstNameLength;
|
||||
|
||||
bool get _isLastNameValid =>
|
||||
_lastNameController.text.length >=
|
||||
srvConfig.accountInformationPolicy.minLastNameLength;
|
||||
srvConfig!.accountInformationPolicy.minLastNameLength;
|
||||
|
||||
bool get _isEmailValid => validateEmail(_emailController.text);
|
||||
|
||||
bool get _isPasswordValid => _passwordInputKey.currentState.valid;
|
||||
bool get _isPasswordValid => _passwordInputKey.currentState!.valid;
|
||||
|
||||
bool get _isPasswordConfirmationValid =>
|
||||
_passwordInputKey.currentState != null &&
|
||||
_passwordInputKey.currentState.value == _verifyPasswordController.text;
|
||||
_passwordInputKey.currentState!.value == _verifyPasswordController.text;
|
||||
|
||||
bool get _isFormValid =>
|
||||
_isFirstNameValid &&
|
||||
@ -59,9 +59,9 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
_isEmailValid &&
|
||||
_isPasswordValid &&
|
||||
_isPasswordConfirmationValid &&
|
||||
_acceptedTOS;
|
||||
_acceptedTOS!;
|
||||
|
||||
String get errorMessage => _createAccountResult ==
|
||||
String? get errorMessage => _createAccountResult ==
|
||||
CreateAccountResult.ERROR_EXISTING_EMAIL
|
||||
? tr("An account is already associated to this email address!")
|
||||
: _createAccountResult == CreateAccountResult.ERROR_TOO_MANY_REQUESTS
|
||||
@ -91,11 +91,11 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
// First name
|
||||
_InputEntry(
|
||||
controller: _firstNameController,
|
||||
label: tr("First name"),
|
||||
label: tr("First name")!,
|
||||
onEdited: _updateUI,
|
||||
icon: Icon(Icons.perm_identity),
|
||||
maxLength:
|
||||
srvConfig.accountInformationPolicy.maxFirstNameLength,
|
||||
srvConfig!.accountInformationPolicy.maxFirstNameLength,
|
||||
error: _showErrors && !_isFirstNameValid
|
||||
? tr("Invalid first name!")
|
||||
: null,
|
||||
@ -104,10 +104,10 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
// Last name
|
||||
_InputEntry(
|
||||
controller: _lastNameController,
|
||||
label: tr("Last name"),
|
||||
label: tr("Last name")!,
|
||||
onEdited: _updateUI,
|
||||
icon: Icon(Icons.perm_identity),
|
||||
maxLength: srvConfig.accountInformationPolicy.maxLastNameLength,
|
||||
maxLength: srvConfig!.accountInformationPolicy.maxLastNameLength,
|
||||
error: _showErrors && !_isLastNameValid
|
||||
? tr("Invalid last name!")
|
||||
: null,
|
||||
@ -116,7 +116,7 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
// Email address
|
||||
_InputEntry(
|
||||
controller: _emailController,
|
||||
label: tr("Email address"),
|
||||
label: tr("Email address")!,
|
||||
onEdited: _updateUI,
|
||||
icon: Icon(Icons.email),
|
||||
keyboard: TextInputType.emailAddress,
|
||||
@ -128,7 +128,7 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
// Password
|
||||
NewPasswordInputWidget(
|
||||
key: _passwordInputKey,
|
||||
label: tr("Password"),
|
||||
label: tr("Password")!,
|
||||
onEdited: _updateUI,
|
||||
icon: Icon(Icons.lock),
|
||||
user: UserInfoForPassword(
|
||||
@ -141,7 +141,7 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
// Verify password
|
||||
_InputEntry(
|
||||
controller: _verifyPasswordController,
|
||||
label: tr("Confirm your password"),
|
||||
label: tr("Confirm your password")!,
|
||||
onEdited: _updateUI,
|
||||
icon: Icon(Icons.lock_outline),
|
||||
isPassword: true,
|
||||
@ -155,15 +155,15 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
// TOS
|
||||
CheckboxListTile(
|
||||
title:
|
||||
Text(tr("I have read and accepted the Terms Of Service.")),
|
||||
Text(tr("I have read and accepted the Terms Of Service.")!),
|
||||
value: _acceptedTOS,
|
||||
onChanged: (b) {
|
||||
_acceptedTOS = b;
|
||||
_updateUI();
|
||||
},
|
||||
subtitle: _showErrors && !_acceptedTOS
|
||||
subtitle: _showErrors && !_acceptedTOS!
|
||||
? Text(
|
||||
tr("You must accept the Terms Of Service to continue."),
|
||||
tr("You must accept the Terms Of Service to continue.")!,
|
||||
style: TextStyle(color: Colors.redAccent),
|
||||
)
|
||||
: null,
|
||||
@ -180,7 +180,7 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: _submitForm,
|
||||
child: Text(tr("Create account")),
|
||||
child: Text(tr("Create account")!),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -211,7 +211,7 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
firstName: _firstNameController.text,
|
||||
lastName: _lastNameController.text,
|
||||
email: _emailController.text,
|
||||
password: _passwordInputKey.currentState.value,
|
||||
password: _passwordInputKey.currentState!.value,
|
||||
));
|
||||
|
||||
setState(() {
|
||||
@ -228,17 +228,17 @@ class _CreateAccountWidgetState extends State<CreateAccountWidget> {
|
||||
widget.onCreated();
|
||||
}
|
||||
|
||||
void _openTOS() => launch(ServerConfigurationHelper.config.termsURL);
|
||||
void _openTOS() => launch(ServerConfigurationHelper.config!.termsURL);
|
||||
|
||||
void _showCreateAccountError() async {
|
||||
await showCupertinoDialog(
|
||||
context: context,
|
||||
builder: (c) => CupertinoAlertDialog(
|
||||
title: Text(tr("Error while creating your account")),
|
||||
content: Text(errorMessage),
|
||||
title: Text(tr("Error while creating your account")!),
|
||||
content: Text(errorMessage!),
|
||||
actions: <Widget>[
|
||||
CupertinoButton(
|
||||
child: Text(tr("Ok").toUpperCase()),
|
||||
child: Text(tr("Ok")!.toUpperCase()),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
)
|
||||
],
|
||||
@ -252,16 +252,16 @@ class _InputEntry extends StatelessWidget {
|
||||
final String label;
|
||||
final VoidCallback onEdited;
|
||||
final bool isPassword;
|
||||
final String error;
|
||||
final Widget icon;
|
||||
final TextInputType keyboard;
|
||||
final int maxLength;
|
||||
final String? error;
|
||||
final Widget? icon;
|
||||
final TextInputType? keyboard;
|
||||
final int? maxLength;
|
||||
|
||||
const _InputEntry({
|
||||
Key key,
|
||||
@required this.controller,
|
||||
@required this.label,
|
||||
@required this.onEdited,
|
||||
Key? key,
|
||||
required this.controller,
|
||||
required this.label,
|
||||
required this.onEdited,
|
||||
this.isPassword = false,
|
||||
this.error,
|
||||
this.icon,
|
||||
|
@ -9,7 +9,7 @@ class AppBarWrapper extends StatelessWidget implements PreferredSizeWidget {
|
||||
final Widget appBar;
|
||||
final double height;
|
||||
|
||||
const AppBarWrapper({@required this.height, @required this.appBar})
|
||||
const AppBarWrapper({required this.height, required this.appBar})
|
||||
: assert(height != null),
|
||||
assert(appBar != null),
|
||||
super();
|
||||
|
@ -6,27 +6,27 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
class CustomListTile extends StatelessWidget {
|
||||
final Widget leading;
|
||||
final Widget title;
|
||||
final Widget subtitle;
|
||||
final Widget trailing;
|
||||
final Widget? leading;
|
||||
final Widget? title;
|
||||
final Widget? subtitle;
|
||||
final Widget? trailing;
|
||||
final bool isThreeLine;
|
||||
final bool dense;
|
||||
final EdgeInsetsGeometry contentPadding;
|
||||
final bool? dense;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
final bool enabled;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureLongPressCallback onLongPress;
|
||||
final GestureTapCallback? onTap;
|
||||
final GestureLongPressCallback? onLongPress;
|
||||
final bool selected;
|
||||
final Color tileColor;
|
||||
final Color? tileColor;
|
||||
|
||||
/// Custom onLongPress function
|
||||
final Function(Size, Offset) onLongPressWithInfo;
|
||||
final Function(Size, Offset)? onLongPressWithInfo;
|
||||
|
||||
/// Show menu onLongPress
|
||||
final Function(RelativeRect) onLongPressOpenMenu;
|
||||
final Function(RelativeRect)? onLongPressOpenMenu;
|
||||
|
||||
const CustomListTile({
|
||||
Key key,
|
||||
Key? key,
|
||||
this.leading,
|
||||
this.title,
|
||||
this.subtitle,
|
||||
@ -66,14 +66,14 @@ class CustomListTile extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _longPress(BuildContext context) {
|
||||
if (onLongPress != null) onLongPress();
|
||||
if (onLongPress != null) onLongPress!();
|
||||
|
||||
if (onLongPressWithInfo != null || onLongPressOpenMenu != null) {
|
||||
RenderBox renderBox = context.findRenderObject();
|
||||
RenderBox renderBox = context.findRenderObject() as RenderBox;
|
||||
final size = renderBox.size;
|
||||
final offset = renderBox.localToGlobal(Offset(size.width, size.height));
|
||||
|
||||
if (onLongPressWithInfo != null) onLongPressWithInfo(size, offset);
|
||||
if (onLongPressWithInfo != null) onLongPressWithInfo!(size, offset);
|
||||
|
||||
if (onLongPressOpenMenu != null) {
|
||||
final position = RelativeRect.fromLTRB(
|
||||
@ -83,7 +83,7 @@ class CustomListTile extends StatelessWidget {
|
||||
offset.dy + size.height,
|
||||
);
|
||||
|
||||
onLongPressOpenMenu(position);
|
||||
onLongPressOpenMenu!(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ class AutoSizeDialogContentWidget extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const AutoSizeDialogContentWidget({
|
||||
Key key,
|
||||
@required this.child,
|
||||
Key? key,
|
||||
required this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -10,7 +10,7 @@ class CancelDialogButton extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
textColor: Colors.red,
|
||||
);
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ class ConfirmDialogButton<T> extends StatelessWidget {
|
||||
final T value;
|
||||
|
||||
const ConfirmDialogButton({
|
||||
Key key,
|
||||
Key? key,
|
||||
this.enabled = true,
|
||||
@required this.value,
|
||||
required this.value,
|
||||
}) : assert(enabled != null),
|
||||
super(key: key);
|
||||
|
||||
@ -20,7 +20,7 @@ class ConfirmDialogButton<T> extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialButton(
|
||||
onPressed: enabled ? () => Navigator.of(context).pop(value) : null,
|
||||
child: Text(tr("Confirm").toUpperCase()),
|
||||
child: Text(tr("Confirm")!.toUpperCase()),
|
||||
textColor: Colors.green,
|
||||
);
|
||||
}
|
||||
|
@ -11,18 +11,18 @@ import 'package:table_calendar/table_calendar.dart';
|
||||
enum CalendarDisplayMode { SINGLE_USER, MULTIPLE_USERS }
|
||||
|
||||
extension DateOnlyCompare on DateTime {
|
||||
bool isSameDate(DateTime other) => date_utils.isSameDate(this, other);
|
||||
bool isSameDate(DateTime? other) => date_utils.isSameDate(this, other);
|
||||
}
|
||||
|
||||
class PresenceCalendarWidget extends StatefulWidget {
|
||||
final PresenceSet presenceSet;
|
||||
final void Function(DateTime) onDayClicked;
|
||||
final void Function(DateTime)? onDayClicked;
|
||||
final CalendarDisplayMode mode;
|
||||
final DateTime selectedDay;
|
||||
final DateTime? selectedDay;
|
||||
|
||||
const PresenceCalendarWidget({
|
||||
Key key,
|
||||
@required this.presenceSet,
|
||||
Key? key,
|
||||
required this.presenceSet,
|
||||
this.onDayClicked,
|
||||
this.mode = CalendarDisplayMode.SINGLE_USER,
|
||||
this.selectedDay,
|
||||
@ -35,7 +35,7 @@ class PresenceCalendarWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _PresenceCalendarWidgetState extends State<PresenceCalendarWidget> {
|
||||
var selectedDay = DateTime.now();
|
||||
DateTime? selectedDay = DateTime.now();
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant PresenceCalendarWidget oldWidget) {
|
||||
@ -63,7 +63,7 @@ class _PresenceCalendarWidgetState extends State<PresenceCalendarWidget> {
|
||||
),
|
||||
onDaySelected: _selectedDay,
|
||||
availableCalendarFormats: const {CalendarFormat.month: "Mois"},
|
||||
focusedDay: selectedDay,
|
||||
focusedDay: selectedDay!,
|
||||
onPageChanged: (s) {
|
||||
setState(() {
|
||||
selectedDay = s;
|
||||
@ -129,21 +129,21 @@ class _PresenceCalendarWidgetState extends State<PresenceCalendarWidget> {
|
||||
}
|
||||
|
||||
void _selectedDay(DateTime selecteDay, DateTime focusedDay) {
|
||||
if (widget.onDayClicked != null) widget.onDayClicked(selecteDay);
|
||||
if (widget.onDayClicked != null) widget.onDayClicked!(selecteDay);
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
class CellWidget extends StatelessWidget {
|
||||
final String text;
|
||||
final Color color;
|
||||
final Color textColor;
|
||||
final Color? color;
|
||||
final Color? textColor;
|
||||
final bool circle;
|
||||
final bool selected;
|
||||
final bool? selected;
|
||||
|
||||
const CellWidget({
|
||||
Key key,
|
||||
@required this.text,
|
||||
Key? key,
|
||||
required this.text,
|
||||
this.color,
|
||||
this.textColor,
|
||||
this.circle = true,
|
||||
|
@ -12,13 +12,13 @@ import 'package:flutter/material.dart';
|
||||
class GroupFollowingWidget extends StatefulWidget {
|
||||
final Group group;
|
||||
final Function() onUpdated;
|
||||
final Color inactiveColor;
|
||||
final Color activeColor;
|
||||
final Color? inactiveColor;
|
||||
final Color? activeColor;
|
||||
|
||||
const GroupFollowingWidget({
|
||||
Key key,
|
||||
@required this.group,
|
||||
@required this.onUpdated,
|
||||
Key? key,
|
||||
required this.group,
|
||||
required this.onUpdated,
|
||||
this.activeColor,
|
||||
this.inactiveColor,
|
||||
}) : assert(group != null),
|
||||
@ -46,7 +46,7 @@ class _GroupFollowingWidgetState extends SafeState<GroupFollowingWidget> {
|
||||
color: _group.following ? widget.activeColor : widget.inactiveColor,
|
||||
)),
|
||||
TextSpan(
|
||||
text: " " + (_group.following ? tr("Following") : tr("Follow"))),
|
||||
text: " " + (_group.following ? tr("Following")! : tr("Follow")!)),
|
||||
]),
|
||||
),
|
||||
onTap: () => _toggleFollowing(),
|
||||
@ -56,7 +56,7 @@ class _GroupFollowingWidgetState extends SafeState<GroupFollowingWidget> {
|
||||
/// Toggle following status
|
||||
void _toggleFollowing() async {
|
||||
if (!await GroupsHelper().setFollowing(_group.id, !_group.following)) {
|
||||
showSimpleSnack(context, tr("Could not update following status!"));
|
||||
showSimpleSnack(context, tr("Could not update following status!")!);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ class GroupIcon extends StatelessWidget {
|
||||
final double width;
|
||||
|
||||
const GroupIcon({
|
||||
Key key,
|
||||
@required this.group,
|
||||
Key? key,
|
||||
required this.group,
|
||||
this.width = 50,
|
||||
}) : assert(group != null),
|
||||
assert(width != null),
|
||||
|
@ -12,11 +12,11 @@ import 'package:flutter/material.dart';
|
||||
|
||||
class GroupMembershipWidget extends StatefulWidget {
|
||||
final Group group;
|
||||
final Function() onUpdated;
|
||||
final Function() onError;
|
||||
final Function()? onUpdated;
|
||||
final Function()? onError;
|
||||
|
||||
const GroupMembershipWidget(
|
||||
{@required this.group, this.onUpdated, this.onError})
|
||||
{required this.group, this.onUpdated, this.onError})
|
||||
: assert(group != null);
|
||||
|
||||
@override
|
||||
@ -34,13 +34,13 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
Widget build(BuildContext context) {
|
||||
switch (_level) {
|
||||
case GroupMembershipLevel.ADMINISTRATOR:
|
||||
return Text(tr("Administrator"));
|
||||
return Text(tr("Administrator")!);
|
||||
|
||||
case GroupMembershipLevel.MODERATOR:
|
||||
return Text(tr("Moderator"));
|
||||
return Text(tr("Moderator")!);
|
||||
|
||||
case GroupMembershipLevel.MEMBER:
|
||||
return Text(tr("Member"));
|
||||
return Text(tr("Member")!);
|
||||
|
||||
case GroupMembershipLevel.INVITED:
|
||||
return _buildInvitedState();
|
||||
@ -63,7 +63,7 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
WidgetSpan(
|
||||
child: Icon(Icons.info_outline, size: 12),
|
||||
alignment: PlaceholderAlignment.middle),
|
||||
TextSpan(text: " " + tr("Invited") + " ", style: blackForWhiteTheme()),
|
||||
TextSpan(text: " " + tr("Invited")! + " ", style: blackForWhiteTheme()),
|
||||
TextSpan(
|
||||
text: tr("Accept"),
|
||||
style: TextStyle(color: Colors.green),
|
||||
@ -88,15 +88,15 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
return;
|
||||
|
||||
if (!await GroupsHelper.respondInvitation(_id, accept)) {
|
||||
showSimpleSnack(context, tr("Could not respond to your invitation!"));
|
||||
if (this.widget.onError != null) this.widget.onError();
|
||||
showSimpleSnack(context, tr("Could not respond to your invitation!")!);
|
||||
if (this.widget.onError != null) this.widget.onError!();
|
||||
} else {
|
||||
// Refresh state
|
||||
group.membershipLevel =
|
||||
accept ? GroupMembershipLevel.MEMBER : GroupMembershipLevel.VISITOR;
|
||||
this.setState(() {});
|
||||
|
||||
if (this.widget.onUpdated != null) this.widget.onUpdated();
|
||||
if (this.widget.onUpdated != null) this.widget.onUpdated!();
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
child: Icon(Icons.access_time, size: 12),
|
||||
alignment: PlaceholderAlignment.middle),
|
||||
TextSpan(
|
||||
text: " " + tr("Requested") + " ", style: blackForWhiteTheme()),
|
||||
text: " " + tr("Requested")! + " ", style: blackForWhiteTheme()),
|
||||
TextSpan(
|
||||
text: tr("Cancel"),
|
||||
style: TextStyle(color: Colors.blue),
|
||||
@ -120,14 +120,14 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
/// Cancel group membership request
|
||||
void _cancelRequest() async {
|
||||
if (!await GroupsHelper().cancelRequest(_id)) {
|
||||
showSimpleSnack(context, tr("Could not cancel your membership request!"));
|
||||
if (this.widget.onError != null) this.widget.onError();
|
||||
showSimpleSnack(context, tr("Could not cancel your membership request!")!);
|
||||
if (this.widget.onError != null) this.widget.onError!();
|
||||
} else {
|
||||
// Refresh state
|
||||
group.membershipLevel = GroupMembershipLevel.VISITOR;
|
||||
this.setState(() {});
|
||||
|
||||
if (this.widget.onUpdated != null) this.widget.onUpdated();
|
||||
if (this.widget.onUpdated != null) this.widget.onUpdated!();
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
Widget _buildVisitorState() {
|
||||
// Check if the user can request membership
|
||||
if (group.registrationLevel == GroupRegistrationLevel.CLOSED)
|
||||
return Text(tr("Closed registration"));
|
||||
return Text(tr("Closed registration")!);
|
||||
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
@ -149,14 +149,14 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
|
||||
/// Create new membership request
|
||||
void _requestMembership() async {
|
||||
if (!await GroupsHelper.sendRequest(_id)) {
|
||||
showSimpleSnack(context, tr("Could not send your membership request!"));
|
||||
if (this.widget.onError != null) this.widget.onError();
|
||||
showSimpleSnack(context, tr("Could not send your membership request!")!);
|
||||
if (this.widget.onError != null) this.widget.onError!();
|
||||
} else {
|
||||
// Refresh state
|
||||
group.membershipLevel = GroupMembershipLevel.PENDING;
|
||||
this.setState(() {});
|
||||
|
||||
if (this.widget.onUpdated != null) this.widget.onUpdated();
|
||||
if (this.widget.onUpdated != null) this.widget.onUpdated!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ class IconButtonWithBadge extends StatelessWidget {
|
||||
final bool active;
|
||||
|
||||
const IconButtonWithBadge({
|
||||
Key key,
|
||||
@required this.icon,
|
||||
@required this.onPressed,
|
||||
Key? key,
|
||||
required this.icon,
|
||||
required this.onPressed,
|
||||
this.number = 0,
|
||||
this.active = false,
|
||||
}) : assert(icon != null),
|
||||
|
@ -69,7 +69,7 @@ class _InitializeWidgetState extends SafeState<InitializeWidget> {
|
||||
await ServerConfigurationHelper.ensureLoaded();
|
||||
|
||||
if (!isWeb &&
|
||||
ServerConfigurationHelper.config.minSupportedMobileVersion >
|
||||
ServerConfigurationHelper.config!.minSupportedMobileVersion >
|
||||
VersionHelper.version) await showDeprecationDialog(context);
|
||||
|
||||
if (!AccountHelper.isUserIDLoaded) {
|
||||
@ -91,7 +91,7 @@ class _InitializeWidgetState extends SafeState<InitializeWidget> {
|
||||
print("Attempting WebSocket connection...");
|
||||
|
||||
if (config().additionalLoading != null)
|
||||
await config().additionalLoading();
|
||||
await config().additionalLoading!();
|
||||
|
||||
await WebSocketHelper.connect();
|
||||
|
||||
@ -113,7 +113,7 @@ class _InitializeWidgetState extends SafeState<InitializeWidget> {
|
||||
if (_error || !WebSocketHelper.isConnected()) return _buildNonReadyWidget();
|
||||
|
||||
if (config().mainRouteBuilder != null)
|
||||
return config().mainRouteBuilder(context, mainControllerKey);
|
||||
return config().mainRouteBuilder!(context, mainControllerKey);
|
||||
|
||||
return isTablet(context)
|
||||
? TabletRoute(key: mainControllerKey)
|
||||
@ -149,9 +149,9 @@ class _InitializeWidgetState extends SafeState<InitializeWidget> {
|
||||
),
|
||||
!isWeb
|
||||
? Text(tr("Version %version% - Build %build%", args: {
|
||||
"version": VersionHelper.info.version.toString(),
|
||||
"build": VersionHelper.info.buildNumber.toString()
|
||||
}))
|
||||
"version": VersionHelper.info!.version.toString(),
|
||||
"build": VersionHelper.info!.buildNumber.toString()
|
||||
})!)
|
||||
: Container(),
|
||||
Spacer(flex: 1),
|
||||
],
|
||||
@ -171,13 +171,13 @@ class _InitializeWidgetState extends SafeState<InitializeWidget> {
|
||||
children: <Widget>[
|
||||
Icon(Icons.error, color: Colors.white),
|
||||
SizedBox(height: 30),
|
||||
Text(tr("Could not connect to server!")),
|
||||
Text(tr("Could not connect to server!")!),
|
||||
SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => _tryConnect(),
|
||||
child: Text(tr("Try again")),
|
||||
child: Text(tr("Try again")!),
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -186,6 +186,6 @@ class _InitializeWidgetState extends SafeState<InitializeWidget> {
|
||||
void _popToMainRoute() {
|
||||
// Pop until we reach main route
|
||||
Navigator.of(context).popUntil((settings) =>
|
||||
ModalRoute.of(context).isCurrent || !ModalRoute.of(context).isActive);
|
||||
ModalRoute.of(context)!.isCurrent || !ModalRoute.of(context)!.isActive);
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,13 @@ typedef UpdatedLikingCallBack = Function(int, bool);
|
||||
|
||||
class LikeWidget extends StatefulWidget {
|
||||
final LikeElement likeElement;
|
||||
final double buttonIconSize;
|
||||
final Color activeColor;
|
||||
final Color inativeColor;
|
||||
final double? buttonIconSize;
|
||||
final Color? activeColor;
|
||||
final Color? inativeColor;
|
||||
|
||||
const LikeWidget(
|
||||
{Key key,
|
||||
@required this.likeElement,
|
||||
{Key? key,
|
||||
required this.likeElement,
|
||||
this.buttonIconSize = 15.0,
|
||||
this.activeColor,
|
||||
this.inativeColor})
|
||||
@ -35,7 +35,7 @@ class LikeWidget extends StatefulWidget {
|
||||
class _LikeWidgetState extends SafeState<LikeWidget> {
|
||||
LikeElement get elem => widget.likeElement;
|
||||
|
||||
String get _likeString {
|
||||
String? get _likeString {
|
||||
switch (elem.likes) {
|
||||
case 0:
|
||||
return tr("Like");
|
||||
@ -66,7 +66,7 @@ class _LikeWidgetState extends SafeState<LikeWidget> {
|
||||
SizedBox(
|
||||
width: 8.0,
|
||||
),
|
||||
Text(_likeString),
|
||||
Text(_likeString!),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -12,14 +12,14 @@ import 'package:flutter/material.dart';
|
||||
class LoginRouteContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const LoginRouteContainer({Key key, @required this.child}) : super(key: key);
|
||||
const LoginRouteContainer({Key? key, required this.child}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!isTablet(context)) return LoginRoutesTheme(child: child);
|
||||
|
||||
return Container(
|
||||
color: Config.get().splashBackgroundColor,
|
||||
color: Config.get()!.splashBackgroundColor,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
|
@ -8,12 +8,12 @@ import 'package:flutter/material.dart';
|
||||
class LoginRoutesTheme extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const LoginRoutesTheme({Key key, @required this.child}) : super(key: key);
|
||||
const LoginRoutesTheme({Key? key, required this.child}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
scaffoldBackgroundColor: Config.get().splashBackgroundColor,
|
||||
scaffoldBackgroundColor: Config.get()!.splashBackgroundColor,
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
@ -30,9 +30,9 @@ class LoginRoutesTheme extends StatelessWidget {
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
fillColor: MaterialStateProperty.all(Colors.white),
|
||||
checkColor:
|
||||
MaterialStateProperty.all(Config.get().splashBackgroundColor),
|
||||
MaterialStateProperty.all(Config.get()!.splashBackgroundColor),
|
||||
),
|
||||
dialogBackgroundColor: Config.get().splashBackgroundColor,
|
||||
dialogBackgroundColor: Config.get()!.splashBackgroundColor,
|
||||
dialogTheme: DialogTheme(
|
||||
contentTextStyle: TextStyle(
|
||||
color: Colors.white,
|
||||
@ -40,7 +40,7 @@ class LoginRoutesTheme extends StatelessWidget {
|
||||
),
|
||||
buttonTheme: ButtonThemeData(buttonColor: Colors.white),
|
||||
primaryColor: Colors.white,
|
||||
backgroundColor: Config.get().splashBackgroundColor,
|
||||
backgroundColor: Config.get()!.splashBackgroundColor,
|
||||
disabledColor: Colors.grey,
|
||||
highlightColor: Colors.white12,
|
||||
hintColor: Colors.white,
|
||||
@ -51,11 +51,11 @@ class LoginRoutesTheme extends StatelessWidget {
|
||||
colorScheme: ColorScheme(
|
||||
primary: Colors.white,
|
||||
secondary: Colors.white,
|
||||
surface: Config.get().splashBackgroundColor,
|
||||
background: Config.get().splashBackgroundColor,
|
||||
surface: Config.get()!.splashBackgroundColor,
|
||||
background: Config.get()!.splashBackgroundColor,
|
||||
error: Colors.redAccent,
|
||||
onPrimary: Config.get().splashBackgroundColor,
|
||||
onSecondary: Config.get().splashBackgroundColor,
|
||||
onPrimary: Config.get()!.splashBackgroundColor,
|
||||
onSecondary: Config.get()!.splashBackgroundColor,
|
||||
onSurface: Colors.white,
|
||||
onBackground: Colors.white,
|
||||
onError: Colors.redAccent,
|
||||
|
@ -8,10 +8,10 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class LoginScaffold extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Widget noStyleChild;
|
||||
final Widget? child;
|
||||
final Widget? noStyleChild;
|
||||
|
||||
const LoginScaffold({Key key, @required this.child, this.noStyleChild})
|
||||
const LoginScaffold({Key? key, required this.child, this.noStyleChild})
|
||||
: assert(child != null || noStyleChild != null),
|
||||
super(key: key);
|
||||
|
||||
@ -37,7 +37,7 @@ class LoginScaffold extends StatelessWidget {
|
||||
fillColor: Colors.white,
|
||||
hoverColor: Colors.white,
|
||||
),
|
||||
scaffoldBackgroundColor: Config.get().splashBackgroundColor,
|
||||
scaffoldBackgroundColor: Config.get()!.splashBackgroundColor,
|
||||
textTheme: TextTheme(
|
||||
bodyText2: TextStyle(color: Colors.white),
|
||||
button: TextStyle(color: Colors.white),
|
||||
@ -64,7 +64,7 @@ class LoginScaffold extends StatelessWidget {
|
||||
Spacer(flex: 1),
|
||||
Text(
|
||||
tr(config().appQuickDescription ??
|
||||
tr("Free social network that respect your privacy")),
|
||||
tr("Free social network that respect your privacy"))!,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Spacer(flex: 3),
|
||||
|
@ -14,7 +14,7 @@ import 'package:flutter/material.dart';
|
||||
class LoginWidget extends StatefulWidget {
|
||||
final void Function() onSignedIn;
|
||||
|
||||
const LoginWidget({Key key, @required this.onSignedIn}) : super(key: key);
|
||||
const LoginWidget({Key? key, required this.onSignedIn}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LoginWidgetState createState() => _LoginWidgetState();
|
||||
@ -24,7 +24,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
final _emailEditingController = TextEditingController();
|
||||
final _passwordEditingController = TextEditingController();
|
||||
bool _loading = false;
|
||||
AuthResult _authResult;
|
||||
AuthResult? _authResult;
|
||||
|
||||
String get _currEmail => _emailEditingController.text;
|
||||
|
||||
@ -33,7 +33,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
bool get _canSubmit => validateEmail(_currEmail) && _currPassword.length >= 3;
|
||||
|
||||
/// Build error card
|
||||
Widget _buildErrorCard() {
|
||||
Widget? _buildErrorCard() {
|
||||
if (_authResult == null) return null;
|
||||
|
||||
//Determine the right message
|
||||
@ -83,7 +83,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
child: _loading
|
||||
? CircularProgressIndicator()
|
||||
: ElevatedButton(
|
||||
child: Text(tr("Sign in")),
|
||||
child: Text(tr("Sign in")!),
|
||||
onPressed: _canSubmit ? () => _submitForm(context) : null,
|
||||
),
|
||||
),
|
||||
|
@ -12,7 +12,7 @@ import 'package:flutter/material.dart';
|
||||
///
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
typedef OnSelectMenuAction = void Function(BarCallbackActions);
|
||||
typedef OnSelectMenuAction = void Function(BarCallbackActions?);
|
||||
|
||||
/// Callback actions
|
||||
enum BarCallbackActions {
|
||||
@ -35,15 +35,15 @@ Color _secondaryColor() => darkTheme() ? darkAccentColor : Colors.white;
|
||||
class _MenuItem {
|
||||
final String label;
|
||||
final Widget icon;
|
||||
final BarCallbackActions action;
|
||||
final BarCallbackActions? action;
|
||||
final bool isMenu;
|
||||
final PageType pageType;
|
||||
final PageType? pageType;
|
||||
|
||||
const _MenuItem({
|
||||
@required this.label,
|
||||
@required this.icon,
|
||||
@required this.action,
|
||||
@required this.pageType,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
required this.action,
|
||||
required this.pageType,
|
||||
this.isMenu = false,
|
||||
}) : assert(label != null),
|
||||
assert(isMenu != null),
|
||||
@ -57,7 +57,7 @@ class _ActionMenuItem {
|
||||
final String label;
|
||||
final BarCallbackActions action;
|
||||
|
||||
const _ActionMenuItem({@required this.label, @required this.action})
|
||||
const _ActionMenuItem({required this.label, required this.action})
|
||||
: assert(label != null),
|
||||
assert(action != null);
|
||||
}
|
||||
@ -65,27 +65,27 @@ class _ActionMenuItem {
|
||||
/// List of menu items to show
|
||||
final _menuItems = <_MenuItem>[
|
||||
_MenuItem(
|
||||
label: tr("Notifications"),
|
||||
label: tr("Notifications")!,
|
||||
icon: Icon(Icons.notifications),
|
||||
action: BarCallbackActions.OPEN_NOTIFICATIONS,
|
||||
pageType: PageType.NOTIFICATIONS_PAGE),
|
||||
_MenuItem(
|
||||
label: tr("Conversations"),
|
||||
label: tr("Conversations")!,
|
||||
icon: Icon(Icons.comment),
|
||||
action: BarCallbackActions.OPEN_CONVERSATIONS,
|
||||
pageType: PageType.CONVERSATIONS_LIST_PAGE),
|
||||
_MenuItem(
|
||||
label: tr("Newest"),
|
||||
label: tr("Newest")!,
|
||||
icon: Icon(Icons.refresh),
|
||||
action: BarCallbackActions.OPEN_NEWEST_POSTS,
|
||||
pageType: PageType.LATEST_POSTS_PAGE),
|
||||
_MenuItem(
|
||||
label: tr("Friends"),
|
||||
label: tr("Friends")!,
|
||||
icon: Icon(Icons.group),
|
||||
action: BarCallbackActions.OPEN_FRIENDS,
|
||||
pageType: PageType.FRIENDS_LIST_PAGE),
|
||||
_MenuItem(
|
||||
label: tr("Menu"),
|
||||
label: tr("Menu")!,
|
||||
icon: Icon(Icons.more_vert),
|
||||
isMenu: true,
|
||||
action: null,
|
||||
@ -95,14 +95,14 @@ final _menuItems = <_MenuItem>[
|
||||
/// List of menu actions items
|
||||
final _menuActionsItem = <_ActionMenuItem>[
|
||||
_ActionMenuItem(
|
||||
label: tr("My Page"), action: BarCallbackActions.OPEN_MY_PAGE),
|
||||
_ActionMenuItem(label: tr("Groups"), action: BarCallbackActions.OPEN_GROUPS),
|
||||
label: tr("My Page")!, action: BarCallbackActions.OPEN_MY_PAGE),
|
||||
_ActionMenuItem(label: tr("Groups")!, action: BarCallbackActions.OPEN_GROUPS),
|
||||
_ActionMenuItem(
|
||||
label: tr("Search"), action: BarCallbackActions.OPEN_SEARCH_PAGE),
|
||||
label: tr("Search")!, action: BarCallbackActions.OPEN_SEARCH_PAGE),
|
||||
_ActionMenuItem(
|
||||
label: tr("Settings"), action: BarCallbackActions.OPEN_SETTINGS),
|
||||
label: tr("Settings")!, action: BarCallbackActions.OPEN_SETTINGS),
|
||||
_ActionMenuItem(
|
||||
label: tr("Sign out"), action: BarCallbackActions.ACTION_LOGOUT),
|
||||
label: tr("Sign out")!, action: BarCallbackActions.ACTION_LOGOUT),
|
||||
];
|
||||
|
||||
/// Public widget
|
||||
@ -111,8 +111,8 @@ class ComunicMobileAppBar extends StatefulWidget
|
||||
final PageInfo currentPage;
|
||||
|
||||
const ComunicMobileAppBar({
|
||||
Key key,
|
||||
@required this.currentPage,
|
||||
Key? key,
|
||||
required this.currentPage,
|
||||
}) : assert(currentPage != null),
|
||||
super(key: key);
|
||||
|
||||
@ -153,7 +153,7 @@ class _ComunicMobileAppBarState extends SafeState<ComunicMobileAppBar> {
|
||||
}
|
||||
|
||||
/// Get the number of unread notifications for the selected notice
|
||||
int getNumberUnread(BarCallbackActions action) {
|
||||
int? getNumberUnread(BarCallbackActions? action) {
|
||||
if (_unreadNotifications == null) return 0;
|
||||
|
||||
switch (action) {
|
||||
@ -187,35 +187,35 @@ class _ComunicMobileAppBarState extends SafeState<ComunicMobileAppBar> {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleAction(BarCallbackActions action) {
|
||||
void _handleAction(BarCallbackActions? action) {
|
||||
final controller = MainController.of(context);
|
||||
switch (action) {
|
||||
case BarCallbackActions.OPEN_NOTIFICATIONS:
|
||||
controller.openNotificationsPage();
|
||||
controller!.openNotificationsPage();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_CONVERSATIONS:
|
||||
controller.openConversationsPage();
|
||||
controller!.openConversationsPage();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_NEWEST_POSTS:
|
||||
controller.openLatestPostsPage();
|
||||
controller!.openLatestPostsPage();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_FRIENDS:
|
||||
controller.openFriendsList();
|
||||
controller!.openFriendsList();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_MY_PAGE:
|
||||
controller.openCurrentUserPage();
|
||||
controller!.openCurrentUserPage();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_SEARCH_PAGE:
|
||||
controller.openSearchPage();
|
||||
controller!.openSearchPage();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_GROUPS:
|
||||
controller.openGroupsListPage();
|
||||
controller!.openGroupsListPage();
|
||||
break;
|
||||
case BarCallbackActions.OPEN_SETTINGS:
|
||||
controller.openSettings();
|
||||
controller!.openSettings();
|
||||
break;
|
||||
case BarCallbackActions.ACTION_LOGOUT:
|
||||
controller.requestLogout();
|
||||
controller!.requestLogout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -228,18 +228,15 @@ class _MenuItemWidget extends StatelessWidget {
|
||||
final bool isSelected;
|
||||
|
||||
/// Notifications notice
|
||||
final int newNotice;
|
||||
final int? newNotice;
|
||||
|
||||
const _MenuItemWidget({
|
||||
Key key,
|
||||
@required this.item,
|
||||
@required this.onTap,
|
||||
@required this.isSelected,
|
||||
Key? key,
|
||||
required this.item,
|
||||
required this.onTap,
|
||||
required this.isSelected,
|
||||
this.newNotice = 0,
|
||||
}) : assert(item != null),
|
||||
assert(onTap != null),
|
||||
assert(isSelected != null),
|
||||
super(key: key);
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -269,7 +266,7 @@ class _MenuItemWidget extends StatelessWidget {
|
||||
color: isSelected ? _primaryColor() : _secondaryColor()),
|
||||
child: item.icon,
|
||||
),
|
||||
newNotice > 0 ? Spacer() : Container(),
|
||||
newNotice! > 0 ? Spacer() : Container(),
|
||||
newNotice == 0
|
||||
? Container()
|
||||
: Material(
|
||||
|
@ -16,9 +16,9 @@ class UserMobilePage extends StatefulWidget {
|
||||
final void Function() onNeedRefresh;
|
||||
|
||||
const UserMobilePage({
|
||||
Key key,
|
||||
@required this.userInfo,
|
||||
@required this.onNeedRefresh,
|
||||
Key? key,
|
||||
required this.userInfo,
|
||||
required this.onNeedRefresh,
|
||||
}) : assert(userInfo != null),
|
||||
assert(onNeedRefresh != null),
|
||||
super(key: key);
|
||||
@ -29,12 +29,12 @@ class UserMobilePage extends StatefulWidget {
|
||||
|
||||
class _UserMobilePageState extends State<UserMobilePage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
TabController _tabController;
|
||||
TabController? _tabController;
|
||||
|
||||
List<UserPageTab> get _tabs => [
|
||||
// User posts
|
||||
UserPageTab(
|
||||
label: tr("Posts"),
|
||||
label: tr("Posts")!,
|
||||
onBuild: (c) => UserPostsSection(
|
||||
user: widget.userInfo,
|
||||
),
|
||||
@ -42,13 +42,13 @@ class _UserMobilePageState extends State<UserMobilePage>
|
||||
|
||||
// About user
|
||||
UserPageTab(
|
||||
label: tr("About"),
|
||||
label: tr("About")!,
|
||||
onBuild: (c) => AboutUserSection(user: widget.userInfo),
|
||||
),
|
||||
|
||||
// User friends
|
||||
UserPageTab(
|
||||
label: tr("Friends"),
|
||||
label: tr("Friends")!,
|
||||
onBuild: (c) => widget.userInfo.isCurrentUser
|
||||
? FriendsListScreen(
|
||||
showAppBar: false,
|
||||
@ -70,7 +70,7 @@ class _UserMobilePageState extends State<UserMobilePage>
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
_tabController!.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -111,8 +111,8 @@ class UserPageTab {
|
||||
final bool visible;
|
||||
|
||||
UserPageTab({
|
||||
@required this.label,
|
||||
@required this.onBuild,
|
||||
required this.label,
|
||||
required this.onBuild,
|
||||
this.visible = true,
|
||||
}) : assert(label != null),
|
||||
assert(onBuild != null),
|
||||
|
@ -10,16 +10,16 @@ import 'package:flutter/material.dart';
|
||||
|
||||
class NetworkImageWidget extends StatelessWidget {
|
||||
final String url;
|
||||
final String thumbnailURL;
|
||||
final String? thumbnailURL;
|
||||
final bool allowFullScreen;
|
||||
final bool roundedEdges;
|
||||
final double width;
|
||||
final double height;
|
||||
final double loadingHeight;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final double? loadingHeight;
|
||||
|
||||
const NetworkImageWidget({
|
||||
Key key,
|
||||
@required this.url,
|
||||
Key? key,
|
||||
required this.url,
|
||||
this.thumbnailURL,
|
||||
this.allowFullScreen = false,
|
||||
this.width,
|
||||
@ -30,9 +30,9 @@ class NetworkImageWidget extends StatelessWidget {
|
||||
assert(allowFullScreen != null),
|
||||
super(key: key);
|
||||
|
||||
double get _loadingHeight => loadingHeight != null ? loadingHeight : height;
|
||||
double? get _loadingHeight => loadingHeight != null ? loadingHeight : height;
|
||||
|
||||
double get _loadingWidth => width;
|
||||
double? get _loadingWidth => width;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -8,34 +8,34 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class UserInfoForPassword {
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final String email;
|
||||
final String? firstName;
|
||||
final String? lastName;
|
||||
final String? email;
|
||||
|
||||
const UserInfoForPassword({
|
||||
@required this.firstName,
|
||||
@required this.lastName,
|
||||
@required this.email,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.email,
|
||||
});
|
||||
}
|
||||
|
||||
class NewPasswordInputWidget extends StatefulWidget {
|
||||
final Widget icon;
|
||||
final VoidCallback onEdited;
|
||||
final VoidCallback onSubmitted;
|
||||
final TextInputAction textInputAction;
|
||||
final Widget? icon;
|
||||
final VoidCallback? onEdited;
|
||||
final VoidCallback? onSubmitted;
|
||||
final TextInputAction? textInputAction;
|
||||
final String label;
|
||||
|
||||
final UserInfoForPassword user;
|
||||
|
||||
const NewPasswordInputWidget({
|
||||
Key key,
|
||||
Key? key,
|
||||
this.icon,
|
||||
this.onEdited,
|
||||
this.onSubmitted,
|
||||
this.textInputAction,
|
||||
@required this.label,
|
||||
@required this.user,
|
||||
required this.label,
|
||||
required this.user,
|
||||
}) : assert(label != null),
|
||||
assert(user != null),
|
||||
super(key: key);
|
||||
@ -51,7 +51,7 @@ class NewPasswordInputWidgetState extends State<NewPasswordInputWidget> {
|
||||
|
||||
bool get valid => value.isNotEmpty && (_errorMessage ?? "").isEmpty;
|
||||
|
||||
PasswordPolicy get _policy => ServerConfigurationHelper.config.passwordPolicy;
|
||||
PasswordPolicy get _policy => ServerConfigurationHelper.config!.passwordPolicy;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant NewPasswordInputWidget oldWidget) {
|
||||
@ -65,7 +65,7 @@ class NewPasswordInputWidgetState extends State<NewPasswordInputWidget> {
|
||||
obscureText: true,
|
||||
onChanged: (s) => _onChanged(),
|
||||
onSubmitted:
|
||||
widget.onSubmitted == null ? null : (s) => widget.onSubmitted(),
|
||||
widget.onSubmitted == null ? null : (s) => widget.onSubmitted!(),
|
||||
textInputAction: widget.textInputAction,
|
||||
decoration: InputDecoration(
|
||||
errorText: _errorMessage,
|
||||
@ -77,30 +77,30 @@ class NewPasswordInputWidgetState extends State<NewPasswordInputWidget> {
|
||||
|
||||
void _onChanged() {
|
||||
setState(() {});
|
||||
if (widget.onEdited != null) widget.onEdited();
|
||||
if (widget.onEdited != null) widget.onEdited!();
|
||||
}
|
||||
|
||||
/// Generate an error message associated with current password
|
||||
String get _errorMessage {
|
||||
String? get _errorMessage {
|
||||
if (value.isEmpty) return null;
|
||||
|
||||
// Mandatory checks
|
||||
if (!_policy.allowMailInPassword &&
|
||||
(widget.user.email ?? "").isNotEmpty &&
|
||||
(widget.user.email.toLowerCase().contains(value.toLowerCase()) ||
|
||||
value.toLowerCase().contains(widget.user.email.toLowerCase()))) {
|
||||
(widget.user.email!.toLowerCase().contains(value.toLowerCase()) ||
|
||||
value.toLowerCase().contains(widget.user.email!.toLowerCase()))) {
|
||||
return tr("Your password must not contains part of your email address!");
|
||||
}
|
||||
|
||||
if (!_policy.allowNameInPassword &&
|
||||
(widget.user.firstName ?? "").isNotEmpty &&
|
||||
value.toLowerCase().contains(widget.user.firstName.toLowerCase())) {
|
||||
value.toLowerCase().contains(widget.user.firstName!.toLowerCase())) {
|
||||
return tr("Your password must not contains your first name!");
|
||||
}
|
||||
|
||||
if (!_policy.allowNameInPassword &&
|
||||
(widget.user.lastName ?? "").isNotEmpty &&
|
||||
value.toLowerCase().contains(widget.user.lastName.toLowerCase())) {
|
||||
value.toLowerCase().contains(widget.user.lastName!.toLowerCase())) {
|
||||
return tr("Your password must not contains your last name!");
|
||||
}
|
||||
|
||||
|
@ -15,16 +15,16 @@ typedef OnSelectUserCallback = void Function(User);
|
||||
|
||||
class PickUserWidget extends StatefulWidget {
|
||||
final OnSelectUserCallback onSelectUser;
|
||||
final void Function(String) onValueChange;
|
||||
final void Function(String)? onValueChange;
|
||||
final String label;
|
||||
final bool resetOnChoose;
|
||||
final bool keepFocusOnChoose;
|
||||
final bool enabled;
|
||||
|
||||
const PickUserWidget({
|
||||
Key key,
|
||||
@required this.onSelectUser,
|
||||
@required this.label,
|
||||
Key? key,
|
||||
required this.onSelectUser,
|
||||
required this.label,
|
||||
this.resetOnChoose = false,
|
||||
this.keepFocusOnChoose = false,
|
||||
this.onValueChange,
|
||||
@ -46,8 +46,8 @@ class _PickUserWidgetState extends State<PickUserWidget> {
|
||||
// Widget properties
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
OverlayEntry _overlayEntry;
|
||||
UsersList _suggestions;
|
||||
OverlayEntry? _overlayEntry;
|
||||
UsersList? _suggestions;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -79,7 +79,7 @@ class _PickUserWidgetState extends State<PickUserWidget> {
|
||||
}
|
||||
|
||||
OverlayEntry _createOverlayEntry() {
|
||||
RenderBox renderBox = context.findRenderObject();
|
||||
RenderBox renderBox = context.findRenderObject() as RenderBox;
|
||||
final size = renderBox.size;
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
@ -93,9 +93,9 @@ class _PickUserWidgetState extends State<PickUserWidget> {
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: _suggestions == null ? 0 : _suggestions.length,
|
||||
itemCount: _suggestions == null ? 0 : _suggestions!.length,
|
||||
itemBuilder: (c, i) => SimpleUserTile(
|
||||
user: _suggestions[i],
|
||||
user: _suggestions![i],
|
||||
onTap: _userTapped,
|
||||
),
|
||||
),
|
||||
@ -106,19 +106,19 @@ class _PickUserWidgetState extends State<PickUserWidget> {
|
||||
|
||||
void _showOverlay() {
|
||||
_overlayEntry = _createOverlayEntry();
|
||||
Overlay.of(context).insert(_overlayEntry);
|
||||
Overlay.of(context)!.insert(_overlayEntry!);
|
||||
}
|
||||
|
||||
void _removeOverlay() {
|
||||
if (_overlayEntry != null) {
|
||||
_overlayEntry.remove();
|
||||
_overlayEntry!.remove();
|
||||
_overlayEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// This method get called each time the input value is updated
|
||||
Future<void> _updateSuggestions() async {
|
||||
if (widget.onValueChange != null) widget.onValueChange(_controller.text);
|
||||
if (widget.onValueChange != null) widget.onValueChange!(_controller.text);
|
||||
|
||||
if (_controller.text.length == 0) return _removeOverlay();
|
||||
|
||||
@ -128,7 +128,7 @@ class _PickUserWidgetState extends State<PickUserWidget> {
|
||||
|
||||
_suggestions = results;
|
||||
if (_overlayEntry != null)
|
||||
_overlayEntry.markNeedsBuild();
|
||||
_overlayEntry!.markNeedsBuild();
|
||||
else
|
||||
_showOverlay();
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
||||
class PostContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const PostContainer({Key key, @required this.child})
|
||||
const PostContainer({Key? key, required this.child})
|
||||
: assert(child != null),
|
||||
super(key: key);
|
||||
|
||||
|
@ -31,10 +31,10 @@ class PostCreateFormWidget extends StatefulWidget {
|
||||
final void Function() onCreated;
|
||||
|
||||
const PostCreateFormWidget({
|
||||
Key key,
|
||||
@required this.postTarget,
|
||||
@required this.targetID,
|
||||
@required this.onCreated,
|
||||
Key? key,
|
||||
required this.postTarget,
|
||||
required this.targetID,
|
||||
required this.onCreated,
|
||||
}) : assert(postTarget != null),
|
||||
assert(targetID != null),
|
||||
super(key: key);
|
||||
@ -50,13 +50,13 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
// Class members
|
||||
bool _isCreating = false;
|
||||
final TextEditingController _postTextController = TextEditingController();
|
||||
PostVisibilityLevel _postVisibilityLevel;
|
||||
BytesFile _postImage;
|
||||
String _postURL;
|
||||
List<int> _postPDF;
|
||||
DateTime _timeEnd;
|
||||
NewSurvey _postSurvey;
|
||||
String _youtubeID;
|
||||
PostVisibilityLevel? _postVisibilityLevel;
|
||||
BytesFile? _postImage;
|
||||
String? _postURL;
|
||||
List<int>? _postPDF;
|
||||
DateTime? _timeEnd;
|
||||
NewSurvey? _postSurvey;
|
||||
String? _youtubeID;
|
||||
|
||||
bool get hasImage => _postImage != null;
|
||||
|
||||
@ -184,7 +184,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
|
||||
// Post visibility level
|
||||
_PostOptionWidget(
|
||||
icon: PostVisibilityLevelsMapIcons[_postVisibilityLevel],
|
||||
icon: PostVisibilityLevelsMapIcons[_postVisibilityLevel!]!,
|
||||
selected: false,
|
||||
customColor: Colors.black,
|
||||
onTap: _changeVisibilityLevel,
|
||||
@ -194,7 +194,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
_isCreating
|
||||
? Container()
|
||||
: ElevatedButton(
|
||||
child: Text(tr("Send").toUpperCase()),
|
||||
child: Text(tr("Send")!.toUpperCase()),
|
||||
onPressed: canSubmitForm ? _submitForm : null),
|
||||
],
|
||||
),
|
||||
@ -221,7 +221,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
Future<void> _changeVisibilityLevel() async {
|
||||
final newLevel = await showPostVisibilityPickerDialog(
|
||||
context: context,
|
||||
initialLevel: _postVisibilityLevel,
|
||||
initialLevel: _postVisibilityLevel!,
|
||||
isGroup: widget.postTarget == PostTarget.GROUP_PAGE,
|
||||
);
|
||||
|
||||
@ -254,7 +254,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
});
|
||||
} catch (e, s) {
|
||||
logError(e, s);
|
||||
snack(context, tr("Failed to pick an image for the post!"));
|
||||
snack(context, tr("Failed to pick an image for the post!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
});
|
||||
} catch (e, stack) {
|
||||
print("Pick PDF error: $e\n$stack");
|
||||
showSimpleSnack(context, tr("Could not pick a PDF!"));
|
||||
showSimpleSnack(context, tr("Could not pick a PDF!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
Future<void> _pickCountdownTime() async {
|
||||
final yesterday = DateTime.now().subtract(Duration(days: 1));
|
||||
|
||||
final initialDate = _timeEnd == null ? DateTime.now() : _timeEnd;
|
||||
final initialDate = _timeEnd == null ? DateTime.now() : _timeEnd!;
|
||||
|
||||
// Pick date
|
||||
final newDate = await showDatePicker(
|
||||
@ -358,7 +358,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
/// Submit new post
|
||||
Future<void> _submitForm() async {
|
||||
if (!canSubmitForm)
|
||||
showSimpleSnack(context, tr("Form can not be submitted at this point!"));
|
||||
showSimpleSnack(context, tr("Form can not be submitted at this point!")!);
|
||||
|
||||
setState(() => _isCreating = true);
|
||||
|
||||
@ -366,7 +366,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
await _postHelper.createPost(NewPost(
|
||||
target: widget.postTarget,
|
||||
targetID: widget.targetID,
|
||||
visibility: _postVisibilityLevel,
|
||||
visibility: _postVisibilityLevel!,
|
||||
content: _postTextController.text,
|
||||
kind: postKind,
|
||||
image: _postImage,
|
||||
@ -378,14 +378,14 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
));
|
||||
setState(() => _isCreating = false);
|
||||
|
||||
showSimpleSnack(context, tr("The post has been successfully created!"));
|
||||
showSimpleSnack(context, tr("The post has been successfully created!")!);
|
||||
|
||||
this._resetForm();
|
||||
widget.onCreated();
|
||||
} catch (e, s) {
|
||||
setState(() => _isCreating = false);
|
||||
print("Error while creating post : $e $s");
|
||||
showSimpleSnack(context, tr("Could not create post !"));
|
||||
showSimpleSnack(context, tr("Could not create post !")!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,14 +394,14 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
|
||||
class _PostOptionWidget extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final bool selected;
|
||||
final Color customColor;
|
||||
final Color? customColor;
|
||||
final void Function() onTap;
|
||||
|
||||
const _PostOptionWidget(
|
||||
{Key key,
|
||||
@required this.icon,
|
||||
@required this.selected,
|
||||
@required this.onTap,
|
||||
{Key? key,
|
||||
required this.icon,
|
||||
required this.selected,
|
||||
required this.onTap,
|
||||
this.customColor})
|
||||
: assert(icon != null),
|
||||
assert(selected != null),
|
||||
|
@ -24,18 +24,18 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
class PostsListWidget extends StatefulWidget {
|
||||
final List<Widget> topWidgets;
|
||||
final Future<PostsList> Function() getPostsList;
|
||||
final Future<PostsList> Function(int from) getOlder;
|
||||
final List<Widget>? topWidgets;
|
||||
final Future<PostsList?> Function() getPostsList;
|
||||
final Future<PostsList?> Function(int from)? getOlder;
|
||||
final bool showPostsTarget;
|
||||
final bool buildListView;
|
||||
final bool userNamesClickable;
|
||||
final bool disablePullToRefresh;
|
||||
|
||||
const PostsListWidget({
|
||||
Key key,
|
||||
@required this.getPostsList,
|
||||
@required this.showPostsTarget,
|
||||
Key? key,
|
||||
required this.getPostsList,
|
||||
required this.showPostsTarget,
|
||||
this.userNamesClickable = true,
|
||||
this.buildListView = true,
|
||||
this.getOlder,
|
||||
@ -58,10 +58,10 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
final GroupsHelper _groupsHelper = GroupsHelper();
|
||||
|
||||
// Class members
|
||||
PostsList _list;
|
||||
UsersList _users;
|
||||
GroupsList _groups;
|
||||
ScrollWatcher _scrollController;
|
||||
PostsList? _list;
|
||||
late UsersList _users;
|
||||
late GroupsList _groups;
|
||||
ScrollWatcher? _scrollController;
|
||||
ErrorLevel _error = ErrorLevel.NONE;
|
||||
bool _loading = false;
|
||||
|
||||
@ -70,7 +70,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
set error(ErrorLevel err) => setState(() => _error = err);
|
||||
|
||||
int get _numberTopWidgets =>
|
||||
widget.topWidgets == null ? 0 : widget.topWidgets.length;
|
||||
widget.topWidgets == null ? 0 : widget.topWidgets!.length;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -122,7 +122,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
try {
|
||||
final list = !getOlder
|
||||
? await widget.getPostsList()
|
||||
: await widget.getOlder(_list.oldestID);
|
||||
: await widget.getOlder!(_list!.oldestID);
|
||||
|
||||
if (list == null) return _loadError();
|
||||
|
||||
@ -140,7 +140,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
_users = users;
|
||||
_groups = groups;
|
||||
} else {
|
||||
_list.addAll(list);
|
||||
_list!.addAll(list);
|
||||
_users.addAll(users);
|
||||
_groups.addAll(groups);
|
||||
}
|
||||
@ -157,7 +157,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
void _registerRequiredPosts() async {
|
||||
if (_list == null) return;
|
||||
|
||||
final missing = _list
|
||||
final missing = _list!
|
||||
.where((f) => !_registeredPosts.contains(f.id))
|
||||
.map((f) => f.id)
|
||||
.toSet();
|
||||
@ -192,7 +192,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(tr("There is no post to display here yet.")),
|
||||
child: Text(tr("There is no post to display here yet.")!),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -205,7 +205,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
Widget _buildListView() {
|
||||
return ListView.builder(
|
||||
// We use max function here to display to post notice in case there are not posts to display but there are custom widgets...
|
||||
itemCount: max(_list.length, 1) + _numberTopWidgets,
|
||||
itemCount: max(_list!.length, 1) + _numberTopWidgets,
|
||||
|
||||
itemBuilder: _buildItem,
|
||||
controller: _scrollController,
|
||||
@ -215,20 +215,20 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
Widget _buildColumn() {
|
||||
return Column(
|
||||
children: List.generate(
|
||||
_list.length,
|
||||
_list!.length,
|
||||
(i) => _buildItem(null, i),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItem(BuildContext context, int index) {
|
||||
if (index < _numberTopWidgets) return widget.topWidgets[index];
|
||||
Widget _buildItem(BuildContext? context, int index) {
|
||||
if (index < _numberTopWidgets) return widget.topWidgets![index];
|
||||
|
||||
// Show no posts notice if required
|
||||
if (_list.length == 0) return _buildNoPostNotice();
|
||||
if (_list!.length == 0) return _buildNoPostNotice();
|
||||
|
||||
return PostTile(
|
||||
post: _list[index - _numberTopWidgets],
|
||||
post: _list![index - _numberTopWidgets],
|
||||
usersInfo: _users,
|
||||
groupsInfo: _groups,
|
||||
onDeletedPost: _removePost,
|
||||
@ -241,7 +241,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
Widget build(BuildContext context) {
|
||||
if (_error == ErrorLevel.MAJOR) return _buildErrorCard();
|
||||
if (_list == null) return buildCenteredProgressBar();
|
||||
if (_list.length == 0 && _numberTopWidgets == 0)
|
||||
if (_list!.length == 0 && _numberTopWidgets == 0)
|
||||
return _buildNoPostNotice();
|
||||
if (!widget.buildListView) return _buildColumn();
|
||||
|
||||
@ -250,7 +250,7 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
return _buildListViewWithRefreshIndicator();
|
||||
}
|
||||
|
||||
void _removePost(Post post) => setState(() => _list.remove(post));
|
||||
void _removePost(Post post) => setState(() => _list!.remove(post));
|
||||
|
||||
void reachedPostsBottom() {
|
||||
if (widget.getOlder != null) loadPostsList(getOlder: true);
|
||||
@ -261,15 +261,14 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
if (_list == null) return;
|
||||
|
||||
try {
|
||||
final p = _list.singleWhere((p) => p.id == c.postID, orElse: () => null);
|
||||
|
||||
if (p == null) return;
|
||||
// This command will throw if post could not be found
|
||||
final Post p = _list!.singleWhere((p) => p.id == c.postID);
|
||||
|
||||
if (!_users.hasUser(c.userID))
|
||||
_users.add(await UsersHelper().getSingleWithThrow(c.userID));
|
||||
|
||||
setState(() {
|
||||
p.comments.add(c);
|
||||
p.comments!.add(c);
|
||||
});
|
||||
} catch (e, stack) {
|
||||
print("$e\n$stack");
|
||||
@ -281,22 +280,20 @@ class PostsListWidgetState extends SafeState<PostsListWidget> {
|
||||
if (_list == null) return;
|
||||
|
||||
try {
|
||||
final p = _list.singleWhere((p) => p.id == c.postID, orElse: () => null);
|
||||
final Post p = _list!.singleWhere((p) => p.id == c.postID);
|
||||
|
||||
if (p == null) return;
|
||||
final index = p.comments!.indexWhere((d) => d.id == c.id);
|
||||
|
||||
final index = p.comments.indexWhere((d) => d.id == c.id);
|
||||
|
||||
if (index > -1) p.comments[index] = c;
|
||||
if (index > -1) p.comments![index] = c;
|
||||
} catch (e, stack) {
|
||||
print("$e\n$stack");
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a comment from the list
|
||||
void _removeComment(int commentID) {
|
||||
void _removeComment(int? commentID) {
|
||||
if (_list == null) return;
|
||||
|
||||
_list.forEach((p) => p.comments.removeWhere((c) => c.id == commentID));
|
||||
_list!.forEach((p) => p.comments!.removeWhere((c) => c.id == commentID));
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ typedef OnReachBottomCallback = void Function();
|
||||
class ScrollWatcher extends ScrollController {
|
||||
|
||||
// Callbacks
|
||||
OnReachBottomCallback onReachBottom;
|
||||
OnReachBottomCallback? onReachBottom;
|
||||
|
||||
ScrollWatcher({this.onReachBottom}) {
|
||||
addListener(_updatePosition);
|
||||
@ -21,7 +21,7 @@ class ScrollWatcher extends ScrollController {
|
||||
|
||||
// Refresh bottom position
|
||||
if(position.pixels.floor() == position.maxScrollExtent.floor())
|
||||
onReachBottom();
|
||||
onReachBottom!();
|
||||
|
||||
}
|
||||
}
|
@ -11,15 +11,15 @@ class MultiChoicesSettingsTile<T> extends SettingsTile {
|
||||
final List<MultiChoiceEntry<T>> choices;
|
||||
final T currentValue;
|
||||
final Function(T) onChanged;
|
||||
final Widget leading;
|
||||
final Widget trailing;
|
||||
final Widget? leading;
|
||||
final Widget? trailing;
|
||||
|
||||
MultiChoicesSettingsTile({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.choices,
|
||||
@required this.currentValue,
|
||||
@required this.onChanged,
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.choices,
|
||||
required this.currentValue,
|
||||
required this.onChanged,
|
||||
this.leading,
|
||||
this.trailing,
|
||||
}) : assert(title != null),
|
||||
|
@ -18,15 +18,15 @@ class TextEditSettingsTile extends SettingsTile {
|
||||
final bool Function(String) checkInput;
|
||||
final bool allowEmptyValues;
|
||||
final int maxLines;
|
||||
final int maxLength;
|
||||
final int? maxLength;
|
||||
|
||||
bool get readOnly => onChanged == null;
|
||||
|
||||
TextEditSettingsTile({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.currValue,
|
||||
@required this.onChanged,
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.currValue,
|
||||
required this.onChanged,
|
||||
this.checkInput = _defaultCheck,
|
||||
this.allowEmptyValues = false,
|
||||
this.maxLength,
|
||||
@ -55,7 +55,7 @@ class TextEditSettingsTile extends SettingsTile {
|
||||
initialValue: currValue,
|
||||
label: title,
|
||||
checkInput: checkInput,
|
||||
errorMessage: tr("Invalid value!"),
|
||||
errorMessage: tr("Invalid value!")!,
|
||||
canBeEmpty: allowEmptyValues,
|
||||
maxLines: maxLines,
|
||||
maxLength: maxLength,
|
||||
|
@ -15,8 +15,8 @@ class StatusWidget extends StatefulWidget {
|
||||
final Widget Function(BuildContext) child;
|
||||
|
||||
const StatusWidget({
|
||||
Key key,
|
||||
@required this.child,
|
||||
Key? key,
|
||||
required this.child,
|
||||
}) : assert(child != null),
|
||||
super(key: key);
|
||||
|
||||
@ -25,8 +25,8 @@ class StatusWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class StatusWidgetState extends SafeState<StatusWidget> {
|
||||
int unreadNotifications = 0;
|
||||
int unreadConversations = 0;
|
||||
int? unreadNotifications = 0;
|
||||
int? unreadConversations = 0;
|
||||
|
||||
Future<void> init() async {
|
||||
try {
|
||||
@ -52,7 +52,7 @@ class StatusWidgetState extends SafeState<StatusWidget> {
|
||||
}
|
||||
|
||||
/// Find an ancestor of this object
|
||||
static StatusWidgetState of(BuildContext c) =>
|
||||
static StatusWidgetState? of(BuildContext c) =>
|
||||
c.findAncestorStateOfType<StatusWidgetState>();
|
||||
|
||||
@override
|
||||
|
@ -16,9 +16,9 @@ class SurveyWidget extends StatefulWidget {
|
||||
final Function(Survey) onUpdated;
|
||||
|
||||
const SurveyWidget({
|
||||
Key key,
|
||||
@required this.survey,
|
||||
@required this.onUpdated,
|
||||
Key? key,
|
||||
required this.survey,
|
||||
required this.onUpdated,
|
||||
}) : assert(survey != null),
|
||||
assert(onUpdated != null),
|
||||
super(key: key);
|
||||
@ -74,12 +74,12 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
Flexible(
|
||||
child: Text(
|
||||
tr("Your response: %response%",
|
||||
args: {"response": survey.userResponse.name}),
|
||||
args: {"response": survey.userResponse!.name})!,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
MaterialButton(
|
||||
child: Text(tr("Cancel").toUpperCase()),
|
||||
child: Text(tr("Cancel")!.toUpperCase()),
|
||||
onPressed: _cancelUserResponse,
|
||||
)
|
||||
],
|
||||
@ -96,7 +96,7 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
|
||||
if (!await _helper.cancelResponse(survey)) {
|
||||
showSimpleSnack(
|
||||
context, tr("Could not cancel your response to the survey !"));
|
||||
context, tr("Could not cancel your response to the survey !")!);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
constraints: BoxConstraints(maxWidth: 300),
|
||||
child: DropdownButton<SurveyChoice>(
|
||||
isExpanded: true,
|
||||
hint: Text(tr("Respond to survey")),
|
||||
hint: Text(tr("Respond to survey")!),
|
||||
items: survey.choices
|
||||
.map(
|
||||
(f) => DropdownMenuItem<SurveyChoice>(
|
||||
@ -128,7 +128,7 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: _createNewChoices,
|
||||
child: Text(tr("Create a new choice")),
|
||||
child: Text(tr("Create a new choice")!),
|
||||
),
|
||||
);
|
||||
|
||||
@ -136,7 +136,7 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: _blockNewChoices,
|
||||
child: Text(tr("Block the creation of new responses")),
|
||||
child: Text(tr("Block the creation of new responses")!),
|
||||
),
|
||||
);
|
||||
|
||||
@ -149,16 +149,16 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
Widget _buildNoResponseNotice() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(tr("No response yet to this survey.")),
|
||||
child: Text(tr("No response yet to this survey.")!),
|
||||
);
|
||||
}
|
||||
|
||||
/// Respond to survey
|
||||
Future<void> _respondToSurvey(SurveyChoice choice) async {
|
||||
Future<void> _respondToSurvey(SurveyChoice? choice) async {
|
||||
// Send the response to the server
|
||||
if (!await _helper.respondToSurvey(survey: survey, choice: choice))
|
||||
if (!await _helper.respondToSurvey(survey: survey, choice: choice!))
|
||||
return showSimpleSnack(
|
||||
context, tr("Could not send your response to the survey!"));
|
||||
context, tr("Could not send your response to the survey!")!);
|
||||
|
||||
setState(() {
|
||||
survey.setUserResponse(choice);
|
||||
@ -178,10 +178,10 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
try {
|
||||
final newChoice = await askUserString(
|
||||
context: context,
|
||||
title: tr("New choice"),
|
||||
message: tr("Please specify the new choice for the survey"),
|
||||
title: tr("New choice")!,
|
||||
message: tr("Please specify the new choice for the survey")!,
|
||||
defaultValue: "",
|
||||
hint: tr("New choice..."),
|
||||
hint: tr("New choice...")!,
|
||||
maxLength: 50,
|
||||
);
|
||||
|
||||
@ -193,7 +193,7 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
} catch (e, s) {
|
||||
print("Could not create new survey choice! $e\n$s");
|
||||
showSimpleSnack(
|
||||
context, tr("Could not create a new choice for this survey!"));
|
||||
context, tr("Could not create a new choice for this survey!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ class _SurveyWidgetState extends SafeState<SurveyWidget> {
|
||||
} catch (e, s) {
|
||||
print("Could not block the creation of new choices! $e\n$s");
|
||||
showSimpleSnack(
|
||||
context, tr("Could not block the creation of new choices!"));
|
||||
context, tr("Could not block the creation of new choices!")!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
||||
class TabTransitionWidget extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const TabTransitionWidget(this.child, {Key key})
|
||||
const TabTransitionWidget(this.child, {Key? key})
|
||||
: assert(child != null),
|
||||
super(key: key);
|
||||
|
||||
|
@ -14,10 +14,10 @@ class AppBarCustomDropDownWidget extends StatefulWidget {
|
||||
final Widget Function(BuildContext) onBuildOverlay;
|
||||
|
||||
const AppBarCustomDropDownWidget({
|
||||
Key key,
|
||||
@required this.icon,
|
||||
@required this.notificationsBadge,
|
||||
@required this.onBuildOverlay,
|
||||
Key? key,
|
||||
required this.icon,
|
||||
required this.notificationsBadge,
|
||||
required this.onBuildOverlay,
|
||||
}) : assert(icon != null),
|
||||
assert(notificationsBadge != null),
|
||||
assert(onBuildOverlay != null),
|
||||
@ -46,7 +46,7 @@ class AppBarCustomDropDownWidgetState
|
||||
setState(() => _visible = !_visible);
|
||||
|
||||
if (_visible) {
|
||||
RenderBox renderBox = context.findRenderObject();
|
||||
RenderBox renderBox = context.findRenderObject() as RenderBox;
|
||||
final size = renderBox.size;
|
||||
final offset = renderBox.localToGlobal(Offset(size.width, size.height));
|
||||
|
||||
@ -68,10 +68,10 @@ class _AppBarCustomPopupRoute extends PopupRoute {
|
||||
final void Function() onDispose;
|
||||
|
||||
_AppBarCustomPopupRoute({
|
||||
@required this.showContext,
|
||||
@required this.onBuild,
|
||||
@required this.offset,
|
||||
@required this.onDispose,
|
||||
required this.showContext,
|
||||
required this.onBuild,
|
||||
required this.offset,
|
||||
required this.onDispose,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -82,7 +82,7 @@ class _AppBarCustomPopupRoute extends PopupRoute {
|
||||
}
|
||||
|
||||
@override
|
||||
Color get barrierColor => null;
|
||||
Color? get barrierColor => null;
|
||||
|
||||
@override
|
||||
bool get barrierDismissible => true;
|
||||
@ -116,10 +116,10 @@ class _AppBarCustomPopupRoute extends PopupRoute {
|
||||
}
|
||||
|
||||
class _PopupContentBody extends StatelessWidget {
|
||||
final Widget Function(BuildContext) onBuild;
|
||||
final Offset offset;
|
||||
final Widget Function(BuildContext)? onBuild;
|
||||
final Offset? offset;
|
||||
|
||||
const _PopupContentBody({Key key, this.onBuild, this.offset})
|
||||
const _PopupContentBody({Key? key, this.onBuild, this.offset})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@ -132,12 +132,12 @@ class _PopupContentBody extends StatelessWidget {
|
||||
child: Container(color: Color(0x55000000)),
|
||||
),
|
||||
Positioned(
|
||||
left: offset.dx - _overlay_w + 4,
|
||||
top: offset.dy - 4,
|
||||
left: offset!.dx - _overlay_w + 4,
|
||||
top: offset!.dy - 4,
|
||||
width: _overlay_w,
|
||||
height: _overlay_h,
|
||||
child: Scaffold(
|
||||
body: Card(child: onBuild(context)),
|
||||
body: Card(child: onBuild!(context)),
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
)
|
||||
|
@ -15,9 +15,9 @@ class CallWindowWidget extends StatefulWidget {
|
||||
final void Function() onClose;
|
||||
|
||||
const CallWindowWidget({
|
||||
Key key,
|
||||
@required this.convID,
|
||||
@required this.onClose,
|
||||
Key? key,
|
||||
required this.convID,
|
||||
required this.onClose,
|
||||
}) : assert(convID != null),
|
||||
assert(onClose != null),
|
||||
super(key: key);
|
||||
@ -27,7 +27,7 @@ class CallWindowWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CallWindowWidgetState extends State<CallWindowWidget> {
|
||||
double _left, _top;
|
||||
double? _left, _top;
|
||||
|
||||
var _fullScreen = false;
|
||||
|
||||
@ -71,7 +71,7 @@ class _CallWindowWidgetState extends State<CallWindowWidget> {
|
||||
height: 30,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
title: Text(convName == null ? tr("Loading...") : convName),
|
||||
title: Text(convName == null ? tr("Loading...")! : convName),
|
||||
actions: <Widget>[
|
||||
// Go full screen
|
||||
IconButton(
|
||||
@ -98,9 +98,9 @@ class _CallWindowWidgetState extends State<CallWindowWidget> {
|
||||
void _moveEnd(DraggableDetails details) {
|
||||
// Determine the limits of containing stack
|
||||
RenderBox renderBox = context
|
||||
.findAncestorStateOfType<CallsAreaState>()
|
||||
.findAncestorStateOfType<CallsAreaState>()!
|
||||
.context
|
||||
.findRenderObject();
|
||||
.findRenderObject() as RenderBox;
|
||||
final size = renderBox.size;
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
@ -109,13 +109,13 @@ class _CallWindowWidgetState extends State<CallWindowWidget> {
|
||||
_left = details.offset.dx - offset.dx;
|
||||
|
||||
// Force the window to appear completely on the screen
|
||||
if (_top + _WindowSize.height >= size.height)
|
||||
if (_top! + _WindowSize.height >= size.height)
|
||||
_top = size.height - _WindowSize.height;
|
||||
if (_left + _WindowSize.width >= size.width)
|
||||
if (_left! + _WindowSize.width >= size.width)
|
||||
_left = size.width - _WindowSize.width;
|
||||
|
||||
if (_top < 0) _top = 0;
|
||||
if (_left < 0) _left = 0;
|
||||
if (_top! < 0) _top = 0;
|
||||
if (_left! < 0) _left = 0;
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class CallsArea extends StatefulWidget {
|
||||
const CallsArea({Key key}) : super(key: key);
|
||||
const CallsArea({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
CallsAreaState createState() => CallsAreaState();
|
||||
|
@ -24,9 +24,9 @@ class ConversationWindow extends StatefulWidget {
|
||||
final Function() onClose;
|
||||
|
||||
const ConversationWindow({
|
||||
Key key,
|
||||
@required this.convID,
|
||||
@required this.onClose,
|
||||
Key? key,
|
||||
required this.convID,
|
||||
required this.onClose,
|
||||
}) : assert(convID != null),
|
||||
assert(onClose != null),
|
||||
super(key: key);
|
||||
@ -36,8 +36,8 @@ class ConversationWindow extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
Conversation _conversation;
|
||||
String _convTitle;
|
||||
Conversation? _conversation;
|
||||
late String _convTitle;
|
||||
bool _error = false;
|
||||
bool _collapsed = false;
|
||||
bool _hasNewMessages = false;
|
||||
@ -71,7 +71,7 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
} catch (e, s) {
|
||||
_setError(true);
|
||||
print("Could not refresh the list of conversations! $e\n$s");
|
||||
showSimpleSnack(context, tr("Could not load conversation information!"));
|
||||
showSimpleSnack(context, tr("Could not load conversation information!")!);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
if (_error)
|
||||
return ConversationWindowContainer(
|
||||
icon: Icon(Icons.error),
|
||||
title: Text(tr("Error")),
|
||||
title: Text(tr("Error")!),
|
||||
onClose: widget.onClose,
|
||||
onToggleCollapse: _toggleVisibility,
|
||||
isCollapsed: _collapsed,
|
||||
@ -100,7 +100,7 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: _refresh,
|
||||
child: Text(tr("Try again").toUpperCase()),
|
||||
child: Text(tr("Try again")!.toUpperCase()),
|
||||
)
|
||||
]),
|
||||
);
|
||||
@ -109,7 +109,7 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
if (_conversation == null)
|
||||
return ConversationWindowContainer(
|
||||
icon: Icon(Icons.message),
|
||||
title: Text(tr("Loading...")),
|
||||
title: Text(tr("Loading...")!),
|
||||
onClose: widget.onClose,
|
||||
onToggleCollapse: _toggleVisibility,
|
||||
isCollapsed: _collapsed,
|
||||
@ -123,7 +123,7 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
onClose: widget.onClose,
|
||||
onToggleCollapse: _toggleVisibility,
|
||||
isCollapsed: _collapsed,
|
||||
action: (_conversation.callCapabilities != CallCapabilities.NONE
|
||||
action: (_conversation!.callCapabilities != CallCapabilities.NONE
|
||||
? [IconButton(icon: Icon(Icons.call), onPressed: _startCall)]
|
||||
: [])
|
||||
..addAll(<Widget>[
|
||||
@ -131,19 +131,19 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
itemBuilder: (c) => [
|
||||
// Show in full screen
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Open in full screen")),
|
||||
child: Text(tr("Open in full screen")!),
|
||||
value: _Actions.OPEN_FULL_SCREEN,
|
||||
),
|
||||
|
||||
// Show the list of members
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Members")),
|
||||
child: Text(tr("Members")!),
|
||||
value: _Actions.OPEN_MEMBERS,
|
||||
),
|
||||
|
||||
// Show conversation settings
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Settings")),
|
||||
child: Text(tr("Settings")!),
|
||||
value: _Actions.OPEN_SETTINGS,
|
||||
)
|
||||
],
|
||||
@ -174,8 +174,8 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
}
|
||||
|
||||
void _openFullScreen() {
|
||||
MainController.of(context)
|
||||
.openConversation(_conversation, fullScreen: true);
|
||||
MainController.of(context)!
|
||||
.openConversation(_conversation!, fullScreen: true);
|
||||
widget.onClose();
|
||||
}
|
||||
|
||||
@ -189,5 +189,5 @@ class _ConversationWindowState extends SafeState<ConversationWindow> {
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void _startCall() => MainController.of(context).startCall(_convID);
|
||||
void _startCall() => MainController.of(context)!.startCall(_convID);
|
||||
}
|
||||
|
@ -8,24 +8,24 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class ConversationWindowContainer extends StatelessWidget {
|
||||
final Color appBarBgColor;
|
||||
final Widget icon;
|
||||
final Color? appBarBgColor;
|
||||
final Widget? icon;
|
||||
final Widget title;
|
||||
final void Function() onClose;
|
||||
final void Function() onToggleCollapse;
|
||||
final bool isCollapsed;
|
||||
final Widget body;
|
||||
final List<Widget> action;
|
||||
final List<Widget>? action;
|
||||
|
||||
const ConversationWindowContainer({
|
||||
Key key,
|
||||
Key? key,
|
||||
this.appBarBgColor,
|
||||
this.icon,
|
||||
@required this.title,
|
||||
@required this.onClose,
|
||||
@required this.body,
|
||||
@required this.onToggleCollapse,
|
||||
@required this.isCollapsed,
|
||||
required this.title,
|
||||
required this.onClose,
|
||||
required this.body,
|
||||
required this.onToggleCollapse,
|
||||
required this.isCollapsed,
|
||||
this.action,
|
||||
}) : assert(title != null),
|
||||
assert(onClose != null),
|
||||
@ -47,7 +47,7 @@ class ConversationWindowContainer extends StatelessWidget {
|
||||
backgroundColor: appBarBgColor,
|
||||
leading: icon,
|
||||
title: GestureDetector(child: title, onTap: onToggleCollapse),
|
||||
actions: (action == null ? [] : action)
|
||||
actions: action ?? []
|
||||
..add(
|
||||
IconButton(icon: Icon(Icons.close), onPressed: onClose),
|
||||
),
|
||||
|
@ -9,14 +9,14 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre
|
||||
|
||||
class ConversationsAreaWidget extends StatefulWidget {
|
||||
const ConversationsAreaWidget({Key key}) : super(key: key);
|
||||
const ConversationsAreaWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
ConversationsAreaWidgetState createState() => ConversationsAreaWidgetState();
|
||||
}
|
||||
|
||||
class ConversationsAreaWidgetState extends State<ConversationsAreaWidget> {
|
||||
final _openConversations = Map<int, UniqueKey>();
|
||||
final _openConversations = Map<int?, UniqueKey>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -31,17 +31,17 @@ class ConversationsAreaWidgetState extends State<ConversationsAreaWidget> {
|
||||
Widget _buildOpenButton() => OpenConversationButton();
|
||||
|
||||
/// Open a new conversation
|
||||
void openConversations(int convID) {
|
||||
void openConversations(int? convID) {
|
||||
if (!_openConversations.containsKey(convID))
|
||||
setState(() => _openConversations[convID] = UniqueKey());
|
||||
}
|
||||
|
||||
MapEntry<int, Widget> _conversationWindow(int convID, UniqueKey key) =>
|
||||
MapEntry<int?, Widget> _conversationWindow(int? convID, UniqueKey key) =>
|
||||
MapEntry(
|
||||
convID,
|
||||
ConversationWindow(
|
||||
key: key,
|
||||
convID: convID,
|
||||
convID: convID!,
|
||||
onClose: () => setState(() => _openConversations.remove(convID)),
|
||||
),
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ class CurrentUserPanel extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CurrentUserPanelState extends SafeState<CurrentUserPanel> {
|
||||
User _user;
|
||||
User? _user;
|
||||
|
||||
Future<void> _refresh() async {
|
||||
try {
|
||||
@ -49,12 +49,12 @@ class _CurrentUserPanelState extends SafeState<CurrentUserPanel> {
|
||||
if (_user == null) return buildCenteredProgressBar();
|
||||
|
||||
return ListTile(
|
||||
onTap: () => MainController.of(context).openCurrentUserPage(),
|
||||
onTap: () => MainController.of(context)!.openCurrentUserPage(),
|
||||
leading: AccountImageWidget(
|
||||
user: _user,
|
||||
user: _user!,
|
||||
width: 50,
|
||||
),
|
||||
title: Text(_user.displayName),
|
||||
title: Text(_user!.displayName),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ class _GlobalSearchFieldState extends State<GlobalSearchField> {
|
||||
|
||||
final _controller = TextEditingController();
|
||||
|
||||
_SearchResults _searchResultsList;
|
||||
_SearchResults? _searchResultsList;
|
||||
|
||||
OverlayEntry _overlayEntry;
|
||||
OverlayEntry? _overlayEntry;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -96,29 +96,29 @@ class _GlobalSearchFieldState extends State<GlobalSearchField> {
|
||||
|
||||
_searchResultsList = _SearchResults(results, users, groups);
|
||||
|
||||
if (_overlayEntry != null) _overlayEntry.markNeedsBuild();
|
||||
if (_overlayEntry != null) _overlayEntry!.markNeedsBuild();
|
||||
} catch (e, s) {
|
||||
print("Could not perform search! $e\n$s");
|
||||
showSimpleSnack(context, tr("Could not perform search!"));
|
||||
showSimpleSnack(context, tr("Could not perform search!")!);
|
||||
}
|
||||
}
|
||||
|
||||
void _showOverlay() {
|
||||
if (_overlayEntry == null) {
|
||||
_overlayEntry = _createOverlayEntry();
|
||||
Overlay.of(context).insert(_overlayEntry);
|
||||
Overlay.of(context)!.insert(_overlayEntry!);
|
||||
}
|
||||
}
|
||||
|
||||
void _removeOverlay() {
|
||||
if (_overlayEntry != null) {
|
||||
_overlayEntry.remove();
|
||||
_overlayEntry!.remove();
|
||||
_overlayEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
OverlayEntry _createOverlayEntry() {
|
||||
RenderBox renderBox = context.findRenderObject();
|
||||
RenderBox renderBox = context.findRenderObject() as RenderBox;
|
||||
var size = renderBox.size;
|
||||
var offset = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
@ -140,13 +140,13 @@ class _GlobalSearchFieldState extends State<GlobalSearchField> {
|
||||
}
|
||||
|
||||
class _SearchResultsWidget extends StatelessWidget {
|
||||
final _SearchResults results;
|
||||
final _SearchResults? results;
|
||||
final Function() onTap;
|
||||
|
||||
const _SearchResultsWidget({
|
||||
Key key,
|
||||
@required this.results,
|
||||
@required this.onTap,
|
||||
Key? key,
|
||||
required this.results,
|
||||
required this.onTap,
|
||||
}) : assert(onTap != null),
|
||||
super(key: key);
|
||||
|
||||
@ -155,32 +155,32 @@ class _SearchResultsWidget extends StatelessWidget {
|
||||
if (results == null) return Container();
|
||||
return ListView.builder(
|
||||
itemBuilder: _builder,
|
||||
itemCount: results.list.length,
|
||||
itemCount: results!.list.length,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _builder(BuildContext context, int index) {
|
||||
final res = results.list[index];
|
||||
final SearchResult res = results!.list[index];
|
||||
|
||||
switch (res.kind) {
|
||||
case SearchResultKind.USER:
|
||||
final user = results.users.getUser(res.id);
|
||||
final user = results!.users.getUser(res.id);
|
||||
return ListTile(
|
||||
leading: AccountImageWidget(user: user),
|
||||
title: Text(user.displayName),
|
||||
onTap: () {
|
||||
MainController.of(context).openUserPage(user.id);
|
||||
MainController.of(context)!.openUserPage(user.id!);
|
||||
onTap();
|
||||
},
|
||||
);
|
||||
|
||||
case SearchResultKind.GROUP:
|
||||
final group = results.groups.getGroup(res.id);
|
||||
final group = results!.groups.getGroup(res.id)!;
|
||||
return ListTile(
|
||||
leading: GroupIcon(group: group),
|
||||
title: Text(group.displayName),
|
||||
onTap: () {
|
||||
MainController.of(context).openGroup(group.id);
|
||||
MainController.of(context)!.openGroup(group.id);
|
||||
onTap();
|
||||
},
|
||||
);
|
||||
|
@ -29,8 +29,8 @@ class MembershipsPanel extends StatefulWidget {
|
||||
final PageInfo currentPage;
|
||||
|
||||
const MembershipsPanel({
|
||||
Key key,
|
||||
@required this.currentPage,
|
||||
Key? key,
|
||||
required this.currentPage,
|
||||
}) : assert(currentPage != null),
|
||||
super(key: key);
|
||||
|
||||
@ -42,9 +42,9 @@ const _MembershipIconsWidth = 30.0;
|
||||
|
||||
class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
final _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
MembershipList _membershipList;
|
||||
UsersList _usersList;
|
||||
GroupsList _groupsList;
|
||||
MembershipList? _membershipList;
|
||||
UsersList? _usersList;
|
||||
late GroupsList _groupsList;
|
||||
|
||||
Future<void> _refresh() async {
|
||||
try {
|
||||
@ -87,13 +87,13 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
iconColor: IconTheme.of(context).color,
|
||||
child: ListView.builder(
|
||||
itemBuilder: _buildMembershipTile,
|
||||
itemCount: _membershipList.length,
|
||||
itemCount: _membershipList!.length,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMembershipTile(BuildContext context, int index) {
|
||||
final membership = _membershipList[index];
|
||||
final Membership membership = _membershipList![index]!;
|
||||
|
||||
switch (membership.type) {
|
||||
case MembershipType.FRIEND:
|
||||
@ -111,17 +111,19 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
|
||||
// TODO : add private messages icon support
|
||||
Widget _buildFriendMembership(Membership membership) {
|
||||
final user = _usersList.getUser(membership.friend.id);
|
||||
final connected = membership.friend.isConnected;
|
||||
final user = _usersList!.getUser(membership.friend!.id);
|
||||
final connected = membership.friend!.isConnected;
|
||||
|
||||
Widget subtitle;
|
||||
|
||||
if (!membership.friend.accepted) {
|
||||
final friend = membership.friend!;
|
||||
|
||||
if (!friend.accepted) {
|
||||
subtitle = RichText(
|
||||
text: TextSpan(children: [
|
||||
WidgetSpan(
|
||||
child: _RespondFriendshipRequestButton(
|
||||
friend: membership.friend,
|
||||
friend: friend,
|
||||
accept: true,
|
||||
text: tr("Accept"),
|
||||
color: Colors.green,
|
||||
@ -130,7 +132,7 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
TextSpan(text: " "),
|
||||
WidgetSpan(
|
||||
child: _RespondFriendshipRequestButton(
|
||||
friend: membership.friend,
|
||||
friend: friend,
|
||||
accept: false,
|
||||
text: tr("Reject"),
|
||||
color: Colors.red,
|
||||
@ -139,7 +141,9 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
]));
|
||||
} else
|
||||
subtitle = Text(
|
||||
connected ? tr("Online") : diffTimeFromNowToStr(membership.lastActive),
|
||||
connected
|
||||
? tr("Online")!
|
||||
: diffTimeFromNowToStr(membership.lastActive!)!,
|
||||
style: TextStyle(color: connected ? Colors.green : null),
|
||||
);
|
||||
|
||||
@ -152,13 +156,13 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
leading: AccountImageWidget(user: user, width: _MembershipIconsWidth),
|
||||
title: Text(user.displayName),
|
||||
subtitle: subtitle,
|
||||
onTap: () => MainController.of(context).openUserPage(user.id),
|
||||
onTap: () => MainController.of(context)!.openUserPage(user.id!),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildGroupMembership(Membership membership) {
|
||||
final group = _groupsList.getGroup(membership.groupID);
|
||||
final group = _groupsList.getGroup(membership.groupID)!;
|
||||
|
||||
return Container(
|
||||
color: widget.currentPage.type == PageType.GROUP_PAGE &&
|
||||
@ -167,11 +171,11 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
: null,
|
||||
child: Column(
|
||||
children: [_buildMainGroupInformationTile(membership, group)]
|
||||
..addAll(_membershipList
|
||||
..addAll(_membershipList!
|
||||
.getGroupConversations(group.id)
|
||||
.map((e) => Padding(
|
||||
padding: const EdgeInsets.only(left: 30.0),
|
||||
child: _buildConversationMembership(e, true),
|
||||
child: _buildConversationMembership(e!, true),
|
||||
))
|
||||
.toList()),
|
||||
),
|
||||
@ -183,11 +187,11 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
if (!group.isAtLeastMember) {
|
||||
subtitle = GroupMembershipWidget(
|
||||
group: group,
|
||||
onUpdated: () => _refreshKey.currentState.show(),
|
||||
onUpdated: () => _refreshKey.currentState!.show(),
|
||||
onError: _onGroupMembershipUpdateError,
|
||||
);
|
||||
} else {
|
||||
subtitle = Text(diffTimeFromNowToStr(membership.lastActive));
|
||||
subtitle = Text(diffTimeFromNowToStr(membership.lastActive!)!);
|
||||
} // Main group information
|
||||
|
||||
return ListTile(
|
||||
@ -197,17 +201,17 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
),
|
||||
title: Text(group.displayName),
|
||||
subtitle: subtitle,
|
||||
onTap: () => MainController.of(context).openGroup(group.id),
|
||||
onTap: () => MainController.of(context)!.openGroup(group.id),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildConversationMembership(Membership membership,
|
||||
[bool allowGroup = false]) {
|
||||
final conversation = membership.conversation;
|
||||
final conversation = membership.conversation!;
|
||||
|
||||
if (conversation.isGroupConversation && !allowGroup) return Container();
|
||||
|
||||
Color color;
|
||||
Color? color;
|
||||
if (conversation.isHavingCall)
|
||||
color = Color(0xFF815d1d);
|
||||
else if (widget.currentPage.type == PageType.CONVERSATION_PAGE &&
|
||||
@ -221,7 +225,7 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
dense: true,
|
||||
leading: ConversationImageWidget(
|
||||
conversation: conversation,
|
||||
users: _usersList,
|
||||
users: _usersList!,
|
||||
noUserImage: conversation.isGroupConversation,
|
||||
),
|
||||
title: Row(
|
||||
@ -233,20 +237,20 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Text(ConversationsHelper.getConversationName(
|
||||
conversation, _usersList)),
|
||||
conversation, _usersList)!),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Text(diffTimeFromNowToStr(membership.lastActive) +
|
||||
(conversation.isHavingCall ? "\n" + tr("Ongoing call") : "")),
|
||||
onTap: () => MainController.of(context)
|
||||
subtitle: Text(diffTimeFromNowToStr(membership.lastActive!)! +
|
||||
(conversation.isHavingCall ? "\n" + tr("Ongoing call")! : "")),
|
||||
onTap: () => MainController.of(context)!
|
||||
.openConversation(conversation, fullScreen: true),
|
||||
trailing: conversation.isHavingCall
|
||||
? FloatingActionButton(
|
||||
heroTag: null,
|
||||
child: Icon(Icons.call),
|
||||
onPressed: () =>
|
||||
MainController.of(context).startCall(conversation.id),
|
||||
MainController.of(context)!.startCall(conversation.id!),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@ -269,43 +273,43 @@ class _MembershipsPanelState extends SafeState<MembershipsPanel> {
|
||||
if (accept)
|
||||
f.accepted = true;
|
||||
else
|
||||
_membershipList.removeFriend(f.id);
|
||||
_membershipList!.removeFriend(f.id);
|
||||
});
|
||||
_refreshKey.currentState.show();
|
||||
_refreshKey.currentState!.show();
|
||||
} catch (e, s) {
|
||||
print("Could not respond to friendship request! $e\n$s");
|
||||
showSimpleSnack(context, tr("Could not respond to friendship request!"));
|
||||
showSimpleSnack(context, tr("Could not respond to friendship request!")!);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the case of failure in group membership update
|
||||
void _onGroupMembershipUpdateError() {
|
||||
showSimpleSnack(context, tr("Could not update group membership!"));
|
||||
_refreshKey.currentState.show();
|
||||
showSimpleSnack(context, tr("Could not update group membership!")!);
|
||||
_refreshKey.currentState!.show();
|
||||
}
|
||||
}
|
||||
|
||||
class _RespondFriendshipRequestButton extends StatelessWidget {
|
||||
final Friend friend;
|
||||
final bool accept;
|
||||
final String text;
|
||||
final String? text;
|
||||
final Color color;
|
||||
final void Function(Friend, bool) onTap;
|
||||
|
||||
const _RespondFriendshipRequestButton({
|
||||
Key key,
|
||||
@required this.friend,
|
||||
@required this.accept,
|
||||
@required this.text,
|
||||
@required this.color,
|
||||
@required this.onTap,
|
||||
Key? key,
|
||||
required this.friend,
|
||||
required this.accept,
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.onTap,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => onTap(friend, accept),
|
||||
child: Text(text, style: TextStyle(color: color)),
|
||||
child: Text(text!, style: TextStyle(color: color)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ class _ComunicTabletAppBarWidgetState
|
||||
return AppBar(
|
||||
title: GestureDetector(
|
||||
child: Text("Comunic"),
|
||||
onTap: () => MainController.of(context).openLatestPostsPage()),
|
||||
onTap: () => MainController.of(context)!.openLatestPostsPage()),
|
||||
actions: <Widget>[
|
||||
AppBarCustomDropDownWidget(
|
||||
key: notificationsDropdownKey,
|
||||
icon: Icon(Icons.notifications),
|
||||
notificationsBadge: _unreadNotifications.notifications,
|
||||
notificationsBadge: _unreadNotifications.notifications!,
|
||||
onBuildOverlay: (c) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: NotificationsScreen(useSmallDeleteButton: true),
|
||||
@ -77,7 +77,7 @@ class _ComunicTabletAppBarWidgetState
|
||||
AppBarCustomDropDownWidget(
|
||||
key: conversationsDropdownKey,
|
||||
icon: Icon(Icons.message),
|
||||
notificationsBadge: _unreadNotifications.conversations,
|
||||
notificationsBadge: _unreadNotifications.conversations!,
|
||||
onBuildOverlay: (c) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: UnreadConversationsScreen(),
|
||||
@ -88,29 +88,29 @@ class _ComunicTabletAppBarWidgetState
|
||||
itemBuilder: (c) => [
|
||||
// Get groups
|
||||
_MainMenuItem(
|
||||
label: tr("Groups"),
|
||||
label: tr("Groups")!,
|
||||
icon: Icons.group,
|
||||
onTap: () => MainController.of(context).openGroupsListPage()),
|
||||
onTap: () => MainController.of(context)!.openGroupsListPage()),
|
||||
|
||||
// Toggle dark theme
|
||||
_MainMenuItem(
|
||||
label: tr("Night mode"),
|
||||
icon: preferences().preferences.enableDarkMode
|
||||
label: tr("Night mode")!,
|
||||
icon: preferences()!.preferences.enableDarkMode
|
||||
? Icons.brightness_2
|
||||
: Icons.wb_sunny,
|
||||
onTap: _toggleDarkMode),
|
||||
|
||||
// Open settings
|
||||
_MainMenuItem(
|
||||
label: tr("Settings"),
|
||||
label: tr("Settings")!,
|
||||
icon: Icons.settings,
|
||||
onTap: () => MainController.of(context).openSettings()),
|
||||
onTap: () => MainController.of(context)!.openSettings()),
|
||||
|
||||
// Sign out
|
||||
_MainMenuItem(
|
||||
label: tr("Sign out"),
|
||||
label: tr("Sign out")!,
|
||||
icon: Icons.power_settings_new,
|
||||
onTap: () => MainController.of(context).requestLogout()),
|
||||
onTap: () => MainController.of(context)!.requestLogout()),
|
||||
],
|
||||
onSelected: (v) => v(),
|
||||
),
|
||||
@ -120,9 +120,9 @@ class _ComunicTabletAppBarWidgetState
|
||||
|
||||
/// Toggle dark mode
|
||||
void _toggleDarkMode() async {
|
||||
final prefs = preferences().preferences;
|
||||
final prefs = preferences()!.preferences;
|
||||
prefs.enableDarkMode = !prefs.enableDarkMode;
|
||||
await preferences().setPreferences(prefs);
|
||||
await preferences()!.setPreferences(prefs);
|
||||
|
||||
applyNewThemeSettings(context);
|
||||
}
|
||||
@ -136,9 +136,9 @@ class _MainMenuItem extends PopupMenuEntry<_MenuItemCallback> {
|
||||
final _MenuItemCallback onTap;
|
||||
|
||||
const _MainMenuItem({
|
||||
@required this.label,
|
||||
@required this.icon,
|
||||
@required this.onTap,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
required this.onTap,
|
||||
}) : assert(label != null),
|
||||
assert(icon != null),
|
||||
assert(onTap != null);
|
||||
@ -150,7 +150,7 @@ class _MainMenuItem extends PopupMenuEntry<_MenuItemCallback> {
|
||||
double get height => kMinInteractiveDimension;
|
||||
|
||||
@override
|
||||
bool represents(_MenuItemCallback value) => onTap == value;
|
||||
bool represents(_MenuItemCallback? value) => onTap == value;
|
||||
}
|
||||
|
||||
class __MainMenuItemState extends State<_MainMenuItem> {
|
||||
|
@ -23,14 +23,14 @@ import 'package:flutter/material.dart';
|
||||
|
||||
class UserPageTablet extends StatefulWidget {
|
||||
final AdvancedUserInfo userInfo;
|
||||
final FriendStatus friendshipStatus;
|
||||
final FriendStatus? friendshipStatus;
|
||||
final void Function() onNeedRefresh;
|
||||
|
||||
const UserPageTablet({
|
||||
Key key,
|
||||
@required this.userInfo,
|
||||
@required this.friendshipStatus,
|
||||
@required this.onNeedRefresh,
|
||||
Key? key,
|
||||
required this.userInfo,
|
||||
required this.friendshipStatus,
|
||||
required this.onNeedRefresh,
|
||||
}) : assert(userInfo != null),
|
||||
assert(onNeedRefresh != null),
|
||||
super(key: key);
|
||||
@ -106,7 +106,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
_isCurrentUser
|
||||
? Container()
|
||||
: FriendshipStatusWidget(
|
||||
status: widget.friendshipStatus,
|
||||
status: widget.friendshipStatus!,
|
||||
onFriendshipUpdated: widget.onNeedRefresh,
|
||||
)
|
||||
],
|
||||
@ -124,7 +124,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
_userInfo.isFriendsListPublic
|
||||
? Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () => MainController.of(context)
|
||||
onPressed: () => MainController.of(context)!
|
||||
.openUserFriendsList(_userInfo.id),
|
||||
icon: Icon(Icons.group),
|
||||
label: Text("${_userInfo.numberFriends}"),
|
||||
@ -153,7 +153,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
// User membership
|
||||
_AboutUserEntry(
|
||||
icon: Icons.access_time,
|
||||
title: tr("Membership"),
|
||||
title: tr("Membership")!,
|
||||
value: tr("Member for %t%", args: {
|
||||
"t": diffTimeFromNowToStr(_userInfo.accountCreationTime)
|
||||
})),
|
||||
@ -161,7 +161,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
// User public note
|
||||
_AboutUserEntry(
|
||||
icon: Icons.note,
|
||||
title: tr("Note"),
|
||||
title: tr("Note")!,
|
||||
value: _userInfo.publicNote,
|
||||
visible: _userInfo.hasPublicNote,
|
||||
parsed: true,
|
||||
@ -170,7 +170,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
// User email address
|
||||
_AboutUserEntry(
|
||||
icon: Icons.mail_outline,
|
||||
title: tr("Email address"),
|
||||
title: tr("Email address")!,
|
||||
value: _userInfo.emailAddress,
|
||||
visible: _userInfo.emailAddress != null,
|
||||
),
|
||||
@ -178,7 +178,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
// Location
|
||||
_AboutUserEntry(
|
||||
icon: Icons.location_on,
|
||||
title: tr("Location"),
|
||||
title: tr("Location")!,
|
||||
value: _userInfo.location,
|
||||
visible: _userInfo.location != null,
|
||||
),
|
||||
@ -186,7 +186,7 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
// User website
|
||||
_AboutUserEntry(
|
||||
icon: Icons.link,
|
||||
title: tr("Website"),
|
||||
title: tr("Website")!,
|
||||
value: _userInfo.personalWebsite,
|
||||
visible: _userInfo.hasPersonalWebsite,
|
||||
parsed: true,
|
||||
@ -197,9 +197,9 @@ class _UserPageTabletState extends State<UserPageTablet> {
|
||||
}
|
||||
|
||||
class _LeftPaneContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Widget? child;
|
||||
|
||||
const _LeftPaneContainer({Key key, this.child}) : super(key: key);
|
||||
const _LeftPaneContainer({Key? key, this.child}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -218,7 +218,7 @@ class _LeftPaneContainer extends StatelessWidget {
|
||||
class _MainCardSpacer extends StatelessWidget {
|
||||
final bool visible;
|
||||
|
||||
const _MainCardSpacer({this.visible = true, Key key})
|
||||
const _MainCardSpacer({this.visible = true, Key? key})
|
||||
: assert(visible != null),
|
||||
super(key: key);
|
||||
|
||||
@ -230,15 +230,15 @@ class _MainCardSpacer extends StatelessWidget {
|
||||
class _AboutUserEntry extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String value;
|
||||
final String? value;
|
||||
final bool visible;
|
||||
final bool parsed;
|
||||
|
||||
const _AboutUserEntry({
|
||||
Key key,
|
||||
@required this.icon,
|
||||
@required this.title,
|
||||
@required this.value,
|
||||
Key? key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.value,
|
||||
this.visible = true,
|
||||
this.parsed = false,
|
||||
}) : assert(icon != null),
|
||||
@ -268,7 +268,7 @@ class _AboutUserEntry extends StatelessWidget {
|
||||
content: DisplayedString(value),
|
||||
style: TextStyle(),
|
||||
)
|
||||
: Text(value),
|
||||
: Text(value!),
|
||||
dense: true,
|
||||
);
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
class TextRichContentWidget extends StatelessWidget {
|
||||
final TextAlign textAlign;
|
||||
final TextStyle style;
|
||||
final TextAlign? textAlign;
|
||||
final TextStyle? style;
|
||||
final String text;
|
||||
|
||||
TextRichContentWidget(
|
||||
@ -22,7 +22,7 @@ class TextRichContentWidget extends StatelessWidget {
|
||||
}) : assert(text != null);
|
||||
|
||||
/// Parse the text and return it as a list of span elements
|
||||
static List<TextSpan> _parse(String text, TextStyle style) {
|
||||
static List<TextSpan> _parse(String text, TextStyle? style) {
|
||||
if (style == null) style = TextStyle();
|
||||
|
||||
List<TextSpan> list = [];
|
||||
@ -37,7 +37,7 @@ class TextRichContentWidget extends StatelessWidget {
|
||||
|
||||
// Add link
|
||||
list.add(TextSpan(
|
||||
style: style.copyWith(color: Colors.indigo),
|
||||
style: style!.copyWith(color: Colors.indigo),
|
||||
text: s,
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@ -63,6 +63,6 @@ class TextRichContentWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RichText(
|
||||
textAlign: textAlign, text: TextSpan(children: _parse(text, style)));
|
||||
textAlign: textAlign!, text: TextSpan(children: _parse(text, style)));
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
class TextWidget extends StatelessWidget {
|
||||
final DisplayedString content;
|
||||
final bool parseBBcode;
|
||||
final TextStyle style;
|
||||
final TextStyle? style;
|
||||
final TextAlign textAlign;
|
||||
final Color linksColor;
|
||||
|
||||
const TextWidget({
|
||||
Key key,
|
||||
@required this.content,
|
||||
Key? key,
|
||||
required this.content,
|
||||
this.parseBBcode = false,
|
||||
this.textAlign = TextAlign.start,
|
||||
this.style,
|
||||
@ -35,7 +35,7 @@ class TextWidget extends StatelessWidget {
|
||||
|
||||
var usedStyle = style == null ? Theme.of(context).textTheme.bodyText2 : style;
|
||||
|
||||
var content = this.content.parsedString;
|
||||
var content = this.content.parsedString!;
|
||||
|
||||
/*// Parse BBcode
|
||||
if (parseBBcode)
|
||||
@ -53,7 +53,7 @@ class TextWidget extends StatelessWidget {
|
||||
|
||||
/// Sub parse function
|
||||
List<InlineSpan> _parseLinks(
|
||||
BuildContext context, String text, TextStyle style) {
|
||||
BuildContext context, String text, TextStyle? style) {
|
||||
var buff = StringBuffer();
|
||||
final list = <InlineSpan>[];
|
||||
|
||||
@ -79,7 +79,7 @@ class TextWidget extends StatelessWidget {
|
||||
child: InkWell(
|
||||
child: Text(
|
||||
word,
|
||||
style: style.copyWith(color: linksColor),
|
||||
style: style!.copyWith(color: linksColor),
|
||||
),
|
||||
onTap: () => launch(word),
|
||||
),
|
||||
@ -98,7 +98,7 @@ class TextWidget extends StatelessWidget {
|
||||
child: InkWell(
|
||||
child: Text(
|
||||
word,
|
||||
style: style.copyWith(color: linksColor),
|
||||
style: style!.copyWith(color: linksColor),
|
||||
),
|
||||
onTap: () => openVirtualDirectory(context, word),
|
||||
),
|
||||
|
@ -9,11 +9,11 @@ class AccountImageTourPane extends PresentationPane {
|
||||
final Function(BuildContext) onUpdated;
|
||||
|
||||
AccountImageTourPane({
|
||||
@required User user,
|
||||
@required this.onUpdated,
|
||||
required User user,
|
||||
required this.onUpdated,
|
||||
}) : super(
|
||||
iconWidget: AccountImageWidget(user: user, width: 50),
|
||||
title: tr("Account image"),
|
||||
title: tr("Account image")!,
|
||||
text:
|
||||
"${tr("Account images allow to quickly recognize people.")}\n\n${tr("You can decide to define one now!")}",
|
||||
actionTitle: tr("Upload an account image"),
|
||||
|
@ -8,10 +8,10 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class FirstTourPane extends StatelessWidget {
|
||||
final String msgOne;
|
||||
final String msgTwo;
|
||||
final String? msgOne;
|
||||
final String? msgTwo;
|
||||
|
||||
const FirstTourPane({Key key, this.msgOne, this.msgTwo}) : super(key: key);
|
||||
const FirstTourPane({Key? key, this.msgOne, this.msgTwo}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -4,13 +4,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FixedTourSizeTextArea extends StatelessWidget {
|
||||
final String text;
|
||||
final String? text;
|
||||
|
||||
const FixedTourSizeTextArea(this.text);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 300),
|
||||
child: Text(text, textAlign: TextAlign.justify),
|
||||
child: Text(text!, textAlign: TextAlign.justify),
|
||||
);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ class LastTourPane extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Text(
|
||||
tr("The application is yours"),
|
||||
tr("The application is yours")!,
|
||||
style: TextStyle(fontSize: 25),
|
||||
),
|
||||
);
|
||||
|
@ -5,22 +5,22 @@ import 'package:comunic/ui/widgets/tour/fixed_tour_size_text_area.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PresentationPane extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final Widget iconWidget;
|
||||
final IconData? icon;
|
||||
final Widget? iconWidget;
|
||||
final String title;
|
||||
final String text;
|
||||
final Function(BuildContext) child;
|
||||
final String actionTitle;
|
||||
final Function(BuildContext) onActionTap;
|
||||
final String? text;
|
||||
final Function(BuildContext)? child;
|
||||
final String? actionTitle;
|
||||
final Function(BuildContext)? onActionTap;
|
||||
final bool canGoNext;
|
||||
final Future<bool> Function(BuildContext) onTapNext;
|
||||
final Future<bool> Function(BuildContext)? onTapNext;
|
||||
final bool visible;
|
||||
|
||||
const PresentationPane({
|
||||
Key key,
|
||||
Key? key,
|
||||
this.icon,
|
||||
this.iconWidget,
|
||||
@required this.title,
|
||||
required this.title,
|
||||
this.text,
|
||||
this.child,
|
||||
this.actionTitle,
|
||||
@ -41,7 +41,7 @@ class PresentationPane extends StatelessWidget {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Spacer(flex: 3),
|
||||
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget,
|
||||
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget!,
|
||||
Spacer(flex: 1),
|
||||
Text(
|
||||
title,
|
||||
@ -52,9 +52,9 @@ class PresentationPane extends StatelessWidget {
|
||||
Spacer(flex: 1),
|
||||
_hasAction
|
||||
? OutlinedButton(
|
||||
onPressed: () => onActionTap(context),
|
||||
onPressed: () => onActionTap!(context),
|
||||
child: Text(
|
||||
actionTitle,
|
||||
actionTitle!,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
)
|
||||
@ -72,7 +72,7 @@ class PresentationPane extends StatelessWidget {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Spacer(flex: 1),
|
||||
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget,
|
||||
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget!,
|
||||
Spacer(flex: 1),
|
||||
Text(
|
||||
title,
|
||||
@ -81,7 +81,7 @@ class PresentationPane extends StatelessWidget {
|
||||
Spacer(flex: 1),
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: 300),
|
||||
child: SingleChildScrollView(child: child(context))),
|
||||
child: SingleChildScrollView(child: child!(context))),
|
||||
Spacer(flex: 1),
|
||||
],
|
||||
);
|
||||
|
@ -11,24 +11,24 @@ import 'package:flutter/material.dart';
|
||||
|
||||
class TourNotificationsPane extends PresentationPane {
|
||||
TourNotificationsPane({
|
||||
Key key,
|
||||
@required
|
||||
Key? key,
|
||||
required
|
||||
GlobalKey<PushNotificationsConfigurationWidgetState>
|
||||
pushNotificationsKey,
|
||||
@required Function() onConfigured,
|
||||
@required Function() onChanged,
|
||||
@required bool visible,
|
||||
required Function() onConfigured,
|
||||
required Function() onChanged,
|
||||
required bool visible,
|
||||
}) : assert(pushNotificationsKey != null),
|
||||
super(
|
||||
icon: Icons.notifications,
|
||||
title: tr("Push notifications"),
|
||||
title: tr("Push notifications")!,
|
||||
child: (c) => PushNotificationsConfigurationWidget(
|
||||
key: pushNotificationsKey,
|
||||
onConfigured: onConfigured,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
canGoNext: pushNotificationsKey?.currentState?.canSubmit ?? false,
|
||||
onTapNext: (c) => pushNotificationsKey.currentState.submit(),
|
||||
onTapNext: (c) => pushNotificationsKey.currentState!.submit(),
|
||||
visible: visible,
|
||||
);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import 'package:flutter/material.dart';
|
||||
class UserWritingInConvNotifier extends StatefulWidget {
|
||||
final int convID;
|
||||
|
||||
const UserWritingInConvNotifier({Key key, @required this.convID})
|
||||
const UserWritingInConvNotifier({Key? key, required this.convID})
|
||||
: assert(convID != null),
|
||||
super(key: key);
|
||||
|
||||
@ -52,14 +52,14 @@ class _UserWritingInConvNotifierState
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
writingText,
|
||||
writingText!,
|
||||
style: TextStyle(fontSize: 10),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
String get writingText {
|
||||
String? get writingText {
|
||||
if (_list.isEmpty) return "";
|
||||
|
||||
final users = _list.toSet().map((e) => _usersInfo.getUser(e)).toList();
|
||||
@ -73,11 +73,11 @@ class _UserWritingInConvNotifierState
|
||||
});
|
||||
}
|
||||
|
||||
void _handleEvent(int userID) async {
|
||||
void _handleEvent(int? userID) async {
|
||||
setState(() => this._list.add(userID));
|
||||
|
||||
await Future.delayed(
|
||||
Duration(seconds: srvConfig.conversationsPolicy.writingEventLifetime));
|
||||
Duration(seconds: srvConfig!.conversationsPolicy.writingEventLifetime));
|
||||
|
||||
setState(() => this._list.removeAt(0));
|
||||
}
|
||||
|
Reference in New Issue
Block a user