1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2025-06-20 00:35:17 +00:00

Start to fix null safety migration errors

This commit is contained in:
2022-03-10 19:39:57 +01:00
parent ab2c5da0da
commit 3a997cdc56
258 changed files with 2879 additions and 2912 deletions

View File

@ -18,9 +18,9 @@ class ConversationMessageStatsRoute extends StatefulWidget {
final ConversationMessage message;
const ConversationMessageStatsRoute({
Key key,
@required this.conv,
@required this.message,
Key? key,
required this.conv,
required this.message,
}) : assert(conv != null),
assert(message != null),
super(key: key);
@ -32,7 +32,7 @@ class ConversationMessageStatsRoute extends StatefulWidget {
class _ConversationMessageStatsRouteState
extends State<ConversationMessageStatsRoute> {
UsersList _users;
late UsersList _users;
Future<void> _init() async {
_users = await UsersHelper()
@ -43,23 +43,23 @@ class _ConversationMessageStatsRouteState
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(tr("Message statistics")),
title: Text(tr("Message statistics")!),
leading: IconButton(
icon: Icon(Icons.close),
onPressed: () => MainController.of(context).popPage(),
onPressed: () => MainController.of(context)!.popPage(),
),
),
body: AsyncScreenWidget(
onReload: _init,
onBuild: _buildScreen,
errorMessage: tr("Failed to load message information!")),
errorMessage: tr("Failed to load message information!")!),
);
}
List<Widget> get _firstItems => [
ListTile(
leading: Icon(Icons.access_time_rounded),
title: Text(tr("Created on")),
title: Text(tr("Created on")!),
subtitle: Text(dateTimeToString(widget.message.date)),
),
ListTile(
@ -67,17 +67,17 @@ class _ConversationMessageStatsRouteState
user: _users.getUser(widget.message.userID),
),
title: Text(_users.getUser(widget.message.userID).fullName),
subtitle: Text(tr("Creator")),
subtitle: Text(tr("Creator")!),
),
];
Widget _buildScreen() => ListView.builder(
itemCount: _firstItems.length + widget.conv.members.length,
itemCount: _firstItems.length + widget.conv.members!.length,
itemBuilder: (c, i) {
final firstItems = _firstItems;
if (i < firstItems.length) return firstItems[i];
final convMember = widget.conv.members[i - firstItems.length];
final convMember = widget.conv.members![i - firstItems.length];
if (convMember.userID == widget.message.userID) return Container();
@ -86,9 +86,9 @@ class _ConversationMessageStatsRouteState
user: _users.getUser(convMember.userID),
),
title: Text(_users.getUser(convMember.userID).fullName),
subtitle: Text(convMember.lastMessageSeen < widget.message.id
? tr("Message not seen yet")
: tr("Message seen")),
subtitle: Text(convMember.lastMessageSeen < widget.message.id!
? tr("Message not seen yet")!
: tr("Message seen")!),
);
},
);

View File

@ -19,8 +19,8 @@ class ConversationRoute extends StatefulWidget {
final int conversationID;
const ConversationRoute({
Key key,
@required this.conversationID,
Key? key,
required this.conversationID,
}) : assert(conversationID != null),
super(key: key);
@ -30,9 +30,9 @@ class ConversationRoute extends StatefulWidget {
class _ConversationRouteState extends SafeState<ConversationRoute> {
final ConversationsHelper _conversationsHelper = ConversationsHelper();
Conversation _conversation;
UsersList _users;
String _conversationName;
Conversation? _conversation;
UsersList? _users;
String? _conversationName;
bool _error = false;
setError(bool err) => setState(() => _error = err);
@ -50,10 +50,10 @@ class _ConversationRouteState extends SafeState<ConversationRoute> {
_conversation = await _conversationsHelper
.getSingle(widget.conversationID, force: true);
_users = await UsersHelper().getList(_conversation.membersID);
_users = await UsersHelper().getList(_conversation!.membersID);
final conversationName =
ConversationsHelper.getConversationName(_conversation, _users);
ConversationsHelper.getConversationName(_conversation!, _users);
if (!this.mounted) return null;
@ -65,7 +65,7 @@ class _ConversationRouteState extends SafeState<ConversationRoute> {
}
void _openSettings() =>
MainController.of(context).openConversationSettingsRoute(_conversation);
MainController.of(context)!.openConversationSettingsRoute(_conversation!);
Widget _buildRouteBody() {
//Handle errors
@ -76,7 +76,7 @@ class _ConversationRouteState extends SafeState<ConversationRoute> {
TextButton(
onPressed: _loadConversation,
child: Text(
tr("Try again").toUpperCase(),
tr("Try again")!.toUpperCase(),
style: TextStyle(
color: Colors.white,
),
@ -101,19 +101,19 @@ class _ConversationRouteState extends SafeState<ConversationRoute> {
? (_conversation == null || _users == null
? null
: ConversationImageWidget(
conversation: _conversation, users: _users))
conversation: _conversation!, users: _users!))
: ComunicBackButton(),
title: Text(
_conversationName == null ? tr("Loading") : _conversationName,
_conversationName == null ? tr("Loading")! : _conversationName!,
),
actions: <Widget>[
// Start call (if possible)
_conversation == null ||
_conversation.callCapabilities == CallCapabilities.NONE
_conversation!.callCapabilities == CallCapabilities.NONE
? Container()
: IconButton(
icon: Icon(Icons.phone),
onPressed: () => MainController.of(context)
onPressed: () => MainController.of(context)!
.startCall(widget.conversationID),
),

View File

@ -15,7 +15,7 @@ class CreateAccountRoute extends StatelessWidget {
return LoginRouteContainer(
child: Scaffold(
appBar: AppBar(
title: Text(tr("Create an account")),
title: Text(tr("Create an account")!),
),
body: _CreateAccountRouteBody(),
),
@ -38,12 +38,12 @@ class __CreateAccountRouteBodyState extends State<_CreateAccountRouteBody> {
await showCupertinoDialog(
context: context,
builder: (c) => CupertinoAlertDialog(
title: Text(tr("Account created")),
title: Text(tr("Account created")!),
content: Text(tr(
"Your account has been successfully created. You can now login to start to use it.")),
"Your account has been successfully created. You can now login to start to use it.")!),
actions: <Widget>[
CupertinoButton(
child: Text(tr("Login")), onPressed: () => Navigator.of(c).pop())
child: Text(tr("Login")!), onPressed: () => Navigator.of(c).pop())
],
),
);

View File

@ -16,16 +16,16 @@ import 'package:flutter/material.dart';
/// Show presence settings route
Future<void> showPresenceSettingsRoute(
BuildContext context, int groupID) async =>
BuildContext context, int? groupID) async =>
await Navigator.push(context,
MaterialPageRoute(builder: (c) => PresenceSettings(groupID: groupID)));
MaterialPageRoute(builder: (c) => PresenceSettings(groupID: groupID!)));
class PresenceSettings extends StatefulWidget {
final int groupID;
const PresenceSettings({
Key key,
@required this.groupID,
Key? key,
required this.groupID,
}) : assert(groupID != null),
super(key: key);
@ -34,7 +34,7 @@ class PresenceSettings extends StatefulWidget {
}
class _PresenceSettingsState extends State<PresenceSettings> {
PresenceSet _currPresences;
late PresenceSet _currPresences;
Future<void> _load() async {
await ForezPresenceHelper.refreshCache(widget.groupID);
@ -46,12 +46,12 @@ class _PresenceSettingsState extends State<PresenceSettings> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(tr("Presence settings")),
title: Text(tr("Presence settings")!),
),
body: AsyncScreenWidget(
onReload: _load,
onBuild: _buildScreen,
errorMessage: tr("Failed to load data!"),
errorMessage: tr("Failed to load data!")!,
),
);
}
@ -61,7 +61,7 @@ class _PresenceSettingsState extends State<PresenceSettings> {
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
tr("Please click on the day you will be in the plain, so that everyone gets informed ! ;)"),
tr("Please click on the day you will be in the plain, so that everyone gets informed ! ;)")!,
textAlign: TextAlign.center,
),
),
@ -85,7 +85,7 @@ class _PresenceSettingsState extends State<PresenceSettings> {
} catch (e, s) {
logError(e, s);
_currPresences.toggleDate(dt, userID());
snack(context, tr("Failed to update information!"));
snack(context, tr("Failed to update information!")!);
}
}
}

View File

@ -18,7 +18,7 @@ class ForgotPasswordRoute extends StatelessWidget {
return LoginRouteContainer(
child: Scaffold(
appBar: AppBar(
title: Text(tr("Password forgotten")),
title: Text(tr("Password forgotten")!),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
@ -45,7 +45,7 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
var _loading = false;
/// Step 1 - check email address
String _emailAddress;
String? _emailAddress;
final _emailController = TextEditingController();
String get _inputEmail => _emailController.text;
@ -54,14 +54,14 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
_inputEmail.isNotEmpty && validateEmail(_inputEmail);
/// Step 2 - Offer options
bool _hasSecurityQuestions;
bool? _hasSecurityQuestions;
var _selectedOption = _SelectedOption.NONE;
void _setLoading(bool loading) => setState(() => _loading = loading);
/// Step 3b - Answer security questions
List<String> _questions;
List<String>? _questions;
var _questionsControllers = <TextEditingController>[];
List<String> get _answers =>
@ -90,7 +90,7 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(tr("Please enter your email address to reset your password:")),
Text(tr("Please enter your email address to reset your password:")!),
TextField(
controller: _emailController,
onChanged: (s) => setState(() {}),
@ -120,9 +120,9 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
_setLoading(true);
// Check if email address exists or not
if (!await AccountHelper.existsMailAccount(_inputEmail)) {
if (!await AccountHelper.existsMailAccount(_inputEmail) ) {
_setLoading(false);
showSimpleSnack(context, tr("Specified email address was not found!"));
showSimpleSnack(context, tr("Specified email address was not found!")!);
return;
}
@ -135,7 +135,7 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
} catch (e, s) {
print("Could not check given email! $e\n$s");
showSimpleSnack(context,
tr("An error occurred while checking your recovery options !"));
tr("An error occurred while checking your recovery options !")!);
_setLoading(false);
}
}
@ -145,19 +145,19 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(tr("Here are your options to reset your account:")),
Text(tr("Here are your options to reset your account:")!),
_Spacer(),
OutlinedButton.icon(
onPressed: _openSendEmailDialog,
icon: Icon(Icons.email),
label: Flexible(
child: Text(tr("Send us an email to ask for help")))),
_Spacer(visible: _hasSecurityQuestions),
_hasSecurityQuestions
child: Text(tr("Send us an email to ask for help")!))),
_Spacer(visible: _hasSecurityQuestions!),
_hasSecurityQuestions!
? OutlinedButton.icon(
onPressed: _loadSecurityQuestions,
icon: Icon(Icons.help_outline),
label: Text(tr("Answer your security questions")),
label: Text(tr("Answer your security questions")!),
)
: Container(),
],
@ -169,7 +169,7 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
context: context,
builder: (c) => AlertDialog(
title: Text("Contact us"),
content: Text(tr("You can reach us at contact@communiquons.org")),
content: Text(tr("You can reach us at contact@communiquons.org")!),
actions: <Widget>[CancelDialogButton()],
));
}
@ -181,11 +181,11 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
_questions = await AccountHelper.getSecurityQuestions(_emailAddress);
_questionsControllers =
List.generate(_questions.length, (i) => TextEditingController());
List.generate(_questions!.length, (i) => TextEditingController());
_selectedOption = _SelectedOption.SECURITY_QUESTIONS;
} catch (e, s) {
print("Could not load security questions! $e\n$s");
showSimpleSnack(context, tr("Could not load your security questions!"));
showSimpleSnack(context, tr("Could not load your security questions!")!);
}
_setLoading(false);
}
@ -196,20 +196,20 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[]
..add(Text(tr("Please answer now your security questions:")))
..add(Text(tr("Please answer now your security questions:")!))
..add(_Spacer())
..addAll(List.generate(_questions.length, _buildSecurityQuestionField))
..addAll(List.generate(_questions!.length, _buildSecurityQuestionField))
..add(_Spacer())
..add(OutlinedButton(
onPressed: _canSubmitAnswers ? _submitSecurityAnswers : null,
child: Text(tr("Submit")),
child: Text(tr("Submit")!),
)),
);
}
Widget _buildSecurityQuestionField(int id) => Column(
children: <Widget>[
Text(_questions[id]),
Text(_questions![id]),
TextField(
controller: _questionsControllers[id],
onChanged: (s) => setState(() {}),
@ -234,20 +234,20 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
} catch (e, s) {
print("Could not submit security answers! $e\n$s");
showSimpleSnack(
context, tr("Could not validate these security answers!"));
context, tr("Could not validate these security answers!")!);
}
_setLoading(false);
}
/// Call this method whenever the user managed to get a password reset token
void _useResetToken(String token) => Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (c) => PasswordResetRoute(token: token)));
void _useResetToken(String? token) => Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (c) => PasswordResetRoute(token: token!)));
}
class _Spacer extends StatelessWidget {
final bool visible;
const _Spacer({Key key, this.visible = true})
const _Spacer({Key? key, this.visible = true})
: assert(visible != null),
super(key: key);

View File

@ -22,7 +22,7 @@ class _FullScreenImageRouteState extends State<FullScreenImageRoute> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(tr("Image")),
title: Text(tr("Image")!),
actions: [
IconButton(
icon: Icon(Icons.launch), onPressed: () => launch(widget.url))

View File

@ -18,18 +18,16 @@ import '../../utils/files_utils.dart';
///
/// Return original image in case of error / if the user did not crop the image
Future<BytesFile> showImageCropper(BuildContext context, BytesFile source,
{CropAspectRatio aspectRatio}) async {
assert(context != null);
assert(source != null);
{CropAspectRatio? aspectRatio}) async {
File file;
File cropped;
File? file;
File? cropped;
try {
file = await generateTemporaryFile();
await file.writeAsBytes(source.bytes);
await file.writeAsBytes(source.bytes!);
File cropped = await ImageCropper().cropImage(
File? cropped = await ImageCropper().cropImage(
sourcePath: file.absolute.path,
compressFormat: ImageCompressFormat.png,
aspectRatio: aspectRatio,
@ -40,12 +38,12 @@ Future<BytesFile> showImageCropper(BuildContext context, BytesFile source,
),
);
if (cropped == null) return null;
if (cropped == null) return source;
return BytesFile("cropped.png", await cropped.readAsBytes());
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to execute image cropper!"));
snack(context, tr("Failed to execute image cropper!")!);
return source;
} finally {
if (file != null && await file.exists()) file.delete();

View File

@ -25,7 +25,7 @@ class _LoginRouteState extends State<LoginRoute> {
return LoginRouteContainer(
child: Scaffold(
appBar: AppBar(
title: Text(tr("Login to Comunic")),
title: Text(tr("Login to Comunic")!),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
@ -44,7 +44,7 @@ class _LoginRouteState extends State<LoginRoute> {
),
ListTile(
leading: Icon(Icons.help),
title: Text(tr("Password forgotten")),
title: Text(tr("Password forgotten")!),
onTap: _openResetPasswordPage,
)
],

View File

@ -50,7 +50,7 @@ abstract class MainController extends State<MainRoute> {
int get numberOfPages => _pagesStack.length;
/// Get current instance of Home controller
static MainController of(BuildContext context) {
static MainController? of(BuildContext context) {
assert(context != null); // A future implementation might need context again
return mainControllerKey.currentState;
}
@ -75,7 +75,7 @@ abstract class MainController extends State<MainRoute> {
/// Pop until main route is reached
void popUntilMainRoute() => Navigator.of(context).popUntil((settings) =>
ModalRoute.of(context).isCurrent || !ModalRoute.of(context).isActive);
ModalRoute.of(context)!.isCurrent || !ModalRoute.of(context)!.isActive);
/// Go to the previous page (use for [WillPop] widget)
@protected
@ -109,13 +109,13 @@ abstract class MainController extends State<MainRoute> {
pushPage(PageInfo(child: UserAccessDeniedScreen(userID: userID)));
/// Open current user page
void openCurrentUserPage() => this.openUserPage(userID());
void openCurrentUserPage() => this.openUserPage(userID()!);
/// Open a specific group page specified by its [groupID]
///
/// [conversationID] is an optional parameter specifying a conversation
/// that should be opened instead of posts thread
void openGroup(int groupID, {int conversationID}) => pushPage(PageInfo(
void openGroup(int groupID, {int? conversationID}) => pushPage(PageInfo(
type: PageType.GROUP_PAGE,
child: GroupPageScreen(
groupID: groupID,
@ -137,10 +137,10 @@ abstract class MainController extends State<MainRoute> {
void openGroupsListPage() => pushPage(PageInfo(child: GroupsListScreen()));
/// Display the list of friends of a user
void openUserFriendsList(int id) {
void openUserFriendsList(int? id) {
if (id != userID())
pushPage(PageInfo(
child: OtherUserFriendsListScreen(userID: id),
child: OtherUserFriendsListScreen(userID: id!),
canShowAsDialog: true,
));
else
@ -156,9 +156,9 @@ abstract class MainController extends State<MainRoute> {
/// Open a conversation in its context (in group page for group conversations)
void openConversation(Conversation conv, {fullScreen: false}) {
if (conv.isGroupConversation)
openGroup(conv.groupID, conversationID: conv.id);
openGroup(conv.groupID!, conversationID: conv.id);
else
openConversationById(conv.id, fullScreen: fullScreen);
openConversationById(conv.id!, fullScreen: fullScreen);
}
/// Open a conversation
@ -173,7 +173,7 @@ abstract class MainController extends State<MainRoute> {
/// Open conversation settings route
void openConversationSettingsRoute(Conversation conv) => pushPage(PageInfo(
child: UpdateConversationRoute(
conversationID: conv.id,
conversationID: conv.id!,
),
canShowAsDialog: true,
hideNavBar: true,
@ -215,7 +215,7 @@ abstract class MainController extends State<MainRoute> {
///
/// If the current route is not the main route, we pop one page
void popPage() {
if (!ModalRoute.of(context).isCurrent)
if (!ModalRoute.of(context)!.isCurrent)
Navigator.of(context).pop();
else
doPopPage();

View File

@ -18,7 +18,7 @@ enum PageType {
class PageInfo {
final PageType type;
final Widget child;
final int id;
final int? id;
final bool hideNavBar;
final bool canShowAsDialog;
@ -27,7 +27,7 @@ class PageInfo {
PageInfo({
this.type = PageType.OTHER_PAGE,
@required this.child,
required this.child,
this.id,
this.hideNavBar = false,
this.canShowAsDialog = false,

View File

@ -10,7 +10,7 @@ import 'package:flutter/material.dart';
/// @author Pierre HUBERT
class SmartphoneMainRoute extends StatefulWidget implements MainRoute {
const SmartphoneMainRoute({Key key}) : super(key: key);
const SmartphoneMainRoute({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _MainRouteState();

View File

@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
const _SideBarSize = 300.0;
class TabletRoute extends StatefulWidget implements MainRoute {
const TabletRoute({Key key}) : super(key: key);
const TabletRoute({Key? key}) : super(key: key);
@override
_TabletRouteState createState() => _TabletRouteState();
@ -37,7 +37,7 @@ class _TabletRouteState extends MainController {
return WillPopScope(
onWillPop: willPop,
child: Scaffold(
appBar: _buildAppBar(),
appBar: _buildAppBar() as PreferredSizeWidget?,
body: _buildBody(),
),
);
@ -105,14 +105,14 @@ class _TabletRouteState extends MainController {
}
@override
void openConversationById(int convID, {fullScreen = false}) {
void openConversationById(int? convID, {fullScreen = false}) {
if (!fullScreen) {
popUntilMainRoute();
_conversationsKey.currentState.openConversations(convID);
_conversationsKey.currentState!.openConversations(convID);
} else
super.openConversationById(convID, fullScreen: fullScreen);
super.openConversationById(convID!, fullScreen: fullScreen);
}
@override
void startCall(int convID) => _callsKey.currentState.openCall(convID);
void startCall(int convID) => _callsKey.currentState!.openCall(convID);
}

View File

@ -17,8 +17,8 @@ class PasswordResetRoute extends StatelessWidget {
final String token;
const PasswordResetRoute({
Key key,
@required this.token,
Key? key,
required this.token,
}) : assert(token != null),
super(key: key);
@ -27,7 +27,7 @@ class PasswordResetRoute extends StatelessWidget {
return LoginRouteContainer(
child: Scaffold(
appBar: AppBar(
title: Text(tr("Change your password")),
title: Text(tr("Change your password")!),
),
body: _PasswordResetBody(token: token),
),
@ -38,7 +38,7 @@ class PasswordResetRoute extends StatelessWidget {
class _PasswordResetBody extends StatefulWidget {
final String token;
const _PasswordResetBody({Key key, @required this.token})
const _PasswordResetBody({Key? key, required this.token})
: assert(token != null),
super(key: key);
@ -52,7 +52,7 @@ class __PasswordResetBodyState extends SafeState<_PasswordResetBody> {
final _key = GlobalKey<AsyncScreenWidgetState>();
var _status = _Status.BEFORE_CHANGE;
ResCheckPasswordToken _tokenInfo;
late ResCheckPasswordToken _tokenInfo;
void _setStatus(_Status s) => setState(() => _status = s);
@ -68,7 +68,7 @@ class __PasswordResetBodyState extends SafeState<_PasswordResetBody> {
onReload: _validateToken, // The first time, we validate the token
onBuild: _buildBody,
errorMessage: tr(
"Could not validate your password reset token! Maybe it has expired now..."),
"Could not validate your password reset token! Maybe it has expired now...")!,
);
}
@ -79,10 +79,10 @@ class __PasswordResetBodyState extends SafeState<_PasswordResetBody> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(tr("You can choose a new password.")),
Text(tr("You can choose a new password.")!),
OutlinedButton(
onPressed: _changePassword,
child: Text(tr("Choose a new password")),
child: Text(tr("Choose a new password")!),
)
],
));
@ -97,12 +97,12 @@ class __PasswordResetBodyState extends SafeState<_PasswordResetBody> {
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
tr("Congratulations! Your password has now been successfully changed!"),
tr("Congratulations! Your password has now been successfully changed!")!,
textAlign: TextAlign.center,
),
OutlinedButton(
onPressed: _quitScreen,
child: Text(tr("Login")),
child: Text(tr("Login")!),
)
],
));
@ -130,10 +130,10 @@ class __PasswordResetBodyState extends SafeState<_PasswordResetBody> {
_setStatus(_Status.AFTER_CHANGE);
} catch (e, s) {
print("Could not change user password! $e\n$s");
showSimpleSnack(context, tr("Could not change your password!"));
showSimpleSnack(context, tr("Could not change your password!")!);
// We start everything again
_key.currentState.refresh();
_key.currentState!.refresh();
}
}

View File

@ -52,9 +52,9 @@ class _PushNotificationsConfigurationRouteState
Spacer(),
OutlinedButton(
onPressed: _key?.currentState?.canSubmit ?? false
? _key.currentState.submit
? _key.currentState!.submit
: null,
child: Text(tr("Configure").toUpperCase()),
child: Text(tr("Configure")!.toUpperCase()),
style: OutlinedButton.styleFrom(primary: Colors.white)),
Spacer(),
],
@ -69,9 +69,9 @@ class PushNotificationsConfigurationWidget extends StatefulWidget {
final Function() onChanged;
const PushNotificationsConfigurationWidget({
Key key,
@required this.onConfigured,
@required this.onChanged,
Key? key,
required this.onConfigured,
required this.onChanged,
}) : super(key: key);
@override
@ -81,7 +81,7 @@ class PushNotificationsConfigurationWidget extends StatefulWidget {
class PushNotificationsConfigurationWidgetState
extends State<PushNotificationsConfigurationWidget> {
PushNotificationsStatus currStatus;
PushNotificationsStatus? currStatus;
bool get canSubmit =>
(currStatus ?? PushNotificationsStatus.UNDEFINED) !=
@ -92,7 +92,7 @@ class PushNotificationsConfigurationWidgetState
currStatus = await PushNotificationsHelper.getLocalStatus();
if (currStatus == PushNotificationsStatus.UNDEFINED &&
srvConfig.notificationsPolicy.hasFirebase)
srvConfig!.notificationsPolicy.hasFirebase)
currStatus = PushNotificationsStatus.FIREBASE;
widget.onChanged();
@ -103,7 +103,7 @@ class PushNotificationsConfigurationWidgetState
return AsyncScreenWidget(
onReload: _refresh,
onBuild: _buildForm,
errorMessage: tr("Failed to load push notifications settings!"),
errorMessage: tr("Failed to load push notifications settings!")!,
);
}
@ -114,16 +114,16 @@ class PushNotificationsConfigurationWidgetState
Text(
tr("%app% can send push notifications to your device.", args: {
"app": config().appName,
}),
})!,
textAlign: TextAlign.center,
),
SizedBox(height: 10),
_NotificationOption(
title: tr("Use Google services (recommended)"),
title: tr("Use Google services (recommended)")!,
description: tr("Save your battery life."),
option: PushNotificationsStatus.FIREBASE,
current: currStatus,
available: srvConfig.notificationsPolicy.hasFirebase,
current: currStatus!,
available: srvConfig!.notificationsPolicy.hasFirebase,
onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
@ -131,13 +131,13 @@ class PushNotificationsConfigurationWidgetState
),
SizedBox(height: 5),
_NotificationOption(
title: tr("Use independent notifications service"),
title: tr("Use independent notifications service")!,
description: tr(
"Protect more your privacy, but drains battery and is less reliable."),
option: PushNotificationsStatus.INDEPENDENT,
current: currStatus,
current: currStatus!,
available:
srvConfig.notificationsPolicy.hasIndependent && isAndroid,
srvConfig!.notificationsPolicy.hasIndependent && isAndroid,
onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
@ -145,9 +145,9 @@ class PushNotificationsConfigurationWidgetState
),
SizedBox(height: 5),
_NotificationOption(
title: tr("Do not send notification"),
title: tr("Do not send notification")!,
option: PushNotificationsStatus.DISABLED,
current: currStatus,
current: currStatus!,
available: true,
onChanged: (s) {
setState(() => currStatus = s);
@ -181,20 +181,20 @@ class PushNotificationsConfigurationWidgetState
class _NotificationOption extends StatelessWidget {
final String title;
final String description;
final String? description;
final PushNotificationsStatus option;
final PushNotificationsStatus current;
final bool available;
final Function(PushNotificationsStatus) onChanged;
final Function(PushNotificationsStatus?) onChanged;
const _NotificationOption({
Key key,
@required this.title,
Key? key,
required this.title,
this.description,
@required this.option,
@required this.current,
@required this.available,
@required this.onChanged,
required this.option,
required this.current,
required this.available,
required this.onChanged,
}) : assert(title != null),
assert(option != null),
assert(current != null),
@ -219,7 +219,7 @@ class _NotificationOption extends StatelessWidget {
title: Text(title, style: TextStyle(color: Colors.white)),
subtitle: description == null
? null
: Text(description, style: TextStyle(color: Colors.white)),
: Text(description!, style: TextStyle(color: Colors.white)),
contentPadding: EdgeInsets.all(0),
onTap: () => onChanged(option),
),

View File

@ -24,16 +24,16 @@ class AboutApplicationSettings extends StatelessWidget {
tiles: [
SettingsTile(
title: tr("Privacy policy"),
onPressed: (c) => launch(srvConfig.privacyPolicyURL),
onPressed: (c) => launch(srvConfig!.privacyPolicyURL),
),
SettingsTile(
title: tr("Terms of Use"),
onPressed: (c) => launch(srvConfig.termsURL),
onPressed: (c) => launch(srvConfig!.termsURL),
),
SettingsTile(
title: tr("Contact us"),
subtitle: srvConfig.contactEmail,
trailing: CopyIcon(srvConfig.contactEmail),
subtitle: srvConfig!.contactEmail,
trailing: CopyIcon(srvConfig!.contactEmail),
),
SettingsTile(
title: tr("About this application"),

View File

@ -30,7 +30,7 @@ class AccountImageSettingsScreen extends StatefulWidget {
class _AccountImageSettingsScreenState
extends State<AccountImageSettingsScreen> {
AccountImageSettings _settings;
late AccountImageSettings _settings;
final _key = GlobalKey<AsyncScreenWidgetState>();
@ -49,7 +49,7 @@ class _AccountImageSettingsScreenState
onReload: () async =>
_settings = await SettingsHelper.getAccountImageSettings(),
onBuild: () => _buildLayout(),
errorMessage: tr("Could not get account image settings!"),
errorMessage: tr("Could not get account image settings!")!,
);
}
@ -96,19 +96,19 @@ class _AccountImageSettingsScreenState
[
MultiChoiceEntry(
id: AccountImageVisibilityLevels.EVERYONE,
title: tr("Everyone"),
title: tr("Everyone")!,
subtitle: tr(
"Your account image is visible by everyone, including users external to Comunic."),
),
MultiChoiceEntry(
id: AccountImageVisibilityLevels.COMUNIC_USERS,
title: tr("Connected users"),
title: tr("Connected users")!,
subtitle: tr(
"Your account image is visible only to connected Comunic users."),
),
MultiChoiceEntry(
id: AccountImageVisibilityLevels.FRIENDS_ONLY,
title: tr("My friends"),
title: tr("My friends")!,
subtitle: tr("Your account image is visible only by your friends."),
),
];
@ -139,14 +139,14 @@ class _AccountImageSettingsScreenState
// Change account image visibility
MultiChoicesSettingsTile(
title: tr("Account image visibility"),
title: tr("Account image visibility")!,
choices: _visibilityLevels,
currentValue: _settings.visibility,
onChanged: (newLevel) async {
onChanged: (dynamic newLevel) async {
if (!await SettingsHelper.setAccountImageVisibilityLevel(newLevel))
showSimpleSnack(context,
tr("Could not update account image visibility level!"));
_key.currentState.refresh();
tr("Could not update account image visibility level!")!);
_key.currentState!.refresh();
}),
// Delete account image
@ -160,7 +160,7 @@ class _AccountImageSettingsScreenState
/// Upload a new account image
void _uploadAccountImage() async {
await uploadNewAccountImage(context);
_key.currentState.refresh();
_key.currentState!.refresh();
}
/// Generate a random account image
@ -170,11 +170,11 @@ class _AccountImageSettingsScreenState
if (!await SettingsHelper.uploadAccountImageFromMemory(bytes)) {
showSimpleSnack(
context, tr("Could not upload your generated account image!"));
context, tr("Could not upload your generated account image!")!);
return;
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
/// Delete user account image
@ -185,11 +185,11 @@ class _AccountImageSettingsScreenState
return;
if (!await SettingsHelper.deleteAccountImage()) {
showSimpleSnack(context, tr("Could not delete user account image!"));
showSimpleSnack(context, tr("Could not delete user account image!")!);
return;
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
}
@ -203,6 +203,6 @@ Future<void> uploadNewAccountImage(BuildContext context) async {
await SettingsHelper.uploadAccountImage(image);
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to upload new account image!"));
snack(context, tr("Failed to upload new account image!")!);
}
}

View File

@ -25,9 +25,9 @@ class AccountPrivacySettings extends StatefulWidget {
class _AccountPrivacySettingsState extends State<AccountPrivacySettings> {
final _key = GlobalKey<AsyncScreenWidgetState>();
ServerConfig _serverConfig;
DataConservationPolicySettings _userSettings;
String _cachedPassword;
ServerConfig? _serverConfig;
late DataConservationPolicySettings _userSettings;
String? _cachedPassword;
Future<void> _loadSettings() async {
_serverConfig = ServerConfigurationHelper.config;
@ -59,68 +59,68 @@ class _AccountPrivacySettingsState extends State<AccountPrivacySettings> {
)
])
]),
errorMessage: tr("Failed to load privacy settings!"),
errorMessage: tr("Failed to load privacy settings!")!,
);
}
List<SettingsTile> get _dataConservationPolicyTiles => [
DataConservationPolicyTile(
value: _userSettings.notificationLifetime,
title: tr("Automatically delete unread notifications after"),
title: tr("Automatically delete unread notifications after")!,
onChange: (val) {
_userSettings.notificationLifetime = val;
_updateDataConservationPolicy();
},
minValue:
_serverConfig.dataConservationPolicy.minNotificationLifetime,
_serverConfig!.dataConservationPolicy.minNotificationLifetime,
),
DataConservationPolicyTile(
value: _userSettings.commentsLifetime,
title: tr("Automatically delete your comments after"),
title: tr("Automatically delete your comments after")!,
onChange: (val) {
_userSettings.commentsLifetime = val;
_updateDataConservationPolicy();
},
minValue: _serverConfig.dataConservationPolicy.minCommentsLifetime,
minValue: _serverConfig!.dataConservationPolicy.minCommentsLifetime,
),
DataConservationPolicyTile(
value: _userSettings.postsLifetime,
title: tr("Automatically delete your posts after"),
title: tr("Automatically delete your posts after")!,
onChange: (val) {
_userSettings.postsLifetime = val;
_updateDataConservationPolicy();
},
minValue: _serverConfig.dataConservationPolicy.minPostsLifetime,
minValue: _serverConfig!.dataConservationPolicy.minPostsLifetime,
),
DataConservationPolicyTile(
value: _userSettings.conversationMessagesLifetime,
title: tr("Automatically delete your conversation messages after"),
title: tr("Automatically delete your conversation messages after")!,
onChange: (val) {
_userSettings.conversationMessagesLifetime = val;
_updateDataConservationPolicy();
},
minValue: _serverConfig
minValue: _serverConfig!
.dataConservationPolicy.minConversationMessagesLifetime,
),
DataConservationPolicyTile(
value: _userSettings.likesLifetime,
title: tr("Automatically delete your likes after"),
title: tr("Automatically delete your likes after")!,
onChange: (val) {
_userSettings.likesLifetime = val;
_updateDataConservationPolicy();
},
minValue: _serverConfig.dataConservationPolicy.minLikesLifetime,
minValue: _serverConfig!.dataConservationPolicy.minLikesLifetime,
),
DataConservationPolicyTile(
value: _userSettings.inactiveAccountLifeTime,
title: tr(
"Automatically delete your account if you have been inactive for"),
"Automatically delete your account if you have been inactive for")!,
onChange: (val) {
_userSettings.inactiveAccountLifeTime = val;
_updateDataConservationPolicy();
},
minValue:
_serverConfig.dataConservationPolicy.minInactiveAccountLifetime,
_serverConfig!.dataConservationPolicy.minInactiveAccountLifetime,
),
];
@ -132,11 +132,11 @@ class _AccountPrivacySettingsState extends State<AccountPrivacySettings> {
await SettingsHelper.setDataConservationPolicy(
_cachedPassword, _userSettings);
_key.currentState.refresh();
_key.currentState!.refresh();
} catch (e, s) {
print("Could not update data conservation policy! $e\n$s");
showSimpleSnack(
context, tr("Failed to update data conservation policy!"));
context, tr("Failed to update data conservation policy!")!);
}
}
@ -164,22 +164,22 @@ class _AccountPrivacySettingsState extends State<AccountPrivacySettings> {
await AccountHelper.deleteAccount(password);
} catch (e, stack) {
print("Could not delete user account! $e\n$stack");
showSimpleSnack(context, tr("Could not delete your account!"));
showSimpleSnack(context, tr("Could not delete your account!")!);
}
}
}
class DataConservationPolicyTile extends SettingsTile {
final int value;
final int? value;
final String title;
final Function(int) onChange;
final int minValue;
DataConservationPolicyTile({
@required this.value,
@required this.title,
@required this.onChange,
@required this.minValue,
required this.value,
required this.title,
required this.onChange,
required this.minValue,
}) : assert(title != null),
assert(onChange != null),
assert(minValue != null);
@ -203,59 +203,59 @@ class DataConservationPolicyTile extends SettingsTile {
int get _roundValue {
if (this.value == null) return 0;
return _choices.firstWhere((element) => element.id >= this.value).id;
return _choices.firstWhere((element) => element.id >= this.value!).id;
}
List<MultiChoiceEntry<int>> get _choices => [
MultiChoiceEntry(id: 0, title: tr("Never"), hidden: false),
MultiChoiceEntry(id: 0, title: tr("Never")!, hidden: false),
MultiChoiceEntry(
id: _day * 7,
title: tr("7 days"),
title: tr("7 days")!,
hidden: _day * 7 < minValue,
),
MultiChoiceEntry(
id: _day * 15,
title: tr("15 days"),
title: tr("15 days")!,
hidden: _day * 15 < minValue,
),
MultiChoiceEntry(
id: _month,
title: tr("1 month"),
title: tr("1 month")!,
hidden: _month < minValue,
),
MultiChoiceEntry(
id: _month * 3,
title: tr("3 months"),
title: tr("3 months")!,
hidden: _month * 3 < minValue,
),
MultiChoiceEntry(
id: _month * 6,
title: tr("6 months"),
title: tr("6 months")!,
hidden: _month * 6 < minValue,
),
MultiChoiceEntry(
id: _year,
title: tr("1 year"),
title: tr("1 year")!,
hidden: _year < minValue,
),
MultiChoiceEntry(
id: _year * 2,
title: tr("2 years"),
title: tr("2 years")!,
hidden: _year * 5 < minValue,
),
MultiChoiceEntry(
id: _year * 5,
title: tr("5 years"),
title: tr("5 years")!,
hidden: _year * 5 < minValue,
),
MultiChoiceEntry(
id: _year * 10,
title: tr("10 years"),
title: tr("10 years")!,
hidden: _year * 10 < minValue,
),
MultiChoiceEntry(
id: _year * 50,
title: tr("50 years"),
title: tr("50 years")!,
hidden: _year * 50 < minValue,
),
];
@ -265,18 +265,18 @@ class _LastChanceDeleteAccountDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoAlertDialog(
title: Text(tr("Delete your account")),
title: Text(tr("Delete your account")!),
content: Text(tr(
"Let us ask you one last time. Do you really want to delete your account? If you decide to do so, your data will be permanently removed from our servers, so we will not be able to recover your account. If you decide to proceed, the deletion process will start immediatly and you will automatically get disconnected from your account.")),
"Let us ask you one last time. Do you really want to delete your account? If you decide to do so, your data will be permanently removed from our servers, so we will not be able to recover your account. If you decide to proceed, the deletion process will start immediatly and you will automatically get disconnected from your account.")!),
actions: <Widget>[
CupertinoDialogAction(
isDefaultAction: true,
child: Text(tr("Cancel")),
child: Text(tr("Cancel")!),
onPressed: () => Navigator.of(context).pop(false),
),
CupertinoDialogAction(
isDestructiveAction: true,
child: Text(tr("Confirm")),
child: Text(tr("Confirm")!),
onPressed: () => Navigator.of(context).pop(true),
),
],

View File

@ -86,10 +86,10 @@ class _AccountSecuritySettingsScreenState
await SettingsHelper.changePassword(currPassword, newPassword);
showSimpleSnack(
context, tr("Your password has been successfully changed!"));
context, tr("Your password has been successfully changed!")!);
} catch (e, stack) {
print("Could not update current user password! $e\n$stack");
showSimpleSnack(context, tr("Could not update password!"));
showSimpleSnack(context, tr("Could not update password!")!);
}
}
@ -111,10 +111,10 @@ class _AccountSecuritySettingsScreenState
await SettingsHelper.setSecuritySettings(password, newSettings);
showSimpleSnack(context,
tr("You security questions have been successfully updated!"));
tr("You security questions have been successfully updated!")!);
} catch (e, stack) {
print("Could not update security questions!$e\n$stack");
showSimpleSnack(context, tr("Could not update security questions!"));
showSimpleSnack(context, tr("Could not update security questions!")!);
}
}
@ -131,7 +131,7 @@ class _AccountSecuritySettingsScreenState
} catch (e, stack) {
print("Could not disconnect user on all devices! $e\n$stack");
showSimpleSnack(
context, tr("Could not disconnect you from all your devices!"));
context, tr("Could not disconnect you from all your devices!")!);
}
}
}
@ -139,7 +139,7 @@ class _AccountSecuritySettingsScreenState
class _SecurityQuestionsDialog extends StatefulWidget {
final SecuritySettings settings;
const _SecurityQuestionsDialog({Key key, @required this.settings})
const _SecurityQuestionsDialog({Key? key, required this.settings})
: assert(settings != null),
super(key: key);
@ -149,10 +149,10 @@ class _SecurityQuestionsDialog extends StatefulWidget {
}
class __SecurityQuestionsDialogState extends State<_SecurityQuestionsDialog> {
TextEditingController _controllerQuestion1;
TextEditingController _controllerAnswer1;
TextEditingController _controllerQuestion2;
TextEditingController _controllerAnswer2;
late TextEditingController _controllerQuestion1;
late TextEditingController _controllerAnswer1;
late TextEditingController _controllerQuestion2;
late TextEditingController _controllerAnswer2;
SecuritySettings get _newSettings => SecuritySettings(
securityQuestion1: _controllerQuestion1.text,
@ -177,16 +177,16 @@ class __SecurityQuestionsDialogState extends State<_SecurityQuestionsDialog> {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(tr("Update security questions")),
title: Text(tr("Update security questions")!),
content: AutoSizeDialogContentWidget(child: _buildContent()),
actions: <Widget>[
MaterialButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(tr("Cancel").toUpperCase()),
child: Text(tr("Cancel")!.toUpperCase()),
),
MaterialButton(
onPressed: () => Navigator.of(context).pop(_newSettings),
child: Text(tr("Update").toUpperCase()),
child: Text(tr("Update")!.toUpperCase()),
)
],
);
@ -196,7 +196,7 @@ class __SecurityQuestionsDialogState extends State<_SecurityQuestionsDialog> {
return Column(
children: <Widget>[
Text(tr(
"Note: Your two questions and answers MUST be completed in order to be able to recover your account using your security questions!")),
"Note: Your two questions and answers MUST be completed in order to be able to recover your account using your security questions!")!),
_buildTextField(
controller: _controllerQuestion1, label: tr("Question 1")),
_buildTextField(controller: _controllerAnswer1, label: tr("Answer 1")),
@ -208,8 +208,8 @@ class __SecurityQuestionsDialogState extends State<_SecurityQuestionsDialog> {
}
Widget _buildTextField({
@required TextEditingController controller,
@required String label,
required TextEditingController controller,
required String? label,
}) {
return TextField(
controller: controller,

View File

@ -27,10 +27,10 @@ class _SettingsSection {
final Widget Function() onBuild;
const _SettingsSection({
@required this.title,
@required this.subtitle,
@required this.icon,
@required this.onBuild,
required this.title,
required this.subtitle,
required this.icon,
required this.onBuild,
}) : assert(title != null),
assert(subtitle != null),
assert(icon != null),
@ -42,14 +42,14 @@ class AccountSettingsRoute extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(tr("Settings")),
title: Text(tr("Settings")!),
actions: [
PopupMenuButton<_MainMenuActions>(
onSelected: (v) => _doPopupMenuAction(context, v),
itemBuilder: (c) => [
PopupMenuItem(
value: _MainMenuActions.SHOW_TOUR,
child: Text(tr("See the tour again")),
child: Text(tr("See the tour again")!),
),
]),
],
@ -74,7 +74,7 @@ class _AccountSettingsBody extends StatefulWidget {
}
class __AccountSettingsBodyState extends State<_AccountSettingsBody> {
_SettingsSection _currentSection;
late _SettingsSection _currentSection;
@override
void initState() {
@ -87,64 +87,64 @@ class __AccountSettingsBodyState extends State<_AccountSettingsBody> {
/// The list of settings sections
List<_SettingsSection> get _sections => [
_SettingsSection(
title: tr("General settings"),
subtitle: tr("Configure the main settings of your account"),
title: tr("General settings")!,
subtitle: tr("Configure the main settings of your account")!,
icon: Icons.settings,
onBuild: () => GeneralAccountSettingsScreen(),
),
// Emoticons
_SettingsSection(
title: tr("Custom emojis"),
subtitle: tr("Set your own emoticon shorcuts"),
title: tr("Custom emojis")!,
subtitle: tr("Set your own emoticon shorcuts")!,
icon: Icons.insert_emoticon,
onBuild: () => CustomEmojisAccountSettings(),
),
// Account image
_SettingsSection(
title: tr("Account image"),
subtitle: tr("Customize your account image"),
title: tr("Account image")!,
subtitle: tr("Customize your account image")!,
icon: Icons.account_circle,
onBuild: () => AccountImageSettingsScreen(),
),
// Notifications settings
_SettingsSection(
title: tr("Notifications"),
subtitle: tr("Choose the notifications you receive on your phone"),
title: tr("Notifications")!,
subtitle: tr("Choose the notifications you receive on your phone")!,
icon: Icons.notifications,
onBuild: () => NotificationsSettingsScreen(),
),
// Security settings
_SettingsSection(
title: tr("Security"),
subtitle: tr("Manage security options of your account"),
title: tr("Security")!,
subtitle: tr("Manage security options of your account")!,
icon: Icons.lock,
onBuild: () => AccountSecuritySettingsScreen(),
),
// Privacy settings
_SettingsSection(
title: tr("Privacy"),
subtitle: tr("Here you can make actions to protect your privacy"),
title: tr("Privacy")!,
subtitle: tr("Here you can make actions to protect your privacy")!,
icon: Icons.security,
onBuild: () => AccountPrivacySettings(),
),
// Application settings
_SettingsSection(
title: tr("Application settings"),
subtitle: tr("Manage local application settings"),
title: tr("Application settings")!,
subtitle: tr("Manage local application settings")!,
icon: Icons.smartphone,
onBuild: () => ApplicationSettings(),
),
// About settings
_SettingsSection(
title: tr("About this application"),
subtitle: tr("Learn more about us"),
title: tr("About this application")!,
subtitle: tr("Learn more about us")!,
icon: Icons.info,
onBuild: () => AboutApplicationSettings(),
),

View File

@ -17,7 +17,7 @@ class ApplicationSettings extends StatefulWidget {
}
class _ApplicationSettingsState extends State<ApplicationSettings> {
PreferencesHelper _preferencesHelper;
PreferencesHelper? _preferencesHelper;
Future<void> _refresh() async {
_preferencesHelper = await PreferencesHelper.getInstance();
@ -27,7 +27,7 @@ class _ApplicationSettingsState extends State<ApplicationSettings> {
Widget build(BuildContext context) => AsyncScreenWidget(
onReload: _refresh,
onBuild: _buildSections,
errorMessage: tr("Could not load settings!"));
errorMessage: tr("Could not load settings!")!);
Widget _buildSections() {
return SettingsList(
@ -89,17 +89,17 @@ class _ApplicationSettingsState extends State<ApplicationSettings> {
class _PreferencesSettingsTile extends SettingsTile {
final PreferencesKeyList preferencesKey;
final String title;
final String subtitle;
final String? title;
final String? subtitle;
final Function onChange;
final PreferencesHelper helper;
final PreferencesHelper? helper;
_PreferencesSettingsTile({
@required this.preferencesKey,
@required this.title,
@required this.subtitle,
@required this.onChange,
@required this.helper,
required this.preferencesKey,
required this.title,
required this.subtitle,
required this.onChange,
required this.helper,
});
@override
@ -108,14 +108,14 @@ class _PreferencesSettingsTile extends SettingsTile {
title: title,
subtitle: subtitle,
onToggle: _doChange,
switchValue: helper.getBool(preferencesKey),
switchValue: helper!.getBool(preferencesKey),
titleMaxLines: 2,
subtitleMaxLines: 4,
);
}
void _doChange(bool value) async {
await helper.setBool(preferencesKey, value);
await helper!.setBool(preferencesKey, value);
onChange();
}
}

View File

@ -28,7 +28,7 @@ class CustomEmojisAccountSettings extends StatefulWidget {
class _CustomEmojisAccountSettingsState
extends State<CustomEmojisAccountSettings> {
User _user;
late User _user;
final _key = GlobalKey<AsyncScreenWidgetState>();
@ -45,7 +45,7 @@ class _CustomEmojisAccountSettingsState
key: _key,
onReload: _reload,
onBuild: _buildSettings,
errorMessage: tr("Could not refresh user information!"),
errorMessage: tr("Could not refresh user information!")!,
showOldDataWhileUpdating: true,
);
}
@ -63,8 +63,8 @@ class _CustomEmojisAccountSettingsState
return ListView(
children: _user.customEmojies
.map((u) => ListTile(
leading: NetworkImageWidget(url: u.url, width: 50),
title: Text(u.shortcut),
leading: NetworkImageWidget(url: u.url!, width: 50),
title: Text(u.shortcut!),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _deleteEmoji(u)),
@ -98,10 +98,10 @@ class _CustomEmojisAccountSettingsState
await SettingsHelper.uploadNewCustomEmoji(newEmoji);
} catch (e, stack) {
print("Could not add a new emoji: $e\n$stack");
showSimpleSnack(context, tr("Could not upload emoji!"));
showSimpleSnack(context, tr("Could not upload emoji!")!);
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
/// Ask for confirmation before deleting permanently an emoji
@ -115,10 +115,10 @@ class _CustomEmojisAccountSettingsState
await SettingsHelper.deleteCustomEmoji(u.id);
} catch (e, stack) {
print("Could not delete custom emoji! $e\n$stack");
showSimpleSnack(context, tr("Could not delete custom emoji!"));
showSimpleSnack(context, tr("Could not delete custom emoji!")!);
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
}
@ -127,8 +127,8 @@ class _NewCustomEmojiDialog extends StatefulWidget {
final CustomEmojiesList currentList;
const _NewCustomEmojiDialog({
Key key,
@required this.currentList,
Key? key,
required this.currentList,
}) : assert(currentList != null),
super(key: key);
@ -138,7 +138,7 @@ class _NewCustomEmojiDialog extends StatefulWidget {
class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
final _controller = TextEditingController();
BytesFile _file;
BytesFile? _file;
bool get _hasImage => _file != null;
@ -151,12 +151,12 @@ class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
bool get _valid => _hasImage && _shortcutValid;
NewEmoji get _emoji => NewEmoji(shortcut: _shortcut, image: _file);
NewEmoji get _emoji => NewEmoji(shortcut: _shortcut, image: _file!);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(tr("Add new emoji")),
title: Text(tr("Add new emoji")!),
content: ConstrainedBox(
constraints:
BoxConstraints(maxHeight: MediaQuery.of(context).size.height - 50),
@ -167,11 +167,11 @@ class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
actions: <Widget>[
MaterialButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(tr("Cancel").toUpperCase()),
child: Text(tr("Cancel")!.toUpperCase()),
),
MaterialButton(
onPressed: _valid ? () => Navigator.of(context).pop(_emoji) : null,
child: Text(tr("Add").toUpperCase()),
child: Text(tr("Add")!.toUpperCase()),
),
],
);
@ -194,7 +194,7 @@ class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
),
MaterialButton(
onPressed: _pickImage,
child: Text(_hasImage ? tr("Replace image") : tr("Add image")),
child: Text(_hasImage ? tr("Replace image")! : tr("Add image")!),
)
],
);
@ -211,7 +211,7 @@ class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
});
} catch (e, stack) {
print("Could not pick an image! $e\n$stack");
snack(context, tr("Failed to pick an image!"));
snack(context, tr("Failed to pick an image!")!);
}
}
}

View File

@ -28,7 +28,7 @@ class GeneralAccountSettingsScreen extends StatefulWidget {
class _GeneralAccountSettingsScreenState
extends State<GeneralAccountSettingsScreen> {
GeneralSettings _settings;
late GeneralSettings _settings;
final _key = GlobalKey<AsyncScreenWidgetState>();
@ -47,7 +47,7 @@ class _GeneralAccountSettingsScreenState
onReload: () async =>
_settings = await SettingsHelper.getGeneralSettings(),
onBuild: _buildSettings,
errorMessage: tr("Could not load general settings!"),
errorMessage: tr("Could not load general settings!")!,
showOldDataWhileUpdating: true,
);
}
@ -81,28 +81,28 @@ class _GeneralAccountSettingsScreenState
// First name
TextEditSettingsTile(
title: tr("First name"),
title: tr("First name")!,
currValue: _settings.firstName,
onChanged: (s) {
_settings.firstName = s;
_updateSettings();
},
maxLength: srvConfig.accountInformationPolicy.maxFirstNameLength,
maxLength: srvConfig!.accountInformationPolicy.maxFirstNameLength,
checkInput: (s) =>
s.length >= srvConfig.accountInformationPolicy.minFirstNameLength,
s.length >= srvConfig!.accountInformationPolicy.minFirstNameLength,
),
// Last name
TextEditSettingsTile(
title: tr("Last name"),
title: tr("Last name")!,
currValue: _settings.lastName,
onChanged: (s) {
_settings.lastName = s;
_updateSettings();
},
maxLength: srvConfig.accountInformationPolicy.maxLastNameLength,
maxLength: srvConfig!.accountInformationPolicy.maxLastNameLength,
checkInput: (s) =>
s.length >= srvConfig.accountInformationPolicy.minLastNameLength,
s.length >= srvConfig!.accountInformationPolicy.minLastNameLength,
),
// Emails settings
@ -121,15 +121,15 @@ class _GeneralAccountSettingsScreenState
List<MultiChoiceEntry> get _visibilityChoices => [
MultiChoiceEntry(
id: UserPageVisibility.PRIVATE,
title: tr("Private"),
title: tr("Private")!,
subtitle: tr("Private, accessible only to your friends")),
MultiChoiceEntry(
id: UserPageVisibility.PUBLIC,
title: tr("Public"),
title: tr("Public")!,
subtitle: tr("Public, accessible to all Comunic members")),
MultiChoiceEntry(
id: UserPageVisibility.OPEN,
title: tr("Open"),
title: tr("Open")!,
subtitle:
tr("Accessible to everyone, including non-Comunic users")),
];
@ -139,10 +139,10 @@ class _GeneralAccountSettingsScreenState
return [
// Page visibility
MultiChoicesSettingsTile(
title: tr("Page visibility"),
title: tr("Page visibility")!,
choices: _visibilityChoices,
currentValue: _settings.pageVisibility,
onChanged: (v) {
onChanged: (dynamic v) {
_settings.pageVisibility = v;
_updateSettings();
}),
@ -191,7 +191,7 @@ class _GeneralAccountSettingsScreenState
// Personal website
TextEditSettingsTile(
title: tr("Personal website URL (optional)"),
title: tr("Personal website URL (optional)")!,
currValue: _settings.personalWebsite,
onChanged: (v) {
_settings.personalWebsite = v;
@ -203,19 +203,19 @@ class _GeneralAccountSettingsScreenState
// Location
TextEditSettingsTile(
title: tr("Location (optional)"),
title: tr("Location (optional)")!,
currValue: _settings.location ?? "",
onChanged: (v) {
_settings.location = v;
_updateSettings();
},
maxLength: srvConfig.accountInformationPolicy.maxLocationLength,
maxLength: srvConfig!.accountInformationPolicy.maxLocationLength,
allowEmptyValues: true,
),
// Public notes
TextEditSettingsTile(
title: tr("Public note (optional)"),
title: tr("Public note (optional)")!,
currValue: _settings.publicNote,
onChanged: (v) {
_settings.publicNote = v;
@ -235,7 +235,7 @@ class _GeneralAccountSettingsScreenState
context: context,
initialDirectory: _settings.virtualDirectory,
type: VirtualDirectoryTargetType.USER,
id: userID());
id: userID()!);
if (dir == null) return;
@ -252,8 +252,8 @@ class _GeneralAccountSettingsScreenState
await SettingsHelper.updateGeneralSettings(_settings);
} catch (e, stack) {
print("Error while updating settings! $e/n$stack");
showSimpleSnack(context, tr("Could not update general settings!"));
showSimpleSnack(context, tr("Could not update general settings!")!);
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
}

View File

@ -24,8 +24,8 @@ class _NotificationsSettingsScreenState
extends State<NotificationsSettingsScreen> {
final key = GlobalKey<AsyncScreenWidgetState>();
NotificationsSettings _settings;
PushNotificationsStatus _pushNotificationsStatus;
late NotificationsSettings _settings;
PushNotificationsStatus? _pushNotificationsStatus;
Future<void> _loadSettings() async {
_settings = await SettingsHelper.getNotificationsSettings();
@ -37,7 +37,7 @@ class _NotificationsSettingsScreenState
key: key,
onReload: _loadSettings,
onBuild: _buildScreen,
errorMessage: tr("Failed to load notifications settings!"),
errorMessage: tr("Failed to load notifications settings!")!,
);
Widget _buildScreen() => SettingsList(sections: [
@ -81,7 +81,7 @@ class _NotificationsSettingsScreenState
setState(() {});
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to update settings!"));
snack(context, tr("Failed to update settings!")!);
}
}
}

View File

@ -12,8 +12,8 @@ class SinglePostRoute extends StatelessWidget {
final int postID;
const SinglePostRoute({
Key key,
@required this.postID,
Key? key,
required this.postID,
}) : assert(postID != null),
super(key: key);
@ -21,7 +21,7 @@ class SinglePostRoute extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(tr("Post")),
title: Text(tr("Post")!),
),
body: _SinglePostRouteBody(postID: postID),
);
@ -32,8 +32,8 @@ class _SinglePostRouteBody extends StatefulWidget {
final int postID;
const _SinglePostRouteBody({
Key key,
@required this.postID,
Key? key,
required this.postID,
}) : assert(postID != null),
super(key: key);
@ -42,7 +42,7 @@ class _SinglePostRouteBody extends StatefulWidget {
}
class __SinglePostRouteBodyState extends State<_SinglePostRouteBody> {
Future<PostsList> _getPost() async {
Future<PostsList?> _getPost() async {
try {
return PostsList()..add(await PostsHelper().getSingle(widget.postID));
} on Exception catch (e) {

View File

@ -40,7 +40,7 @@ class TourRouteState extends State<TourRoute> {
final Map<int, GlobalKey> pubKeys = Map();
User currUser;
late User currUser;
int _defaultIndex = 0;
@ -57,7 +57,7 @@ class TourRouteState extends State<TourRoute> {
areNotificationsConfigured = true;
// Attempt to automatically register to FCM
else if (srvConfig.notificationsPolicy.hasFirebase) {
else if (srvConfig!.notificationsPolicy.hasFirebase) {
try {
await PushNotificationsHelper.configure(
context, PushNotificationsStatus.FIREBASE);
@ -71,12 +71,12 @@ class TourRouteState extends State<TourRoute> {
void rebuild() => setState(() {});
void setStateKeepCurrentIndex(BuildContext cxt) async {
_defaultIndex = DefaultTabController.of(cxt).index;
await _key.currentState.refresh();
_defaultIndex = DefaultTabController.of(cxt)!.index;
await _key.currentState!.refresh();
}
List<Widget> get _list => (config().toursEntriesBuilder != null
? config().toursEntriesBuilder(this)
? config().toursEntriesBuilder!(this)
: [
FirstTourPane(),
@ -96,25 +96,25 @@ class TourRouteState extends State<TourRoute> {
PresentationPane(
icon: Icons.group_add,
title: tr("Friends"),
title: tr("Friends")!,
text:
"${tr("You can search the people you know and ask them to become your friends!")}\n\n${tr("This will help you to reach them to exchange information!")}",
),
PresentationPane(
icon: Icons.question_answer,
title: tr("Conversations"),
title: tr("Conversations")!,
text:
"${tr("With Comunic, you can have conversations with all your friends.")}\n\n${tr("It is also possible to make video calls!")}",
),
PresentationPane(
icon: Icons.group,
title: tr("Groups"),
title: tr("Groups")!,
text:
"${tr("You can join groups where people share the same interests as you!")}\n\n${tr("It is also easy to create your own groups!")}",
),
PresentationPane(
icon: Icons.lock,
title: tr("Privacy"),
title: tr("Privacy")!,
text:
"${tr("Your data is YOUR DATA. We will never use it or sell it.")}\n\n${tr("If you do not trust us, you can always check out our source code to verify it!")}",
),
@ -135,7 +135,7 @@ class TourRouteState extends State<TourRoute> {
child: AsyncScreenWidget(
key: _key,
onReload: _init,
errorMessage: tr("Failed to load tour!"),
errorMessage: tr("Failed to load tour!")!,
onBuild: () => DefaultTabController(
initialIndex: _defaultIndex,
length: _list.length,
@ -150,22 +150,22 @@ class TourRouteState extends State<TourRoute> {
}
class _RouteBody extends StatefulWidget {
final List<Widget> panes;
final List<Widget>? panes;
const _RouteBody({Key key, this.panes}) : super(key: key);
const _RouteBody({Key? key, this.panes}) : super(key: key);
@override
__RouteBodyState createState() => __RouteBodyState();
}
class __RouteBodyState extends State<_RouteBody> {
TabController _controller;
TabController? _controller;
bool get _isLastPane => _controller.index >= widget.panes.length - 1;
bool get _isLastPane => _controller!.index >= widget.panes!.length - 1;
PresentationPane get _currPane =>
widget.panes[_controller.index] is PresentationPane
? widget.panes[_controller.index]
PresentationPane? get _currPane =>
widget.panes![_controller!.index] is PresentationPane
? widget.panes![_controller!.index] as PresentationPane?
: null;
bool get _canGoNext => _currPane?.canGoNext ?? true;
@ -184,7 +184,7 @@ class __RouteBodyState extends State<_RouteBody> {
void _updateController() {
_controller = DefaultTabController.of(context);
_controller.addListener(() => setState(() {}));
_controller!.addListener(() => setState(() {}));
}
@override
@ -195,7 +195,7 @@ class __RouteBodyState extends State<_RouteBody> {
Spacer(flex: 1),
Expanded(
child: TabBarView(
children: widget.panes,
children: widget.panes!,
physics: NeverScrollableScrollPhysics(),
),
flex: 10),
@ -204,7 +204,7 @@ class __RouteBodyState extends State<_RouteBody> {
Spacer(flex: 1),
OutlinedButton(
onPressed: _canGoNext ? _nextOrFinish : null,
child: Text(!_isLastPane ? tr("Next") : tr("Let's go!")),
child: Text(!_isLastPane ? tr("Next")! : tr("Let's go!")!),
),
Spacer(flex: 1),
],
@ -212,17 +212,17 @@ class __RouteBodyState extends State<_RouteBody> {
);
void _nextOrFinish() async {
if (_controller.indexIsChanging) return;
if (_controller!.indexIsChanging) return;
if (!_isLastPane) {
// Check if the next click has to be captured
if (_currPane?.onTapNext != null) {
if (!await _currPane.onTapNext(context)) return;
if (!await _currPane!.onTapNext!(context)) return;
}
_controller.animateTo(_controller.index + 1);
_controller!.animateTo(_controller!.index + 1);
} else {
(await PreferencesHelper.getInstance())
(await PreferencesHelper.getInstance())!
.setBool(PreferencesKeyList.IS_TOUR_SEEN, true);
Navigator.of(context).pop();
}

View File

@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
class UpdateConversationRoute extends StatefulWidget {
final int conversationID;
const UpdateConversationRoute({Key key, this.conversationID})
const UpdateConversationRoute({Key? key, required this.conversationID})
: assert(conversationID != null),
super(key: key);

View File

@ -13,8 +13,8 @@ class VideoPlayerRoute extends StatefulWidget {
final String url;
const VideoPlayerRoute({
Key key,
@required this.url,
Key? key,
required this.url,
}) : assert(url != null),
super(key: key);
@ -23,16 +23,16 @@ class VideoPlayerRoute extends StatefulWidget {
}
class _VideoPlayerRouteState extends State<VideoPlayerRoute> {
VideoPlayerController _videoPlayerController;
ChewieController _chewieController;
VideoPlayerController? _videoPlayerController;
ChewieController? _chewieController;
Future<void> _initialize() async {
_videoPlayerController = VideoPlayerController.network(widget.url);
await _videoPlayerController.initialize();
await _videoPlayerController!.initialize();
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
videoPlayerController: _videoPlayerController!,
looping: false,
allowFullScreen: true,
allowMuting: true,
@ -42,8 +42,8 @@ class _VideoPlayerRouteState extends State<VideoPlayerRoute> {
@override
void dispose() {
if (_videoPlayerController != null) _videoPlayerController.dispose();
if (_chewieController != null) _chewieController.dispose();
if (_videoPlayerController != null) _videoPlayerController!.dispose();
if (_chewieController != null) _chewieController!.dispose();
super.dispose();
}
@ -61,8 +61,8 @@ class _VideoPlayerRouteState extends State<VideoPlayerRoute> {
Widget _buildBody() => AsyncScreenWidget(
onReload: _initialize,
onBuild: _showBody,
errorMessage: tr("Failed to initialize video!"),
errorMessage: tr("Failed to initialize video!")!,
);
Widget _showBody() => Chewie(controller: _chewieController);
Widget _showBody() => Chewie(controller: _chewieController!);
}

View File

@ -32,12 +32,12 @@ class _WelcomeRouteState extends State<WelcomeRoute> {
children: <Widget>[
ListTile(
leading: Icon(Icons.login, color: Colors.white),
title: Text(tr("Login")),
title: Text(tr("Login")!),
onTap: _openLoginPage,
),
ListTile(
leading: Icon(Icons.person_add_alt_1, color: Colors.white),
title: Text(tr("Join the network")),
title: Text(tr("Join the network")!),
onTap: _openCreateAccountPage,
)
],