1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2025-06-20 16:55: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

@ -27,14 +27,14 @@ Color get _headerColor => Colors.blueAccent.shade700;
class AuthorizedGroupPageScreen extends StatefulWidget {
final AdvancedGroupInfo advancedGroupInfo;
final int conversationID;
final int? conversationID;
final Function() needRefresh;
const AuthorizedGroupPageScreen({
Key key,
@required this.advancedGroupInfo,
@required this.conversationID,
@required this.needRefresh,
Key? key,
required this.advancedGroupInfo,
required this.conversationID,
required this.needRefresh,
}) : assert(advancedGroupInfo != null),
assert(needRefresh != null),
super(key: key);
@ -49,42 +49,42 @@ class _AuthorizedGroupPageScreenState
with SingleTickerProviderStateMixin {
AdvancedGroupInfo get _group => widget.advancedGroupInfo;
TabController _tabController;
TabController? _tabController;
List<_GroupPageTab> get _tabs => [
// Posts list
_GroupPageTab(
widget: (c) => GroupPostsSection(group: _group),
label: tr("Posts"),
label: tr("Posts")!,
),
// Forez presence tab
_GroupPageTab(
widget: (c) => ForezPresenceSection(groupID: _group.id),
label: tr("Presence"),
label: tr("Presence")!,
visible: _group.isForezGroup,
),
// About the group
_GroupPageTab(
widget: (c) => AboutGroupSection(group: _group),
label: tr("About"),
label: tr("About")!,
),
_GroupPageTab(
widget: (c) => GroupMembersSection(groupID: _group.id),
label: tr("Members"),
visible: _group.isAtLeastModerator || _group.isMembersListPublic,
label: tr("Members")!,
visible: _group.isAtLeastModerator || _group.isMembersListPublic!,
)
].where((element) => element.visible).toList()
// Add group conversations
..insertAll(
(_group.isForezGroup ? 2 : 1),
_group.conversations
_group.conversations!
.map((e) => _GroupPageTab(
widget: (c) => GroupConversationSection(conv: e),
label: e.name))
label: e.name!))
.toList());
@override
@ -94,7 +94,7 @@ class _AuthorizedGroupPageScreenState
initialIndex: widget.conversationID == null
? 0
: (_group.isForezGroup ? 2 : 1) +
_group.conversations
_group.conversations!
.indexWhere((element) => element.id == widget.conversationID),
vsync: this,
);
@ -104,7 +104,7 @@ class _AuthorizedGroupPageScreenState
@override
void dispose() {
_tabController.dispose();
_tabController!.dispose();
super.dispose();
}
@ -189,7 +189,7 @@ class _AuthorizedGroupPageScreenState
_group.isAdmin
? IconButton(
icon: Icon(Icons.settings, color: _headerTextColor),
onPressed: () => MainController.of(context).push(
onPressed: () => MainController.of(context)!.push(
GroupSettingsScreen(groupID: _group.id),
canShowAsDialog: true))
: Container(),
@ -207,9 +207,9 @@ class _GroupPageTab {
final String label;
const _GroupPageTab({
@required this.widget,
required this.widget,
this.visible = true,
@required this.label,
required this.label,
}) : assert(widget != null),
assert(visible != null),
assert(label != null);

View File

@ -33,16 +33,16 @@ class CallScreen extends StatefulWidget {
/// Use custom application bar. This function takes as parameter a nullable
/// String which is the title of the conversation
final PreferredSizeWidget Function(String) buildCustomAppBar;
final PreferredSizeWidget Function(String?)? buildCustomAppBar;
/// Execute custom action when the call is closed
///
/// The default behavior is to pop the page
final void Function() onClose;
final void Function()? onClose;
const CallScreen({
Key key,
@required this.convID,
Key? key,
required this.convID,
this.floatingButtons = true,
this.buildCustomAppBar,
this.onClose,
@ -60,15 +60,15 @@ class _CallScreenState extends SafeState<CallScreen> {
int get convID => widget.convID;
// State properties
Conversation _conversation;
String _convName;
CallConfig _conf;
late Conversation _conversation;
String? _convName;
late CallConfig _conf;
var _error = false;
CallMembersList _membersList;
UsersList _usersList;
final _peersConnections = Map<int, RTCPeerConnection>();
final _renderers = Map<int, RTCVideoRenderer>();
MediaStream _localStream;
CallMembersList? _membersList;
late UsersList _usersList;
final _peersConnections = Map<int?, RTCPeerConnection>();
final _renderers = Map<int?, RTCVideoRenderer>();
MediaStream? _localStream;
var _isLocalStreamVisible = true;
var _hideMenuBars = false;
@ -81,16 +81,16 @@ class _CallScreenState extends SafeState<CallScreen> {
_conversation.callCapabilities == CallCapabilities.VIDEO;
bool get isStreamingAudio =>
_localStream != null && _localStream.getAudioTracks().length > 0;
_localStream != null && _localStream!.getAudioTracks().length > 0;
bool get isStreamingVideo =>
_localStream != null && _localStream.getVideoTracks().length > 0;
_localStream != null && _localStream!.getVideoTracks().length > 0;
bool get isAudioMuted =>
isStreamingAudio && !_localStream.getAudioTracks()[0].enabled;
isStreamingAudio && !_localStream!.getAudioTracks()[0].enabled;
bool get isVideoMuted =>
isStreamingVideo && !_localStream.getVideoTracks()[0].enabled;
isStreamingVideo && !_localStream!.getVideoTracks()[0].enabled;
@override
void initState() {
@ -137,7 +137,7 @@ class _CallScreenState extends SafeState<CallScreen> {
try {
if (!_usersList.hasUser(e.userID))
_usersList.add(await UsersHelper().getSingleWithThrow(e.userID));
setState(() => _membersList.add(CallMember(userID: e.userID)));
setState(() => _membersList!.add(CallMember(userID: e.userID!)));
} catch (e, stack) {
print("$e\n$stack");
}
@ -164,7 +164,7 @@ class _CallScreenState extends SafeState<CallScreen> {
});
// Connect to ready peers
for (final peer in _membersList.readyPeers)
for (final peer in _membersList!.readyPeers)
await this._memberReady(peer.userID);
setState(() {});
@ -183,7 +183,7 @@ class _CallScreenState extends SafeState<CallScreen> {
await setWakeLock(false);
// Close all ready members
for (final member in _membersList.readyPeers)
for (final member in _membersList!.readyPeers)
await _removeMember(member.userID);
// Close local stream
@ -204,9 +204,9 @@ class _CallScreenState extends SafeState<CallScreen> {
message: tr("Do you really want to leave this call ?"))) return;
if (widget.onClose == null)
MainController.of(context).popPage();
MainController.of(context)!.popPage();
else
widget.onClose();
widget.onClose!();
}
/// Start streaming on our end
@ -232,8 +232,8 @@ class _CallScreenState extends SafeState<CallScreen> {
// Start renderer
_renderers[userID()] = RTCVideoRenderer();
await _renderers[userID()].initialize();
_renderers[userID()].srcObject = _localStream;
await _renderers[userID()]!.initialize();
_renderers[userID()]!.srcObject = _localStream;
setState(() {});
// Open stream
@ -244,8 +244,8 @@ class _CallScreenState extends SafeState<CallScreen> {
_peersConnections[userID()] = peerConnection;
for (final track in _localStream.getTracks()) {
await peerConnection.addTrack(track, _localStream);
for (final track in _localStream!.getTracks()) {
await peerConnection.addTrack(track, _localStream!);
}
peerConnection.onAddStream =
@ -275,7 +275,7 @@ class _CallScreenState extends SafeState<CallScreen> {
await CallsHelper.sendSessionDescription(convID, userID(), offer);
} catch (e, stack) {
print("Could not start streaming! $e\n$stack");
showSimpleSnack(context, tr("Could not start streaming!"));
showSimpleSnack(context, tr("Could not start streaming!")!);
}
}
@ -283,7 +283,7 @@ class _CallScreenState extends SafeState<CallScreen> {
Future<void> _stopStreaming() async {
// Close peer connection
if (_peersConnections.containsKey(userID())) {
_peersConnections[userID()].close();
_peersConnections[userID()]!.close();
_peersConnections.remove(userID());
await CallsHelper.notifyStoppedStreaming(convID);
@ -291,13 +291,13 @@ class _CallScreenState extends SafeState<CallScreen> {
// Stop local stream
if (_localStream != null) {
await _localStream.dispose();
await _localStream!.dispose();
_localStream = null;
}
// Close renderer
if (_renderers.containsKey(userID())) {
await _renderers[userID()].dispose();
await _renderers[userID()]!.dispose();
_renderers.remove(userID());
}
}
@ -324,20 +324,20 @@ class _CallScreenState extends SafeState<CallScreen> {
// Toggle appropriate mute
else {
if (!isVideo)
_localStream.getAudioTracks()[0].enabled =
!_localStream.getAudioTracks()[0].enabled;
_localStream!.getAudioTracks()[0].enabled =
!_localStream!.getAudioTracks()[0].enabled;
else
_localStream.getVideoTracks()[0].enabled =
!_localStream.getVideoTracks()[0].enabled;
_localStream!.getVideoTracks()[0].enabled =
!_localStream!.getVideoTracks()[0].enabled;
}
setState(() {});
}
/// Call this when a user started to stream media
Future<void> _memberReady(int memberID) async {
Future<void> _memberReady(int? memberID) async {
try {
_membersList.getUser(memberID).status = MemberStatus.READY;
_membersList!.getUser(memberID).status = MemberStatus.READY;
setState(() {});
// Create peer connection
@ -353,15 +353,15 @@ class _CallScreenState extends SafeState<CallScreen> {
// Create a renderer
_renderers[memberID] = RTCVideoRenderer();
await _renderers[memberID].initialize();
await _renderers[memberID]!.initialize();
// Register callbacks
peerConnection.onIceCandidate =
(c) => CallsHelper.sendIceCandidate(convID, memberID, c);
peerConnection.onAddStream = (s) {
setState(() {
_membersList.getUser(memberID).stream = s;
_renderers[memberID].srcObject = s;
_membersList!.getUser(memberID).stream = s;
_renderers[memberID]!.srcObject = s;
});
};
@ -371,7 +371,7 @@ class _CallScreenState extends SafeState<CallScreen> {
setState(() {});
} catch (e, stack) {
print("Could not connect to remote peer $e\n$stack!");
showSimpleSnack(context, tr("Could not connect to a remote peer!"));
showSimpleSnack(context, tr("Could not connect to a remote peer!")!);
}
}
@ -388,13 +388,13 @@ class _CallScreenState extends SafeState<CallScreen> {
// Check the kind of signal
// SessionDescription
if (ev.sessionDescription != null) {
await _peersConnections[ev.peerID]
.setRemoteDescription(ev.sessionDescription);
await _peersConnections[ev.peerID]!
.setRemoteDescription(ev.sessionDescription!);
// Send answer if required
if (ev.sessionDescription.type == "offer") {
final answer = await _peersConnections[ev.peerID].createAnswer({});
await _peersConnections[ev.peerID].setLocalDescription(answer);
if (ev.sessionDescription!.type == "offer") {
final answer = await _peersConnections[ev.peerID]!.createAnswer({});
await _peersConnections[ev.peerID]!.setLocalDescription(answer);
await CallsHelper.sendSessionDescription(convID, ev.peerID, answer);
}
@ -402,41 +402,41 @@ class _CallScreenState extends SafeState<CallScreen> {
// Ice Candidate
else {
await _peersConnections[ev.peerID].addCandidate(ev.candidate);
await _peersConnections[ev.peerID]!.addCandidate(ev.candidate!);
}
} catch (e, stack) {
print("Error while handling new signal ! $e\n$stack");
showSimpleSnack(context, tr("Error while processing new signal!"));
showSimpleSnack(context, tr("Error while processing new signal!")!);
}
}
/// Call this when a user has interrupted streaming
Future<void> _removeRemotePeerConnection(int memberID) async {
final member = _membersList.getUser(memberID);
Future<void> _removeRemotePeerConnection(int? memberID) async {
final member = _membersList!.getUser(memberID);
member.status = MemberStatus.JOINED;
setState(() {});
if (_peersConnections.containsKey(memberID)) {
await _peersConnections[memberID].close();
await _peersConnections[memberID]!.close();
_peersConnections.remove(memberID);
}
if (_renderers.containsKey(memberID)) {
await _renderers[memberID].dispose();
await _renderers[memberID]!.dispose();
_renderers.remove(memberID);
}
if (member.stream != null) {
member.stream.dispose();
member.stream!.dispose();
member.stream = null;
}
}
/// Call this when a member has completely left the call
Future<void> _removeMember(int memberID) async {
Future<void> _removeMember(int? memberID) async {
await _removeRemotePeerConnection(memberID);
_membersList.removeUser(memberID);
_membersList!.removeUser(memberID);
setState(() {});
}
@ -453,7 +453,7 @@ class _CallScreenState extends SafeState<CallScreen> {
switch (option) {
// Switch camera
case _PopupMenuOption.SWITCH_CAMERA:
await Helper.switchCamera(_localStream.getVideoTracks()[0]);
await Helper.switchCamera(_localStream!.getVideoTracks()[0]);
break;
// Stop streaming
@ -478,14 +478,14 @@ class _CallScreenState extends SafeState<CallScreen> {
/// Build application bar
PreferredSizeWidget _buildAppBar() {
if (widget.buildCustomAppBar != null)
return widget.buildCustomAppBar(_convName);
return widget.buildCustomAppBar!(_convName);
return AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => _leaveCall(),
),
title: _convName == null ? CircularProgressIndicator() : Text(_convName),
title: _convName == null ? CircularProgressIndicator() : Text(_convName!),
);
}
@ -496,7 +496,7 @@ class _CallScreenState extends SafeState<CallScreen> {
return buildErrorCard(tr("Could not initialize call!"), actions: [
MaterialButton(
onPressed: () => _initCall(),
child: Text(tr("Try again").toUpperCase()),
child: Text(tr("Try again")!.toUpperCase()),
)
]);
@ -526,7 +526,7 @@ class _CallScreenState extends SafeState<CallScreen> {
padding: const EdgeInsets.all(8.0),
child: RichText(
text: TextSpan(
children: _membersList
children: _membersList!
.map((f) => TextSpan(
text: _usersList.getUser(f.userID).displayName + " ",
style: TextStyle(
@ -540,7 +540,7 @@ class _CallScreenState extends SafeState<CallScreen> {
/// Videos area
Widget _buildVideosArea(BuildContext context, BoxConstraints constraints) {
final availableVideos = _membersList.readyPeers
final List<CallMember> availableVideos = _membersList!.readyPeers
.where((f) => f.hasVideoStream && _renderers.containsKey(f.userID))
.toList();
@ -591,12 +591,12 @@ class _CallScreenState extends SafeState<CallScreen> {
}
Widget _buildMemberVideo(int peerID) {
return RTCVideoView(_renderers[peerID]);
return RTCVideoView(_renderers[peerID]!);
}
Widget _buildLocalVideo() {
return Positioned(
child: RTCVideoView(_renderers[userID()]),
child: RTCVideoView(_renderers[userID()]!),
height: 50,
width: 50,
right: 10,
@ -657,12 +657,12 @@ class _CallScreenState extends SafeState<CallScreen> {
// Switch camera
PopupMenuItem(
enabled: isStreamingVideo,
child: Text(tr("Switch camera")),
child: Text(tr("Switch camera")!),
value: _PopupMenuOption.SWITCH_CAMERA),
// Interrupt streaming
PopupMenuItem(
child: Text(tr("Stop streaming")),
child: Text(tr("Stop streaming")!),
value: _PopupMenuOption.STOP_STREAMING)
],
child: _FooterButton(
@ -679,7 +679,7 @@ class _CallScreenState extends SafeState<CallScreen> {
}
class _FooterButton extends StatelessWidget {
final Function() onPressed;
final Function()? onPressed;
final Widget icon;
final bool visible;
final double width;
@ -687,13 +687,13 @@ class _FooterButton extends StatelessWidget {
final bool roundedButtons;
const _FooterButton({
Key key,
@required this.icon,
@required this.onPressed,
Key? key,
required this.icon,
required this.onPressed,
this.visible = true,
this.width = 45,
this.bgColor = Colors.black,
@required this.roundedButtons,
required this.roundedButtons,
}) : assert(icon != null),
assert(visible != null),
assert(roundedButtons != null),
@ -712,7 +712,7 @@ class _FooterButton extends StatelessWidget {
child: FloatingActionButton(
child: icon,
foregroundColor: Colors.white,
onPressed: onPressed == null ? null : () => onPressed(),
onPressed: onPressed == null ? null : () => onPressed!(),
backgroundColor: bgColor,
),
));

View File

@ -15,8 +15,8 @@ class ConversationMembersScreen extends StatefulWidget {
final int convID;
const ConversationMembersScreen({
Key key,
@required this.convID,
Key? key,
required this.convID,
}) : assert(convID != null),
super(key: key);
@ -26,8 +26,8 @@ class ConversationMembersScreen extends StatefulWidget {
}
class _ConversationMembersScreenState extends State<ConversationMembersScreen> {
Conversation _conversation;
UsersList _members;
late Conversation _conversation;
late UsersList _members;
Future<void> _refresh() async {
_conversation =
@ -38,28 +38,28 @@ class _ConversationMembersScreenState extends State<ConversationMembersScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(tr("Conversation members"))),
appBar: AppBar(title: Text(tr("Conversation members")!)),
body: AsyncScreenWidget(
onReload: _refresh,
onBuild: _buildMembersList,
errorMessage:
tr("Could not load the list of members of this conversation!"),
tr("Could not load the list of members of this conversation!")!,
),
);
}
Widget _buildMembersList() => ListView.builder(
itemBuilder: _buildItem,
itemCount: _conversation.members.length,
itemCount: _conversation.members!.length,
);
Widget _buildItem(BuildContext context, int index) {
final member = _conversation.members[index];
final member = _conversation.members![index];
final user = _members.getUser(member.userID);
return ListTile(
leading: AccountImageWidget(user: user),
title: Text(user.displayName),
subtitle: Text(member.isAdmin ? tr("Admin") : tr("Member")),
subtitle: Text(member.isAdmin ? tr("Admin")! : tr("Member")!),
);
}
}

View File

@ -42,7 +42,7 @@ enum _OlderMessagesLevel { NONE, LOADING, NO_MORE_AVAILABLE }
class ConversationScreen extends StatefulWidget {
final int conversationID;
const ConversationScreen({Key key, this.conversationID})
const ConversationScreen({Key? key, required this.conversationID})
: assert(conversationID != null),
super(key: key);
@ -56,8 +56,8 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
final UsersHelper _usersHelper = UsersHelper();
// Class members
Conversation _conversation;
ConversationMessagesList _messages;
late Conversation _conversation;
ConversationMessagesList? _messages;
UsersList _usersInfo = UsersList();
ErrorLevel _error = ErrorLevel.NONE;
final _textFieldFocus = FocusNode();
@ -66,21 +66,21 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
bool _isSendingMessage = false;
TextEditingController _textController = TextEditingController();
ScrollWatcher _scrollController;
ScrollWatcher? _scrollController;
_OlderMessagesLevel _loadingOlderMessages = _OlderMessagesLevel.NONE;
int _lastWritingEventSent = 0;
CancelToken _sendCancel;
double _sendProgress;
CancelToken? _sendCancel;
double? _sendProgress;
String get textMessage => _textController.text;
bool get _isMessageValid =>
textMessage.length >=
ServerConfigurationHelper.config.conversationsPolicy.minMessageLen &&
ServerConfigurationHelper.config!.conversationsPolicy.minMessageLen &&
textMessage.length <
ServerConfigurationHelper.config.conversationsPolicy.maxMessageLen;
ServerConfigurationHelper.config!.conversationsPolicy.maxMessageLen;
showKeyboard() => _textFieldFocus.requestFocus();
@ -179,14 +179,14 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
this.listen<UpdatedConversationMessageEvent>((ev) async {
if (ev.msg.convID == widget.conversationID) {
await _conversationsHelper.saveMessage(ev.msg);
setState(() => _messages.replace(ev.msg));
setState(() => _messages!.replace(ev.msg));
}
});
this.listen<DeletedConversationMessageEvent>((ev) async {
if (ev.msg.convID == widget.conversationID) {
await _conversationsHelper.removeMessage(ev.msg);
setState(() => _messages.removeMsg(ev.msg.id));
setState(() => _messages!.removeMsg(ev.msg.id));
}
});
@ -216,7 +216,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
//First, get the messages
final messages = await _conversationsHelper.getNewMessages(
conversationID: widget.conversationID,
lastMessageID: _messages == null ? 0 : _messages.lastMessageID,
lastMessageID: _messages == null ? 0 : _messages!.lastMessageID,
online: online,
);
@ -235,14 +235,14 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
Future<void> _loadOlderMessages() async {
if (_loadingOlderMessages != _OlderMessagesLevel.NONE ||
_messages == null ||
_messages.length == 0) return;
_messages!.length == 0) return;
try {
// Let's start to load older messages
_setLoadingOlderMessagesState(_OlderMessagesLevel.LOADING);
final messages = await _conversationsHelper.getOlderMessages(
conversationID: widget.conversationID,
oldestMessagesID: _messages.firstMessageID);
oldestMessagesID: _messages!.firstMessageID);
// Mark as not loading anymore
_setLoadingOlderMessagesState(_OlderMessagesLevel.NONE);
@ -280,14 +280,14 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
if (_messages == null)
_messages = messages;
else
_messages.addAll(messages);
_messages!.addAll(messages);
//Reverse the order of the messages (if required)
if (messages.length > 0) {
_messages.sort();
final reverse = _messages.reversed;
_messages!.sort();
final Iterable<ConversationMessage> reverse = _messages!.reversed;
_messages = ConversationMessagesList();
_messages.addAll(reverse);
_messages!.addAll(reverse);
}
});
@ -300,20 +300,20 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
try {
final file = await showPickFileDialog(
context: context,
maxFileSize: srvConfig.conversationsPolicy.filesMaxSize,
allowedMimeTypes: srvConfig.conversationsPolicy.allowedFilesType,
imageMaxWidth: srvConfig.conversationsPolicy.maxMessageImageWidth,
imageMaxHeight: srvConfig.conversationsPolicy.maxMessageImageHeight,
maxFileSize: srvConfig!.conversationsPolicy.filesMaxSize,
allowedMimeTypes: srvConfig!.conversationsPolicy.allowedFilesType,
imageMaxWidth: srvConfig!.conversationsPolicy.maxMessageImageWidth,
imageMaxHeight: srvConfig!.conversationsPolicy.maxMessageImageHeight,
);
if (file == null) return;
BytesFile thumbnail;
BytesFile? thumbnail;
if (isVideo(lookupMimeType(file.filename)))
if (isVideo(lookupMimeType(file.filename)!))
thumbnail = await generateVideoThumbnail(
videoFile: file,
maxWidth: srvConfig.conversationsPolicy.maxThumbnailWidth,
maxWidth: srvConfig!.conversationsPolicy.maxThumbnailWidth,
);
_sendCancel = CancelToken();
@ -331,7 +331,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
assert(res == SendMessageResult.SUCCESS);
} catch (e, s) {
logError(e, s);
showSimpleSnack(context, tr("Failed to send a file!"));
showSimpleSnack(context, tr("Failed to send a file!")!);
}
setState(() {
@ -363,8 +363,8 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
SnackBar(
content: Text(
result == SendMessageResult.MESSAGE_REJECTED
? tr("Message rejected by the server!")
: tr("Could not send message!"),
? tr("Message rejected by the server!")!
: tr("Could not send message!")!,
),
duration: Duration(milliseconds: 500),
),
@ -395,7 +395,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
Widget _buildNoMessagesNotice() {
return Expanded(
child: Center(
child: Text(tr("There is no message yet in this conversation.")),
child: Text(tr("There is no message yet in this conversation.")!),
),
);
}
@ -406,15 +406,15 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
child: ListView.builder(
controller: _scrollController,
reverse: true,
itemCount: _messages.length,
itemCount: _messages!.length,
itemBuilder: (c, i) => _buildMessageItem(i),
));
}
Widget _buildMessageItem(int msgIndex) {
final msg = _messages[msgIndex];
final msg = _messages![msgIndex];
final nextMessage =
msgIndex + 1 < _messages.length ? _messages[msgIndex + 1] : null;
msgIndex + 1 < _messages!.length ? _messages![msgIndex + 1] : null;
return Column(
children: <Widget>[
@ -427,7 +427,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
? Container(
alignment: Alignment.center,
child: ServerConversationMessageTile(
message: msg.serverMessage, users: _usersInfo),
message: msg.serverMessage!, users: _usersInfo),
)
: Container(
margin: EdgeInsets.symmetric(vertical: 5),
@ -442,7 +442,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
}
Widget _buildSenderLayout(
ConversationMessage message, ConversationMessage previousMessage) {
ConversationMessage message, ConversationMessage? previousMessage) {
final messageRadius = Radius.circular(10);
return Container(
@ -466,7 +466,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
}
Widget _buildReceiverLayout(
ConversationMessage message, ConversationMessage previousMessage) {
ConversationMessage message, ConversationMessage? previousMessage) {
final messageRadius = Radius.circular(10);
return Row(children: [
@ -640,11 +640,11 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
flex: 5,
),
Spacer(flex: 1),
Text("${(_sendProgress * 100).toInt()}%"),
Text("${(_sendProgress! * 100).toInt()}%"),
Spacer(flex: 1),
OutlinedButton(
onPressed: () => _sendCancel.cancel(),
child: Text(tr("Cancel").toUpperCase()),
onPressed: () => _sendCancel!.cancel(),
child: Text(tr("Cancel")!.toUpperCase()),
),
Spacer(flex: 1),
],
@ -667,8 +667,8 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
? _buildLoadingOlderMessage()
: null,
),
_messages.length == 0 ? _buildNoMessagesNotice() : _buildMessagesList(),
UserWritingInConvNotifier(convID: _conversation.id),
_messages!.length == 0 ? _buildNoMessagesNotice() : _buildMessagesList(),
UserWritingInConvNotifier(convID: _conversation.id!),
_sendCancel != null ? _buildSendingWidget() : _buildSendMessageForm(),
_showEmojiPicker ? _buildEmojiContainer() : Container(),
],
@ -681,7 +681,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
final t = time();
if (t - _lastWritingEventSent <
srvConfig.conversationsPolicy.writingEventInterval) return;
srvConfig!.conversationsPolicy.writingEventInterval) return;
_lastWritingEventSent = t;
await ConversationsHelper.sendWritingEvent(_conversation.id);
@ -692,7 +692,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
/// Request message statistics
void _requestMessageStats(ConversationMessage message) async {
MainController.of(context)
MainController.of(context)!
.openConversationMessageStats(_conversation, message);
}
@ -700,20 +700,20 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
Future<void> _updateMessage(ConversationMessage message) async {
final newContent = await askUserString(
context: context,
title: tr("Update message"),
message: tr("Please enter new message content:"),
defaultValue: message.message.content,
hint: tr("New message"),
title: tr("Update message")!,
message: tr("Please enter new message content:")!,
defaultValue: message.message.content!,
hint: tr("New message")!,
minLength:
ServerConfigurationHelper.config.conversationsPolicy.minMessageLen,
ServerConfigurationHelper.config!.conversationsPolicy.minMessageLen,
maxLength:
ServerConfigurationHelper.config.conversationsPolicy.maxMessageLen,
ServerConfigurationHelper.config!.conversationsPolicy.maxMessageLen,
);
if (newContent == null) return;
if (!await _conversationsHelper.updateMessage(message.id, newContent)) {
showSimpleSnack(context, tr("Could not update message content!"));
showSimpleSnack(context, tr("Could not update message content!")!);
return;
}
}
@ -723,21 +723,21 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
final choice = await showDialog<bool>(
context: context,
builder: (c) => AlertDialog(
title: Text(tr("Confirm deletion")),
title: Text(tr("Confirm deletion")!),
content: Text(
tr("Do you really want to delete this message ? The operation can not be cancelled !"),
tr("Do you really want to delete this message ? The operation can not be cancelled !")!,
textAlign: TextAlign.justify,
),
actions: <Widget>[
TextButton(
child: Text(
tr("Cancel").toUpperCase(),
tr("Cancel")!.toUpperCase(),
),
onPressed: () => Navigator.pop(c, false),
),
TextButton(
child: Text(
tr("Confirm").toUpperCase(),
tr("Confirm")!.toUpperCase(),
style: TextStyle(color: Colors.red),
),
onPressed: () => Navigator.pop(c, true),
@ -750,6 +750,6 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
// Execute the request
if (!await _conversationsHelper.deleteMessage(message.id))
showSimpleSnack(context, tr("Could not delete conversation message!"));
showSimpleSnack(context, tr("Could not delete conversation message!")!);
}
}

View File

@ -21,10 +21,10 @@ import 'package:flutter/material.dart';
class ConversationsListScreen extends StatefulWidget {
final bool useSmallFAB;
final Function() onOpen;
final Function()? onOpen;
const ConversationsListScreen({
Key key,
Key? key,
this.useSmallFAB = false,
this.onOpen,
}) : assert(useSmallFAB != null),
@ -37,9 +37,9 @@ class ConversationsListScreen extends StatefulWidget {
class _ConversationScreenState extends SafeState<ConversationsListScreen> {
final ConversationsHelper _conversationsHelper = ConversationsHelper();
final UsersHelper _usersHelper = UsersHelper();
ConversationsList _list;
UsersList _users;
GroupsList _groups;
ConversationsList? _list;
late UsersList _users;
GroupsList? _groups;
LoadErrorLevel _error = LoadErrorLevel.NONE;
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>();
@ -49,7 +49,7 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
super.initState();
this.listen<NewNumberUnreadConversations>(
(d) => _refreshIndicatorKey.currentState.show());
(d) => _refreshIndicatorKey.currentState!.show());
}
@override
@ -94,9 +94,9 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
tr("Could not retrieve the list of conversations!"),
actions: <Widget>[
TextButton(
onPressed: () => _refreshIndicatorKey.currentState.show(),
onPressed: () => _refreshIndicatorKey.currentState!.show(),
child: Text(
tr("Retry").toUpperCase(),
tr("Retry")!.toUpperCase(),
style: TextStyle(
color: Colors.white,
),
@ -108,23 +108,23 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
/// Open a conversation
void _openConversation(Conversation conv) {
MainController.of(context).openConversation(conv);
if (widget.onOpen != null) widget.onOpen();
MainController.of(context)!.openConversation(conv);
if (widget.onOpen != null) widget.onOpen!();
}
/// Create a new conversation
void _createConversation() {
MainController.of(context).push(
MainController.of(context)!.push(
CreateConversationScreen(),
canShowAsDialog: true,
hideNavBar: true,
);
if (widget.onOpen != null) widget.onOpen();
if (widget.onOpen != null) widget.onOpen!();
}
/// Handle conversations updated requests
void _updateConversation(Conversation conversation) {
MainController.of(context).openConversationSettingsRoute(conversation);
MainController.of(context)!.openConversationSettingsRoute(conversation);
}
/// Handle conversation deletion request
@ -153,7 +153,7 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
} catch (e, s) {
print("Failed to leave conversation! $e => $s");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(tr("Could not leave the conversation!"))));
SnackBar(content: Text(tr("Could not leave the conversation!")!)));
}
// Reload the list of conversations
@ -181,11 +181,11 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
physics: AlwaysScrollableScrollPhysics(),
controller: ScrollController(),
itemBuilder: (context, index) {
if (_list[index].isGroupConversation &&
!_list[index].following) return Container();
if (_list![index].isGroupConversation &&
!_list![index].following) return Container();
return ConversationTile(
conversation: _list.elementAt(index),
conversation: _list!.elementAt(index),
usersList: _users,
groupsList: _groups,
onOpen: (c) {
@ -195,7 +195,7 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
onRequestLeave: _requestLeaveConversation,
);
},
itemCount: _list.length,
itemCount: _list!.length,
),
),
),

View File

@ -22,7 +22,7 @@ enum _ErrorsLevel { NONE, MINOR, MAJOR }
class FriendsListScreen extends StatefulWidget {
final bool showAppBar;
const FriendsListScreen({Key key, this.showAppBar = true}) : super(key: key);
const FriendsListScreen({Key? key, this.showAppBar = true}) : super(key: key);
@override
State<StatefulWidget> createState() => _FriendsListScreenState();
@ -35,8 +35,8 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
/// Widget members
_ErrorsLevel _error = _ErrorsLevel.NONE;
FriendsList _friendsList;
UsersList _usersInfo;
FriendsList? _friendsList;
late UsersList _usersInfo;
GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>();
@ -61,7 +61,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
/// Refresh the list of friends
Future<void> _refreshList() async {
await _refreshIndicatorKey.currentState.show();
await _refreshIndicatorKey.currentState!.show();
}
/// Load the list of friends
@ -72,7 +72,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
final list = await _friendsHelper.getList(online: online);
// Check if there is no cache yet
if (!online && list.isEmpty) return;
if (!online && list!.isEmpty) return;
// Check for errors
if (list == null) return _gotError();
@ -98,7 +98,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
TextButton(
onPressed: _refreshList,
child: Text(
tr("Retry").toUpperCase(),
tr("Retry")!.toUpperCase(),
style: TextStyle(color: Colors.white),
),
),
@ -109,7 +109,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
Widget build(BuildContext context) => Scaffold(
appBar: widget.showAppBar
? AppBar(
title: Text(tr("Your friends list")),
title: Text(tr("Your friends list")!),
)
: null,
body: _buildBody(),
@ -131,18 +131,18 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
onRefresh: () => _loadList(true),
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
itemCount: _friendsList.length,
itemBuilder: (c, i) => _friendsList[i].accepted
itemCount: _friendsList!.length,
itemBuilder: (c, i) => _friendsList![i].accepted
? AcceptedFriendTile(
friend: _friendsList[i],
user: _usersInfo.getUser(_friendsList[i].id),
friend: _friendsList![i],
user: _usersInfo.getUser(_friendsList![i].id),
onOpenPrivateConversation: _openPrivateConversation,
onSetFollowing: _setFollowingFriend,
onRequestDelete: _deleteFriend,
)
: PendingFriendTile(
friend: _friendsList[i],
user: _usersInfo.getUser(_friendsList[i].id),
friend: _friendsList![i],
user: _usersInfo.getUser(_friendsList![i].id),
onRespond: _respondRequest,
)),
),
@ -154,7 +154,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
/// Respond to friendship request
Future<void> _respondRequest(Friend f, bool accept) async {
if (!await _friendsHelper.respondRequest(f.id, accept))
showSimpleSnack(context, tr("Could not respond to friendship request!"));
showSimpleSnack(context, tr("Could not respond to friendship request!")!);
// Load the list of friends again
_refreshList();
@ -163,7 +163,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
/// Update following status of a friend
Future<void> _setFollowingFriend(Friend friend, bool follow) async {
if (!await _friendsHelper.setFollowing(friend.id, follow))
showSimpleSnack(context, tr("Could not update following status!"));
showSimpleSnack(context, tr("Could not update following status!")!);
_refreshList();
}
@ -173,18 +173,18 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
final choice = await showDialog<bool>(
context: context,
builder: (b) => AlertDialog(
title: Text(tr("Delete friend")),
title: Text(tr("Delete friend")!),
content: Text(tr(
"Are you sure do you want to remove this friend from your list of friends ? A friendship request will have to be sent to get this user back to your list!")),
"Are you sure do you want to remove this friend from your list of friends ? A friendship request will have to be sent to get this user back to your list!")!),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text(tr("Cancel").toUpperCase()),
child: Text(tr("Cancel")!.toUpperCase()),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(
tr("Confirm").toUpperCase(),
tr("Confirm")!.toUpperCase(),
style: TextStyle(color: Colors.red),
),
),
@ -197,7 +197,7 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
// Forward the request to the server
if (!await _friendsHelper.removeFriend(f.id))
showSimpleSnack(
context, tr("Could not delete this person from your friends list!"));
context, tr("Could not delete this person from your friends list!")!);
// Refresh list
_refreshList();

View File

@ -16,9 +16,9 @@ class GroupAccessDeniedScreen extends StatefulWidget {
final Function() onMembershipAcquired;
const GroupAccessDeniedScreen({
Key key,
@required this.groupID,
@required this.onMembershipAcquired,
Key? key,
required this.groupID,
required this.onMembershipAcquired,
}) : assert(groupID != null),
assert(onMembershipAcquired != null),
super(key: key);
@ -29,7 +29,7 @@ class GroupAccessDeniedScreen extends StatefulWidget {
}
class _GroupAccessDeniedScreenState extends SafeState<GroupAccessDeniedScreen> {
Group _group;
Group? _group;
bool error = false;
@ -45,7 +45,7 @@ class _GroupAccessDeniedScreenState extends SafeState<GroupAccessDeniedScreen> {
return buildErrorCard(tr("Could not get basic group information!"),
actions: [
MaterialButton(
child: Text(tr("Try again").toUpperCase()),
child: Text(tr("Try again")!.toUpperCase()),
onPressed: () => this._refresh(),
)
]);
@ -61,20 +61,20 @@ class _GroupAccessDeniedScreenState extends SafeState<GroupAccessDeniedScreen> {
Spacer(
flex: 5,
),
GroupIcon(group: _group),
GroupIcon(group: _group!),
Spacer(),
Text(
_group.displayName,
_group!.displayName,
style: TextStyle(fontSize: 20),
),
Spacer(),
Text(
tr("A registration is required to access this group page."),
tr("A registration is required to access this group page.")!,
textAlign: TextAlign.center,
),
Spacer(),
GroupMembershipWidget(
group: _group,
group: _group!,
onUpdated: () => this._refresh(),
onError: () => this._refresh(),
),

View File

@ -12,11 +12,11 @@ import 'package:flutter/material.dart';
class GroupPageScreen extends StatefulWidget {
final int groupID;
final int conversationID;
final int? conversationID;
const GroupPageScreen({
Key key,
@required this.groupID,
Key? key,
required this.groupID,
this.conversationID,
}) : assert(groupID != null),
super(key: key);
@ -28,7 +28,7 @@ class GroupPageScreen extends StatefulWidget {
class _GroupPageScreenState extends SafeState<GroupPageScreen> {
int get groupID => widget.groupID;
GetAdvancedInfoResult _getGroupResult;
GetAdvancedInfoResult? _getGroupResult;
var error = false;
@override
@ -44,7 +44,7 @@ class _GroupPageScreenState extends SafeState<GroupPageScreen> {
actions: [
MaterialButton(
onPressed: () => _refreshPage(),
child: Text(tr("Try again").toUpperCase()),
child: Text(tr("Try again")!.toUpperCase()),
)
]);
@ -52,7 +52,7 @@ class _GroupPageScreenState extends SafeState<GroupPageScreen> {
if (_getGroupResult == null) return buildCenteredProgressBar();
// Check if access to the group was denied
if (_getGroupResult.status == GetAdvancedInfoStatus.ACCESS_DENIED)
if (_getGroupResult!.status == GetAdvancedInfoStatus.ACCESS_DENIED)
return GroupAccessDeniedScreen(
groupID: groupID,
onMembershipAcquired: () => _refreshPage(),
@ -60,7 +60,7 @@ class _GroupPageScreenState extends SafeState<GroupPageScreen> {
// Now we can show group page
return AuthorizedGroupPageScreen(
advancedGroupInfo: _getGroupResult.info,
advancedGroupInfo: _getGroupResult!.info!,
conversationID: widget.conversationID,
needRefresh: () => _refreshPage(),
);

View File

@ -13,8 +13,8 @@ class AboutGroupSection extends StatelessWidget {
final AdvancedGroupInfo group;
const AboutGroupSection({
Key key,
@required this.group,
Key? key,
required this.group,
}) : assert(group != null),
super(key: key);
@ -25,7 +25,7 @@ class AboutGroupSection extends StatelessWidget {
group.hasURL
? ListTile(
leading: Icon(Icons.link),
title: Text(tr("URL")),
title: Text(tr("URL")!),
subtitle: Text(group.url),
onTap: () => launch(group.url),
)
@ -35,7 +35,7 @@ class AboutGroupSection extends StatelessWidget {
group.hasDescription
? ListTile(
leading: Icon(Icons.note),
title: Text(tr("Description")),
title: Text(tr("Description")!),
subtitle: Text(group.description),
)
: Container(),
@ -44,64 +44,64 @@ class AboutGroupSection extends StatelessWidget {
ListTile(
leading: Icon(Icons.access_time),
title: Text("Created"),
subtitle: Text(diffTimeFromNowToStr(group.timeCreate)),
subtitle: Text(diffTimeFromNowToStr(group.timeCreate!)!),
),
// Number of members
ListTile(
leading: Icon(Icons.group),
title: Text(tr("Members")),
title: Text(tr("Members")!),
subtitle: Text(
tr("%1% members", args: {"1": group.numberMembers.toString()})),
tr("%1% members", args: {"1": group.numberMembers.toString()})!),
),
// Who can create posts
ListTile(
leading: Icon(Icons.add),
title: Text(tr("Who can create posts")),
title: Text(tr("Who can create posts")!),
subtitle: Text(
group.postCreationLevel == GroupPostCreationLevel.MEMBERS
? tr("Every members")
: tr("Only moderators and administrators")),
? tr("Every members")!
: tr("Only moderators and administrators")!),
),
// Registration process
ListTile(
leading: Icon(Icons.login),
title: Text(tr("Registration process")),
title: Text(tr("Registration process")!),
subtitle: Text(group.registrationLevel ==
GroupRegistrationLevel.CLOSED
? tr("On invitation only")
? tr("On invitation only")!
: (group.registrationLevel == GroupRegistrationLevel.MODERATED
? tr("A moderator has to approve requests")
: tr("Anyone can join the group without approval"))),
? tr("A moderator has to approve requests")!
: tr("Anyone can join the group without approval")!)),
),
// Group visibility
ListTile(
leading: Icon(Icons.remove_red_eye),
title: Text(tr("Visibility")),
title: Text(tr("Visibility")!),
subtitle: Text(group.visibilityLevel == GroupVisibilityLevel.SECRETE
? tr("Secrete group")
? tr("Secrete group")!
: (group.visibilityLevel == GroupVisibilityLevel.PRIVATE
? tr("Private group")
: tr("Open group"))),
? tr("Private group")!
: tr("Open group")!)),
),
// Group members visibility
ListTile(
leading: Icon(Icons.remove_red_eye),
title: Text(tr("Members list visibility")),
title: Text(tr("Members list visibility")!),
subtitle:
Text(group.isMembersListPublic ? tr("Public") : tr("Private")),
Text(group.isMembersListPublic! ? tr("Public")! : tr("Private")!),
),
group.isForezGroup
? // Group members visibility
ListTile(
leading: Icon(Icons.info_outline),
title: Text(tr("Forez group")),
subtitle: Text(tr("Forez special features enabled")),
title: Text(tr("Forez group")!),
subtitle: Text(tr("Forez special features enabled")!),
)
: Container(),
],

View File

@ -16,8 +16,8 @@ class ForezPresenceSection extends StatefulWidget {
final int groupID;
const ForezPresenceSection({
Key key,
@required this.groupID,
Key? key,
required this.groupID,
}) : assert(groupID != null),
super(key: key);
@ -26,17 +26,17 @@ class ForezPresenceSection extends StatefulWidget {
}
class _ForezPresenceSectionState extends State<ForezPresenceSection> {
PresenceSet _presences;
UsersList _users;
PresenceSet? _presences;
late UsersList _users;
DateTime _currentDay = DateTime.now();
List<int> get _currentListOfUsers => _presences.getUsersAtDate(_currentDay);
List<int> get _currentListOfUsers => _presences!.getUsersAtDate(_currentDay);
Future<void> _refresh() async {
await ForezPresenceHelper.refreshCache(widget.groupID);
_presences = await ForezPresenceHelper.getAll(widget.groupID);
_users = await UsersHelper().getList(_presences.usersID);
_users = await UsersHelper().getList(_presences!.usersID);
}
@override
@ -71,7 +71,7 @@ class _ForezPresenceSectionState extends State<ForezPresenceSection> {
}
Widget _buildCalendar() => PresenceCalendarWidget(
presenceSet: _presences,
presenceSet: _presences!,
mode: CalendarDisplayMode.MULTIPLE_USERS,
selectedDay: _currentDay,
onDayClicked: _selectDay,

View File

@ -12,8 +12,8 @@ class GroupConversationSection extends StatelessWidget {
final Conversation conv;
const GroupConversationSection({
Key key,
@required this.conv,
Key? key,
required this.conv,
}) : assert(conv != null),
super(key: key);
@ -21,7 +21,7 @@ class GroupConversationSection extends StatelessWidget {
Widget build(BuildContext context) => Stack(
children: [
ConversationScreen(
conversationID: conv.id,
conversationID: conv.id!,
),
Positioned(
right: 1.0,
@ -31,12 +31,12 @@ class GroupConversationSection extends StatelessWidget {
? IconButton(
icon: Icon(Icons.phone),
onPressed: () =>
MainController.of(context).startCall(conv.id),
MainController.of(context)!.startCall(conv.id!),
)
: Container(),
IconButton(
icon: Icon(Icons.settings),
onPressed: () => MainController.of(context)
onPressed: () => MainController.of(context)!
.openConversationSettingsRoute(conv),
),
],

View File

@ -21,7 +21,7 @@ import 'package:flutter/material.dart';
class GroupMembersSection extends StatefulWidget {
final int groupID;
const GroupMembersSection({Key key, this.groupID})
const GroupMembersSection({Key? key, required this.groupID})
: assert(groupID != null),
super(key: key);
@ -31,9 +31,9 @@ class GroupMembersSection extends StatefulWidget {
class _GroupMembersSectionState extends State<GroupMembersSection> {
final _key = GlobalKey<AsyncScreenWidgetState>();
Group _group;
GroupMembersList _members;
UsersList _users;
late Group _group;
late GroupMembersList _members;
late UsersList _users;
Future<void> _refresh() async {
final group = await GroupsHelper().getSingle(widget.groupID, force: true);
@ -50,7 +50,7 @@ class _GroupMembersSectionState extends State<GroupMembersSection> {
key: _key,
onReload: _refresh,
onBuild: _buildBodyContent,
errorMessage: tr("Could not load the list of members of this group!"),
errorMessage: tr("Could not load the list of members of this group!")!,
showOldDataWhileUpdating: true,
);
@ -70,7 +70,7 @@ class _GroupMembersSectionState extends State<GroupMembersSection> {
group: _group,
membership: membership,
user: user,
onUpdated: () => _key.currentState.refresh(),
onUpdated: () => _key.currentState!.refresh(),
);
}
@ -93,40 +93,40 @@ class _GroupMembersSectionState extends State<GroupMembersSection> {
await GroupsHelper.sendInvitation(widget.groupID, userID);
} catch (e, s) {
print("Could not invite a user! $e\n$s");
showSimpleSnack(context, tr("Could not invite a user!"));
showSimpleSnack(context, tr("Could not invite a user!")!);
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
}
List<MultiChoiceEntry<GroupMembershipLevel>> get _membershipLevels => [
MultiChoiceEntry(
id: GroupMembershipLevel.ADMINISTRATOR,
title: tr("Administrator"),
title: tr("Administrator")!,
subtitle: tr("Can change members privileges and group settings")),
MultiChoiceEntry(
id: GroupMembershipLevel.MODERATOR,
title: tr("Moderator"),
title: tr("Moderator")!,
subtitle: tr(
"Can always create posts, invite users and respond to membership request")),
MultiChoiceEntry(
id: GroupMembershipLevel.MEMBER,
title: tr("Member"),
title: tr("Member")!,
subtitle: tr("Can access to all group posts")),
MultiChoiceEntry(
id: GroupMembershipLevel.PENDING,
title: tr("Requested"),
title: tr("Requested")!,
hidden: true,
),
MultiChoiceEntry(
id: GroupMembershipLevel.INVITED,
title: tr("Invited"),
title: tr("Invited")!,
hidden: true,
),
MultiChoiceEntry(
id: GroupMembershipLevel.VISITOR,
title: tr("Visitor"),
title: tr("Visitor")!,
hidden: true,
),
];
@ -138,11 +138,11 @@ class _GroupMembershipTile extends StatefulWidget {
final void Function() onUpdated;
const _GroupMembershipTile({
Key key,
@required this.group,
@required this.membership,
@required this.user,
@required this.onUpdated,
Key? key,
required this.group,
required this.membership,
required this.user,
required this.onUpdated,
}) : assert(group != null),
assert(membership != null),
assert(user != null),
@ -176,7 +176,7 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
);
}
Widget _buildTrailing() {
Widget? _buildTrailing() {
switch (widget.membership.level) {
case GroupMembershipLevel.ADMINISTRATOR:
case GroupMembershipLevel.MODERATOR:
@ -205,14 +205,14 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
itemBuilder: (c) => [
// Change membership level
PopupMenuItem(
child: Text(tr("Change level")),
child: Text(tr("Change level")!),
enabled: !_isCurrentUser && widget.group.isAdmin,
value: _MemberMenuOptions.CHANGE_LEVEL,
),
// Remove membership
PopupMenuItem(
child: Text(tr("Remove")),
child: Text(tr("Remove")!),
value: _MemberMenuOptions.DELETE,
enabled: !_isCurrentUser,
),
@ -247,7 +247,7 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
await GroupsHelper.setNewLevel(groupID, memberID, newLevel);
} catch (e, s) {
print("Could not change group membership level! $e\n$s");
showSimpleSnack(context, tr("Could not change group membership level!"));
showSimpleSnack(context, tr("Could not change group membership level!")!);
}
widget.onUpdated();
@ -263,7 +263,7 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
await GroupsHelper.removeMemberFromGroup(groupID, memberID);
} catch (e, s) {
print("Could not remove membership! $e\n$s");
showSimpleSnack(context, tr("Could not remove this membership!"));
showSimpleSnack(context, tr("Could not remove this membership!")!);
}
widget.onUpdated();
@ -272,7 +272,7 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
Widget _buildInvitedCase() {
return MaterialButton(
onPressed: _cancelMembership,
child: Text(tr("Cancel").toUpperCase()),
child: Text(tr("Cancel")!.toUpperCase()),
textColor: Colors.red,
);
}
@ -282,7 +282,7 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
await GroupsHelper.cancelInvitation(groupID, memberID);
} catch (e, s) {
print("Could not cancel invitation! $e\n$s");
showSimpleSnack(context, tr("Could not cancel invitation!"));
showSimpleSnack(context, tr("Could not cancel invitation!")!);
}
widget.onUpdated();
@ -294,12 +294,12 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
children: <Widget>[
MaterialButton(
onPressed: () => _respondRequest(false),
child: Text(tr("Reject").toUpperCase()),
child: Text(tr("Reject")!.toUpperCase()),
textColor: Colors.red,
),
MaterialButton(
onPressed: () => _respondRequest(true),
child: Text(tr("Accept").toUpperCase()),
child: Text(tr("Accept")!.toUpperCase()),
textColor: Colors.green,
)
],
@ -311,7 +311,7 @@ class __GroupMembershipTileState extends State<_GroupMembershipTile> {
await GroupsHelper.respondRequest(groupID, memberID, accept);
} catch (e, s) {
print("Could not respond to membership request! $e\n$s");
showSimpleSnack(context, tr("Could not respond to membership request!"));
showSimpleSnack(context, tr("Could not respond to membership request!")!);
}
widget.onUpdated();

View File

@ -12,8 +12,8 @@ class GroupPostsSection extends StatefulWidget {
final AdvancedGroupInfo group;
const GroupPostsSection({
Key key,
@required this.group,
Key? key,
required this.group,
}) : assert(group != null),
super(key: key);
@ -31,7 +31,7 @@ class _GroupPostsSectionState extends State<GroupPostsSection> {
return PostCreateFormWidget(
postTarget: PostTarget.GROUP_PAGE,
targetID: widget.group.id,
onCreated: () => _postsKey.currentState.loadPostsList(getOlder: false),
onCreated: () => _postsKey.currentState!.loadPostsList(getOlder: false),
);
}

View File

@ -34,7 +34,7 @@ import 'package:flutter_settings_ui/flutter_settings_ui.dart';
class GroupSettingsScreen extends StatefulWidget {
final int groupID;
const GroupSettingsScreen({Key key, @required this.groupID})
const GroupSettingsScreen({Key? key, required this.groupID})
: assert(groupID != null),
super(key: key);
@ -43,7 +43,7 @@ class GroupSettingsScreen extends StatefulWidget {
}
class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
AdvancedGroupInfo _groupSettings;
AdvancedGroupInfo? _groupSettings;
final _key = GlobalKey<AsyncScreenWidgetState>();
@ -53,13 +53,13 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
Future<void> _updateSettings() async {
try {
await GroupsHelper.setSettings(_groupSettings);
await GroupsHelper.setSettings(_groupSettings!);
} catch (e, stack) {
print("Could not update group settings! $e\n$stack");
showSimpleSnack(context, tr("Could not update group settings!"));
showSimpleSnack(context, tr("Could not update group settings!")!);
}
_key.currentState.refresh();
_key.currentState!.refresh();
}
@override
@ -67,7 +67,7 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
return Scaffold(
appBar: AppBar(
leading: ComunicBackButton(),
title: Text(tr("Group settings")),
title: Text(tr("Group settings")!),
),
body: _buildBody(),
);
@ -78,7 +78,7 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
key: _key,
onReload: _refresh,
onBuild: _buildContent,
errorMessage: tr("Could not get group settings!"),
errorMessage: tr("Could not get group settings!")!,
showOldDataWhileUpdating: true,
);
}
@ -96,65 +96,65 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
);
}
Widget _buildGeneralSection() {
SettingsSection _buildGeneralSection() {
return SettingsSection(
title: tr("General information"),
tiles: [
// Group ID
SettingsTile(
title: tr("Group ID"),
subtitle: _groupSettings.id.toString(),
subtitle: _groupSettings!.id.toString(),
),
// Group name
TextEditSettingsTile(
title: tr("Group name"),
currValue: _groupSettings.name,
title: tr("Group name")!,
currValue: _groupSettings!.name,
onChanged: (s) {
_groupSettings.name = s;
_groupSettings!.name = s;
_updateSettings();
}),
// Group virtual directory
SettingsTile(
title: tr("Virtual directory (optional)"),
subtitle: _groupSettings.virtualDirectory,
subtitle: _groupSettings!.virtualDirectory,
onPressed: (_) async {
final newDir = await showVirtualDirectoryDialog(
context: context,
initialDirectory: _groupSettings.virtualDirectory,
id: _groupSettings.id,
initialDirectory: _groupSettings!.virtualDirectory,
id: _groupSettings!.id,
type: VirtualDirectoryTargetType.GROUP,
);
if (newDir == null) return;
_groupSettings.virtualDirectory = newDir;
_groupSettings!.virtualDirectory = newDir;
_updateSettings();
},
),
// Group URL
TextEditSettingsTile(
title: tr("Group URL (optional)"),
currValue: _groupSettings.url,
title: tr("Group URL (optional)")!,
currValue: _groupSettings!.url,
checkInput: validateUrl,
allowEmptyValues: true,
onChanged: (s) {
_groupSettings.url = s;
_groupSettings!.url = s;
_updateSettings();
},
),
// Group description
TextEditSettingsTile(
title: tr("Group description (optional)"),
currValue: _groupSettings.description,
title: tr("Group description (optional)")!,
currValue: _groupSettings!.description,
maxLines: 3,
maxLength: 255,
allowEmptyValues: true,
onChanged: (s) {
_groupSettings.description = s;
_groupSettings!.description = s;
_updateSettings();
}),
],
@ -164,18 +164,18 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
List<MultiChoiceEntry<GroupVisibilityLevel>> get _visibilityLevels => [
MultiChoiceEntry(
id: GroupVisibilityLevel.OPEN,
title: tr("Open group"),
title: tr("Open group")!,
subtitle:
tr("Group information & public posts are available to everyone."),
),
MultiChoiceEntry(
id: GroupVisibilityLevel.PRIVATE,
title: tr("Private group"),
title: tr("Private group")!,
subtitle: tr("The group is accessible to accepted members only."),
),
MultiChoiceEntry(
id: GroupVisibilityLevel.SECRETE,
title: tr("Secrete group"),
title: tr("Secrete group")!,
subtitle: tr("The group is visible only to invited members."),
),
];
@ -183,19 +183,19 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
List<MultiChoiceEntry<GroupRegistrationLevel>> get _registrationLevels => [
MultiChoiceEntry(
id: GroupRegistrationLevel.OPEN,
title: tr("Open registration"),
title: tr("Open registration")!,
subtitle: tr(
"Everyone can choose to join the group without moderator approval"),
),
MultiChoiceEntry(
id: GroupRegistrationLevel.MODERATED,
title: tr("Moderated registration"),
title: tr("Moderated registration")!,
subtitle: tr(
"Everyone can request a membership, but a moderator review the request"),
),
MultiChoiceEntry(
id: GroupRegistrationLevel.CLOSED,
title: tr("Closed registration"),
title: tr("Closed registration")!,
subtitle: tr(
"The only way to join the group is to be invited by a moderator"),
),
@ -204,48 +204,48 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
List<MultiChoiceEntry<GroupPostCreationLevel>> get _postsCreationLevels => [
MultiChoiceEntry(
id: GroupPostCreationLevel.MEMBERS,
title: tr("All members"),
title: tr("All members")!,
subtitle:
tr("All the members of the group can create posts on the group"),
),
MultiChoiceEntry(
id: GroupPostCreationLevel.MODERATORS,
title: tr("Moderators only"),
title: tr("Moderators only")!,
subtitle: tr(
"Only moderators and administrators of the group can create posts on it"),
),
];
Widget _buildAccessRestrictions() => SettingsSection(
SettingsSection _buildAccessRestrictions() => SettingsSection(
title: tr("Access restrictions"),
tiles: [
// Group visibility
MultiChoicesSettingsTile(
title: tr("Group visibility"),
title: tr("Group visibility")!,
choices: _visibilityLevels,
currentValue: _groupSettings.visibilityLevel,
onChanged: (v) {
_groupSettings.visibilityLevel = v;
currentValue: _groupSettings!.visibilityLevel,
onChanged: (dynamic v) {
_groupSettings!.visibilityLevel = v;
_updateSettings();
}),
// Group registration level
MultiChoicesSettingsTile(
title: tr("Group registration level"),
title: tr("Group registration level")!,
choices: _registrationLevels,
currentValue: _groupSettings.registrationLevel,
onChanged: (v) {
_groupSettings.registrationLevel = v;
currentValue: _groupSettings!.registrationLevel,
onChanged: (dynamic v) {
_groupSettings!.registrationLevel = v;
_updateSettings();
}),
// Group posts creation levels
MultiChoicesSettingsTile(
title: tr("Posts creation level"),
title: tr("Posts creation level")!,
choices: _postsCreationLevels,
currentValue: _groupSettings.postCreationLevel,
onChanged: (s) {
_groupSettings.postCreationLevel = s;
currentValue: _groupSettings!.postCreationLevel,
onChanged: (dynamic s) {
_groupSettings!.postCreationLevel = s;
_updateSettings();
}),
@ -253,10 +253,10 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
SettingsTile.switchTile(
title: tr("Make members list public"),
onToggle: (s) {
_groupSettings.isMembersListPublic = s;
_groupSettings!.isMembersListPublic = s;
_updateSettings();
},
switchValue: _groupSettings.isMembersListPublic,
switchValue: _groupSettings!.isMembersListPublic,
titleMaxLines: 2,
)
],
@ -266,19 +266,19 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
get _conversationMinMembershipLevel => [
MultiChoiceEntry(
id: GroupMembershipLevel.ADMINISTRATOR,
title: tr("Administrators only"),
title: tr("Administrators only")!,
subtitle: tr(
"Only the administrators of the group can access the conversation"),
),
MultiChoiceEntry(
id: GroupMembershipLevel.MODERATOR,
title: tr("Moderators and administrators"),
title: tr("Moderators and administrators")!,
subtitle: tr(
"Only moderators and administrators of the group can access the conversation"),
),
MultiChoiceEntry(
id: GroupMembershipLevel.MEMBER,
title: tr("All members"),
title: tr("All members")!,
subtitle: tr(
"All the members of the group can access the conversation"),
),
@ -286,17 +286,17 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
SettingsSection _buildConversationsArea() => SettingsSection(
title: tr("Group conversations"),
tiles: _groupSettings.conversations
tiles: _groupSettings!.conversations!
.map(
(e) {
SettingsTile tile =
MultiChoicesSettingsTile<GroupMembershipLevel>(
title: e.name,
MultiChoicesSettingsTile<GroupMembershipLevel?>(
title: e.name!,
choices: _conversationMinMembershipLevel,
currentValue: e.groupMinMembershipLevel,
leading: e.hasLogo
? CachedNetworkImage(
imageUrl: e.logoURL,
imageUrl: e.logoURL!,
width: 30,
)
: Icon(Icons.group, size: 30),
@ -324,13 +324,13 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
try {
final name = await askUserString(
context: context,
title: tr("New conversation name"),
message: tr("Please give a name to the new conversation"),
title: tr("New conversation name")!,
message: tr("Please give a name to the new conversation")!,
defaultValue: "",
hint: tr("Name"),
hint: tr("Name")!,
minLength: 1,
maxLength: ServerConfigurationHelper
.config.conversationsPolicy.maxConversationNameLen,
.config!.conversationsPolicy.maxConversationNameLen,
);
if (name == null) return;
@ -345,27 +345,27 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
if (visibility == null) return;
await GroupsHelper.createGroupConversation(NewGroupConversation(
groupID: _groupSettings.id,
groupID: _groupSettings!.id,
name: name,
minMembershipLevel: visibility,
));
_key.currentState.refresh();
_key.currentState!.refresh();
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to create a conversation!"));
snack(context, tr("Failed to create a conversation!")!);
}
}
void _changeConversationVisibility(
Conversation conv, GroupMembershipLevel newLevel) async {
Conversation conv, GroupMembershipLevel? newLevel) async {
try {
await GroupsHelper.setConversationVisibility(conv.id, newLevel);
_key.currentState.refresh();
_key.currentState!.refresh();
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to change conversation visibility level!"));
snack(context, tr("Failed to change conversation visibility level!")!);
}
}
@ -378,21 +378,21 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
await GroupsHelper.deleteConversation(conv.id);
_key.currentState.refresh();
_key.currentState!.refresh();
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to delete conversation!"));
snack(context, tr("Failed to delete conversation!")!);
}
}
Widget _buildGroupLogoArea() {
SettingsSection _buildGroupLogoArea() {
return SettingsSection(
title: tr("Group logo"),
tiles: [
// Current logo
SettingsTile(
title: tr("Current logo"),
leading: GroupIcon(group: _groupSettings),
leading: GroupIcon(group: _groupSettings!),
),
// Upload a new logo
@ -421,10 +421,10 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
try {
final logo = await pickImage(context);
if (logo == null) return;
await _doUploadLogo(logo.bytes);
await _doUploadLogo(logo.bytes as Uint8List?);
} catch (e, stack) {
print("Could not upload new logo! $e\n$stack");
showSimpleSnack(context, tr("Could not upload new logo!"));
showSimpleSnack(context, tr("Could not upload new logo!")!);
}
}
@ -435,13 +435,13 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
await _doUploadLogo(newLogo);
} catch (e, stack) {
print("Could not generate new logo! $e\n$stack");
showSimpleSnack(context, tr("Could not generate new random logo!"));
showSimpleSnack(context, tr("Could not generate new random logo!")!);
}
}
Future<void> _doUploadLogo(Uint8List bytes) async {
await GroupsHelper.uploadNewLogo(_groupSettings.id, bytes);
_key.currentState.refresh();
Future<void> _doUploadLogo(Uint8List? bytes) async {
await GroupsHelper.uploadNewLogo(_groupSettings!.id, bytes);
_key.currentState!.refresh();
}
/// Delete previous group logo
@ -452,15 +452,15 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
message: tr("Do you really want to delete the logo of this group ?")))
return;
await GroupsHelper.deleteLogo(_groupSettings.id);
_key.currentState.refresh();
await GroupsHelper.deleteLogo(_groupSettings!.id);
_key.currentState!.refresh();
} catch (e, s) {
print("Could not delete group logo! $e\n$s");
showSimpleSnack(context, tr("Could not delete group logo!"));
showSimpleSnack(context, tr("Could not delete group logo!")!);
}
}
Widget _buildDangerZone() {
SettingsSection _buildDangerZone() {
return SettingsSection(
title: tr("Danger zone"),
tiles: [
@ -485,12 +485,12 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
"Do you really want to delete this group ? All the posts related to it will be permanently deleted!")))
return;
await GroupsHelper.deleteGroup(_groupSettings.id, password);
await GroupsHelper.deleteGroup(_groupSettings!.id, password);
MainController.of(context).popPage();
MainController.of(context)!.popPage();
} catch (e, s) {
print("Could not delete the group! $e\n$s");
showSimpleSnack(context, tr("Could not delete the group"));
showSimpleSnack(context, tr("Could not delete the group")!);
}
}
}

View File

@ -19,7 +19,7 @@ class GroupsListScreen extends StatefulWidget {
}
class _GroupsListScreenState extends SafeState<GroupsListScreen> {
GroupsList _groups;
GroupsList? _groups;
bool _error = false;
final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
@ -41,7 +41,7 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
hide: !_error,
actions: [
MaterialButton(
child: Text(tr("Try again").toUpperCase()),
child: Text(tr("Try again")!.toUpperCase()),
onPressed: () => _refreshList(),
),
],
@ -61,19 +61,19 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
}
Widget _buildGroupsList() => ListView(
children: (_groups.values.toList()
children: (_groups!.values.toList()
..sort((one, two) => two.id.compareTo(one.id)))
.map((g) => ListTile(
leading: GroupIcon(group: g),
title: Text(g.displayName),
subtitle: GroupMembershipWidget(
group: g,
onUpdated: () => _refreshIndicatorKey.currentState.show(),
onUpdated: () => _refreshIndicatorKey.currentState!.show(),
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _deleteGroup(g)),
onTap: () => MainController.of(context).openGroup(g.id),
onTap: () => MainController.of(context)!.openGroup(g.id),
))
.toList(),
);
@ -116,10 +116,10 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
if (!await GroupsHelper().removeMembership(g.id))
showSimpleSnack(
context, tr("Could not remove your membership to this group!"));
context, tr("Could not remove your membership to this group!")!);
// Refresh the list of groups
_refreshIndicatorKey.currentState.show();
_refreshIndicatorKey.currentState!.show();
}
/// Add a group
@ -127,10 +127,10 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
try {
final name = await askUserString(
context: context,
title: tr("Group name"),
message: tr("Name of the group to create"),
title: tr("Group name")!,
message: tr("Name of the group to create")!,
defaultValue: "",
hint: tr("Name of the group"),
hint: tr("Name of the group")!,
maxLength: 50,
);
@ -138,10 +138,10 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
final groupID = await GroupsHelper.create(name);
MainController.of(context).openGroup(groupID);
MainController.of(context)!.openGroup(groupID);
} catch (e, s) {
print("Could not create a new group! $e\n$s");
showSimpleSnack(context, tr("Could not create a new group!"));
showSimpleSnack(context, tr("Could not create a new group!")!);
}
}
}

View File

@ -28,7 +28,7 @@ class NotificationsScreen extends StatefulWidget {
final bool useSmallDeleteButton;
const NotificationsScreen({
Key key,
Key? key,
this.useSmallDeleteButton = false,
}) : assert(useSmallDeleteButton != null),
super(key: key);
@ -38,9 +38,9 @@ class NotificationsScreen extends StatefulWidget {
}
class _NotificationsScreenState extends SafeState<NotificationsScreen> {
NotificationsList _list;
UsersList _users;
GroupsList _groups;
NotificationsList? _list;
late UsersList _users;
late GroupsList _groups;
_Status _status = _Status.LOADING;
final _refreshKey = GlobalKey<RefreshIndicatorState>();
@ -64,12 +64,12 @@ class _NotificationsScreenState extends SafeState<NotificationsScreen> {
});
setStatus(_Status.NONE);
} on Exception catch (e) {
} on Exception catch (e, s) {
print("Exception while getting the list of notifications!");
print(e);
} on Error catch (e) {
print("$e, $s");
} on Error catch (e, s) {
print("Error while getting the list of notifications!");
print(e.stackTrace);
print("$e, $s");
}
}
@ -77,7 +77,7 @@ class _NotificationsScreenState extends SafeState<NotificationsScreen> {
void initState() {
super.initState();
this.listen<NewNumberNotifsEvent>((d) => _refreshKey.currentState.show());
this.listen<NewNumberNotifsEvent>((d) => _refreshKey.currentState!.show());
}
@override
@ -121,14 +121,14 @@ class _NotificationsScreenState extends SafeState<NotificationsScreen> {
/// Build body
Widget _buildBody() {
if (_status == _Status.ERROR || _list.length == 0)
if (_status == _Status.ERROR || _list!.length == 0)
return SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: _buildSingleChildCases(),
);
return ListView(
children: _list
children: _list!
.map((f) => _NotificationTile(
notification: f,
usersList: _users,
@ -146,16 +146,16 @@ class _NotificationsScreenState extends SafeState<NotificationsScreen> {
actions: [
MaterialButton(
onPressed: () => _loadList(),
child: Text(tr("Try again".toUpperCase())),
child: Text(tr("Try again".toUpperCase())!),
)
]);
// When there is no notification
if (_list.length == 0)
if (_list!.length == 0)
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(tr("You do not have any notification now.")),
child: Text(tr("You do not have any notification now.")!),
),
);
@ -165,7 +165,7 @@ class _NotificationsScreenState extends SafeState<NotificationsScreen> {
/// Delete a notification
void _deleteNotification(n.Notification notif) async {
setState(() {
_list.remove(notif);
_list!.remove(notif);
});
NotificationsHelper().markSeen(notif);
@ -179,11 +179,11 @@ class _NotificationsScreenState extends SafeState<NotificationsScreen> {
return;
if (!await NotificationsHelper().deleteAllNotifications()) {
showSimpleSnack(context, tr("Could not delete all your notifications!"));
showSimpleSnack(context, tr("Could not delete all your notifications!")!);
return;
}
_refreshKey.currentState.show();
_refreshKey.currentState!.show();
}
}
@ -194,11 +194,11 @@ class _NotificationTile extends StatelessWidget {
final void Function(n.Notification) onDelete;
const _NotificationTile({
Key key,
@required this.notification,
@required this.usersList,
@required this.groupsList,
@required this.onDelete,
Key? key,
required this.notification,
required this.usersList,
required this.groupsList,
required this.onDelete,
}) : assert(notification != null),
assert(usersList != null),
assert(groupsList != null),
@ -214,51 +214,51 @@ class _NotificationTile extends StatelessWidget {
switch (notification.type) {
// Comment
case n.NotificationType.COMMENT_CREATED:
message += tr("posted a comment");
message += tr("posted a comment")!;
break;
// Friendship requests
case n.NotificationType.SENT_FRIEND_REQUEST:
message += tr("sent you a friendship request.");
message += tr("sent you a friendship request.")!;
break;
case n.NotificationType.ACCEPTED_FRIEND_REQUEST:
message += tr("accepted your friendship request.");
message += tr("accepted your friendship request.")!;
break;
case n.NotificationType.REJECTED_FRIEND_REQUEST:
message += tr("rejected your friendship request.");
message += tr("rejected your friendship request.")!;
break;
// Groups membership
case n.NotificationType.SENT_GROUP_MEMBERSHIP_INVITATION:
message += tr("invited you to join the group");
message += tr("invited you to join the group")!;
break;
case n.NotificationType.ACCEPTED_GROUP_MEMBERSHIP_INVITATION:
message += tr("accepted his invitation to join the group");
message += tr("accepted his invitation to join the group")!;
break;
case n.NotificationType.REJECTED_GROUP_MEMBERSHIP_INVITATION:
message += tr("rejected his invitation to join the group");
message += tr("rejected his invitation to join the group")!;
break;
case n.NotificationType.SENT_GROUP_MEMBERSHIP_REQUEST:
message += tr("sent a request to join the group");
message += tr("sent a request to join the group")!;
break;
case n.NotificationType.ACCEPTED_GROUP_MEMBERSHIP_REQUEST:
message += tr("accepted you request to join the group");
message += tr("accepted you request to join the group")!;
break;
case n.NotificationType.REJECTED_GROUP_MEMBERSHIP_REQUEST:
message += tr("rejected your request to join the group");
message += tr("rejected your request to join the group")!;
break;
// Generic element creation
case n.NotificationType.ELEM_CREATED:
if (notification.onElemType == n.NotificationElementType.POST)
message += tr("created a new post");
message += tr("created a new post")!;
break;
case n.NotificationType.ELEM_UPDATED:
@ -274,24 +274,24 @@ class _NotificationTile extends StatelessWidget {
// User page
if (notification.fromContainerType == n.NotificationElementType.USER_PAGE) {
if (notification.fromUser == notification.fromContainerId)
message += tr("on his / her page");
message += tr("on his / her page")!;
else
message += tr("on %user_name%'s page", args: {
"user_name": usersList.getUser(notification.fromContainerId).fullName
});
})!;
}
// Group page
if (notification.fromContainerType ==
n.NotificationElementType.GROUP_PAGE) {
message += tr("on the group %group%.", args: {
"group": groupsList[notification.fromContainerId].displayName
});
"group": groupsList[notification.fromContainerId]!.displayName
})!;
}
// Group membership
if (notification.onElemType == n.NotificationElementType.GROUP_MEMBERSHIP)
message += groupsList[notification.onElemId].displayName;
message += groupsList[notification.onElemId]!.displayName;
return CustomListTile(
leading: AccountImageWidget(
@ -299,11 +299,11 @@ class _NotificationTile extends StatelessWidget {
),
onTap: () => _onTap(context),
title: Text(message),
subtitle: Text(diffTimeFromNowToStr(notification.timeCreate)),
subtitle: Text(diffTimeFromNowToStr(notification.timeCreate)!),
onLongPressOpenMenu: (position) {
showMenu(context: context, position: position, items: [
PopupMenuItem(
child: Text(tr("Delete")),
child: Text(tr("Delete")!),
value: _PopupMenuActions.DELETE,
),
]).then(_popupMenuAction);
@ -311,7 +311,7 @@ class _NotificationTile extends StatelessWidget {
);
}
void _popupMenuAction(_PopupMenuActions value) {
void _popupMenuAction(_PopupMenuActions? value) {
switch (value) {
case _PopupMenuActions.DELETE:
onDelete(notification);
@ -327,10 +327,10 @@ class _NotificationTile extends StatelessWidget {
openUserPage(userID: notification.fromUser, context: context);
} else if (notification.onElemType ==
n.NotificationElementType.GROUP_MEMBERSHIP) {
MainController.of(context).openGroup(notification.onElemId);
MainController.of(context)!.openGroup(notification.onElemId);
} else {
showSimpleSnack(context,
tr("This kind of notification is not supported yet by this application."));
tr("This kind of notification is not supported yet by this application.")!);
return;
}

View File

@ -16,8 +16,8 @@ class OtherUserFriendsListScreen extends StatefulWidget {
final bool enableAppBar;
const OtherUserFriendsListScreen({
Key key,
@required this.userID,
Key? key,
required this.userID,
this.enableAppBar = true,
}) : assert(userID != null),
assert(enableAppBar != null),
@ -33,12 +33,12 @@ class _OtherUserFriendsListScreenState
final FriendsHelper friendsHelper = FriendsHelper();
final UsersHelper usersHelper = UsersHelper();
Set<int> _friendsList;
UsersList _usersInfo;
late Set<int> _friendsList;
UsersList? _usersInfo;
bool _error = false;
String get _routeName => tr("Friends of %name%",
args: {"name": _usersInfo.getUser(widget.userID).displayName});
String? get _routeName => tr("Friends of %name%",
args: {"name": _usersInfo!.getUser(widget.userID).displayName});
void setError(bool e) => setState(() => _error = e);
@ -79,16 +79,16 @@ class _OtherUserFriendsListScreenState
return Scaffold(
appBar: widget.enableAppBar
? AppBar(
title: Text(_routeName),
title: Text(_routeName!),
)
: null,
body: ListView.builder(
itemCount: _friendsList.length,
itemBuilder: (c, i) => SimpleUserTile(
user: _usersInfo.getUser(_friendsList.elementAt(i)),
user: _usersInfo!.getUser(_friendsList.elementAt(i)),
onTap: (u) => openUserPage(
context: context,
userID: u.id,
userID: u.id!,
),
),
),
@ -104,7 +104,7 @@ class _OtherUserFriendsListScreenState
actions: [
TextButton(
child: Text(
tr("Try again").toUpperCase(),
tr("Try again")!.toUpperCase(),
style: TextStyle(color: Colors.white),
),
onPressed: load,

View File

@ -24,9 +24,9 @@ class SearchScreen extends StatefulWidget {
}
class _SearchScreenState extends State<SearchScreen> {
SearchResultsList _searchResultsList;
UsersList _usersList;
GroupsList _groupsList;
SearchResultsList? _searchResultsList;
late UsersList _usersList;
late GroupsList _groupsList;
@override
Widget build(BuildContext context) {
@ -44,13 +44,13 @@ class _SearchScreenState extends State<SearchScreen> {
? Container()
: Expanded(
child: ListView(
children: _searchResultsList
children: _searchResultsList!
.map((f) => f.kind == SearchResultKind.USER
? _SearchResultUser(
user: _usersList.getUser(f.id),
)
: _SearchResultGroup(
group: _groupsList[f.id],
group: _groupsList[f.id]!,
))
.toList(),
),
@ -78,7 +78,7 @@ class _SearchScreenState extends State<SearchScreen> {
print(e);
print(stack);
showSimpleSnack(context, tr("Could not peform search!"));
showSimpleSnack(context, tr("Could not peform search!")!);
}
}
}
@ -86,7 +86,7 @@ class _SearchScreenState extends State<SearchScreen> {
class _SearchResultUser extends StatelessWidget {
final User user;
const _SearchResultUser({Key key, this.user})
const _SearchResultUser({Key? key, required this.user})
: assert(user != null),
super(key: key);
@ -97,7 +97,7 @@ class _SearchResultUser extends StatelessWidget {
user: user,
),
title: Text(user.displayName),
onTap: () => MainController.of(context).openUserPage(user.id),
onTap: () => MainController.of(context)!.openUserPage(user.id!),
);
}
}
@ -105,7 +105,7 @@ class _SearchResultUser extends StatelessWidget {
class _SearchResultGroup extends StatelessWidget {
final Group group;
const _SearchResultGroup({Key key, this.group})
const _SearchResultGroup({Key? key, required this.group})
: assert(group != null),
super(key: key);
@ -114,8 +114,8 @@ class _SearchResultGroup extends StatelessWidget {
return ListTile(
leading: GroupIcon(group: group),
title: Text(group.displayName),
subtitle: Text(tr("Group")),
onTap: () => MainController.of(context).openGroup(group.id),
subtitle: Text(tr("Group")!),
onTap: () => MainController.of(context)!.openGroup(group.id),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/groups_list.dart';
import 'package:comunic/lists/unread_conversations_list.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/unread_conversation.dart';
import 'package:comunic/ui/routes/main_route/main_route.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart';
import 'package:comunic/ui/widgets/conversation_image_widget.dart';
@ -25,9 +26,9 @@ class UnreadConversationsScreen extends StatefulWidget {
class _UnreadConversationsScreenState
extends SafeState<UnreadConversationsScreen> {
UnreadConversationsList _list;
UsersList _users;
GroupsList _groups;
late UnreadConversationsList _list;
UsersList? _users;
GroupsList? _groups;
final _key = GlobalKey<AsyncScreenWidgetState>();
@ -41,7 +42,7 @@ class _UnreadConversationsScreenState
void initState() {
super.initState();
listen<NewNumberUnreadConversations>((e) => _key.currentState.refresh());
listen<NewNumberUnreadConversations>((e) => _key.currentState!.refresh());
}
@override
@ -50,7 +51,7 @@ class _UnreadConversationsScreenState
key: _key,
onReload: _refresh,
onBuild: _buildList,
errorMessage: tr("Could not load the list of unread conversations!"),
errorMessage: tr("Could not load the list of unread conversations!")!,
);
}
@ -61,7 +62,7 @@ class _UnreadConversationsScreenState
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
tr("You do not have any unread conversation yet..."),
tr("You do not have any unread conversation yet...")!,
textAlign: TextAlign.center,
),
),
@ -74,34 +75,34 @@ class _UnreadConversationsScreenState
}
Widget _tileBuilder(BuildContext context, int index) {
final conv = _list[index];
final UnreadConversation conv = _list[index];
final message = _list[index].message;
final singleUserConv = conv.conv.members.length < 3;
final singleUserConv = conv.conv.members!.length < 3;
String messageStr;
String? messageStr;
if (message.hasFile)
messageStr = tr("New file");
else if (message.hasMessage)
messageStr = singleUserConv
? message.message.content
: tr("%1% : %2%", args: {
"1": _users.getUser(message.userID).fullName,
"1": _users!.getUser(message.userID).fullName,
"2": message.message.content,
});
else
message.serverMessage.getText(_users);
message.serverMessage!.getText(_users);
return ListTile(
leading: ConversationImageWidget(
conversation: conv.conv,
users: _users,
users: _users!,
group: conv.conv.isGroupConversation
? _groups.getGroup(conv.conv.groupID)
? _groups!.getGroup(conv.conv.groupID)
: null,
),
title: Text(ConversationsHelper.getConversationName(conv.conv, _users)),
title: Text(ConversationsHelper.getConversationName(conv.conv, _users)!),
subtitle: RichText(
text: TextSpan(style: Theme.of(context).textTheme.bodyText2, children: [
TextSpan(
@ -110,9 +111,9 @@ class _UnreadConversationsScreenState
),
]),
),
trailing: Text(diffTimeFromNowToStr(conv.message.timeSent)),
trailing: Text(diffTimeFromNowToStr(conv.message.timeSent!)!),
onTap: () =>
MainController.of(context).openConversationById(conv.conv.id),
MainController.of(context)!.openConversationById(conv.conv.id!),
);
}
}

View File

@ -32,7 +32,7 @@ class UpdateConversationScreen extends StatefulWidget {
final convID;
const UpdateConversationScreen({
Key key,
Key? key,
this.convID,
}) : super(key: key);
@ -41,19 +41,19 @@ class UpdateConversationScreen extends StatefulWidget {
}
class _UpdateConversationScreen extends State<UpdateConversationScreen> {
Conversation _conversation;
late Conversation _conversation;
TextEditingController _nameController = TextEditingController();
TextEditingController _colorController = TextEditingController();
UsersList _members = UsersList();
Set<int> _admins = Set();
Set<int?> _admins = Set();
bool _followConversation = true;
bool _canEveryoneAddMembers = true;
String _image;
bool? _canEveryoneAddMembers = true;
String? _image;
String get _conversationColor => _colorController.text;
Color get _color {
Color? get _color {
if (_conversationColor == null || _conversationColor.isEmpty) return null;
try {
@ -72,7 +72,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
isUpdating && _conversation.isGroupConversation;
bool get _canAddMembers =>
(isAdmin || _conversation.canEveryoneAddMembers) &&
(isAdmin || _conversation.canEveryoneAddMembers!) &&
(!isUpdating || !_conversation.isManaged);
get _isValid => _members.length > 0;
@ -104,8 +104,8 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
appBar: AppBar(
leading: ComunicBackButton(),
title: Text(isUpdating
? tr("Update conversation")
: tr("Create a conversation")),
? tr("Update conversation")!
: tr("Create a conversation")!),
actions: [
IconButton(
icon: Icon(Icons.check),
@ -115,7 +115,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
body: AsyncScreenWidget(
onReload: _init,
onBuild: _buildBody,
errorMessage: tr("Failed to load conversation settings!"),
errorMessage: tr("Failed to load conversation settings!")!,
),
);
@ -126,7 +126,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
child: Column(
children: <Widget>[
_isGroupConversation
? Text(tr("This conversation is managed by a group"))
? Text(tr("This conversation is managed by a group")!)
: Container(),
// Conversation name
@ -163,7 +163,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
_followConversation = b;
}),
),
Text(tr("Follow conversation"))
Text(tr("Follow conversation")!)
],
),
@ -173,7 +173,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
: Row(
children: <Widget>[
Switch.adaptive(
value: _canEveryoneAddMembers,
value: _canEveryoneAddMembers!,
onChanged: isAdmin
? (b) => setState(() {
_canEveryoneAddMembers = b;
@ -182,7 +182,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
),
Flexible(
child: Text(tr(
"Allow all members of the conversation to add users")))
"Allow all members of the conversation to add users")!))
],
),
@ -190,7 +190,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
PickUserWidget(
resetOnChoose: true,
keepFocusOnChoose: true,
label: tr("Add member"),
label: tr("Add member")!,
enabled: _canAddMembers,
onSelectUser: (user) => _addMember(user)),
@ -215,12 +215,12 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
onSelected: (choice) => _membersMenuItemSelected(user, choice),
itemBuilder: (c) => <PopupMenuEntry<_MembersMenuChoices>>[
PopupMenuItem(
child: Text(tr("Toggle admin status")),
child: Text(tr("Toggle admin status")!),
value: _MembersMenuChoices.TOGGLE_ADMIN_STATUS,
enabled: isUpdating && isAdmin && user.id != userID(),
),
PopupMenuItem(
child: Text(tr("Remove")),
child: Text(tr("Remove")!),
value: _MembersMenuChoices.REMOVE,
enabled: isAdmin && user.id != userID(),
),
@ -260,7 +260,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
setState(() => _members.insert(0, user));
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to add member to conversation!"));
snack(context, tr("Failed to add member to conversation!")!);
}
}
@ -275,14 +275,14 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
});
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to remove member!"));
snack(context, tr("Failed to remove member!")!);
}
}
void _toggleAdminStatus(User user) async {
try {
final setAdmin = !_admins.contains(user.id);
await ConversationsHelper.setAdmin(_conversation.id, user.id, setAdmin);
await ConversationsHelper.setAdmin(_conversation.id!, user.id!, setAdmin);
setState(() {
if (!setAdmin)
@ -292,7 +292,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
});
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to toggle admin status of user!"));
snack(context, tr("Failed to toggle admin status of user!")!);
}
}
@ -306,17 +306,17 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
name: _nameController.text,
members: _members.map((element) => element.id).toList(),
follow: _followConversation,
canEveryoneAddMembers: _canEveryoneAddMembers,
color: _color));
canEveryoneAddMembers: _canEveryoneAddMembers!,
color: _color)) ;
MainController.of(context).popPage();
MainController.of(context).openConversationById(conversationID);
MainController.of(context)!.popPage();
MainController.of(context)!.openConversationById(conversationID);
return;
}
// Update conversation settings
final newSettings = NewConversationsSettings(
convID: _conversation.id,
convID: _conversation.id!,
following: _followConversation,
isComplete: isAdmin,
name: _nameController.text,
@ -326,10 +326,10 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
await ConversationsHelper.updateConversation(newSettings);
MainController.of(context).popPage();
MainController.of(context)!.popPage();
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to update conversation settings!"));
snack(context, tr("Failed to update conversation settings!")!);
}
}
@ -337,12 +337,12 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
Widget _buildConversationImageWidget() => Column(
children: [
SizedBox(height: 10),
Text(tr("Conversation logo"),
Text(tr("Conversation logo")!,
style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 5),
_image == null
? Text("No logo defined yet.")
: CachedNetworkImage(imageUrl: _image),
: CachedNetworkImage(imageUrl: _image!),
SizedBox(height: 5),
isAdmin
? Row(
@ -350,14 +350,14 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
children: [
OutlinedButton(
onPressed: _uploadNewLogo,
child: Text(tr("Change logo")),
child: Text(tr("Change logo")!),
),
SizedBox(width: 5),
_image == null
? Container()
: ElevatedButton(
onPressed: _deleteLogo,
child: Text(tr("Delete logo")),
child: Text(tr("Delete logo")!),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.red)),
@ -375,8 +375,8 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
final newLogo = await showPickFileDialog(
context: context,
allowedMimeTypes: ["image/png", "image/jpeg", "image/gif"],
imageMaxWidth: srvConfig.conversationsPolicy.maxLogoWidth,
imageMaxHeight: srvConfig.conversationsPolicy.maxLogoHeight,
imageMaxWidth: srvConfig!.conversationsPolicy.maxLogoWidth,
imageMaxHeight: srvConfig!.conversationsPolicy.maxLogoHeight,
);
if (newLogo == null) return;
@ -388,7 +388,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
setState(() => _image = newConvSettings.logoURL);
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to change conversation logo !"));
snack(context, tr("Failed to change conversation logo !")!);
}
}
@ -404,7 +404,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
setState(() => _image = null);
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to remove conversation logo!"));
snack(context, tr("Failed to remove conversation logo!")!);
}
}
}

View File

@ -17,7 +17,7 @@ import 'package:flutter/material.dart';
class UserAccessDeniedScreen extends StatefulWidget {
final int userID;
const UserAccessDeniedScreen({Key key, @required this.userID})
const UserAccessDeniedScreen({Key? key, required this.userID})
: assert(userID != null),
super(key: key);
@ -31,8 +31,8 @@ class _UserAccessDeniedScreenState extends SafeState<UserAccessDeniedScreen> {
final _key = GlobalKey<AsyncScreenWidgetState>();
FriendStatus _status;
User _user;
late FriendStatus _status;
late User _user;
Future<void> refresh() async {
final status = await friendsHelper.getFriendshipStatus(widget.userID);
@ -40,7 +40,7 @@ class _UserAccessDeniedScreenState extends SafeState<UserAccessDeniedScreen> {
// Check if the two users are friend now
if (status.areFriend) {
final controller = MainController.of(context);
final controller = MainController.of(context)!;
controller.popPage();
controller.openUserPage(widget.userID);
}
@ -55,7 +55,7 @@ class _UserAccessDeniedScreenState extends SafeState<UserAccessDeniedScreen> {
key: _key,
onReload: refresh,
onBuild: _buildPage,
errorMessage: tr("Could not load friendship information!"));
errorMessage: tr("Could not load friendship information!")!);
}
Widget _buildPage() {
@ -77,10 +77,10 @@ class _UserAccessDeniedScreenState extends SafeState<UserAccessDeniedScreen> {
_user.displayName,
style: TextStyle(fontSize: 25.0),
),
Text(tr("This account is private.")),
Text(tr("This account is private.")!),
FriendshipStatusWidget(
status: _status,
onFriendshipUpdated: () => _key.currentState.refresh(),
onFriendshipUpdated: () => _key.currentState!.refresh(),
)
],
),

View File

@ -20,7 +20,7 @@ enum _PageStatus { LOADING, ERROR, READY }
class UserPageScreen extends StatefulWidget {
final int userID;
const UserPageScreen({Key key, @required this.userID})
const UserPageScreen({Key? key, required this.userID})
: assert(userID != null),
super(key: key);
@ -34,8 +34,8 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
// Objects members
_PageStatus _status = _PageStatus.LOADING;
AdvancedUserInfo _userInfo;
FriendStatus _frienshipStatus;
late AdvancedUserInfo _userInfo;
FriendStatus? _frienshipStatus;
final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
_setStatus(_PageStatus s) => setState(() => _status = s);
@ -65,7 +65,7 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
_setStatus(_PageStatus.ERROR);
if (e.cause == GetUserAdvancedInformationErrorCause.NOT_AUTHORIZED) {
final controller = MainController.of(context);
final controller = MainController.of(context)!;
controller.popPage();
controller.openUserAccessDeniedPage(widget.userID);
}
@ -94,7 +94,7 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
Widget _buildError() {
return Scaffold(
appBar: AppBar(
title: Text(tr("Error")),
title: Text(tr("Error")!),
),
body: Center(
child:
@ -102,7 +102,7 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
TextButton(
onPressed: _getUserInfo,
child: Text(
tr("Retry").toUpperCase(),
tr("Retry")!.toUpperCase(),
style: TextStyle(color: Colors.white),
),
)
@ -114,12 +114,12 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
return isTablet(context)
? UserPageTablet(
userInfo: _userInfo,
onNeedRefresh: () => _refreshIndicatorKey.currentState.show(),
onNeedRefresh: () => _refreshIndicatorKey.currentState!.show(),
friendshipStatus: _frienshipStatus,
)
: UserMobilePage(
userInfo: _userInfo,
onNeedRefresh: () => _refreshIndicatorKey.currentState.show(),
onNeedRefresh: () => _refreshIndicatorKey.currentState!.show(),
);
}
}

View File

@ -19,8 +19,8 @@ class AboutUserSection extends StatefulWidget {
final AdvancedUserInfo user;
const AboutUserSection({
Key key,
@required this.user,
Key? key,
required this.user,
}) : assert(user != null),
super(key: key);
@ -29,7 +29,7 @@ class AboutUserSection extends StatefulWidget {
}
class _AboutUserSectionState extends State<AboutUserSection> {
FriendStatus _friendStatus;
late FriendStatus _friendStatus;
final _screenKey = GlobalKey<AsyncScreenWidgetState>();
@ -38,14 +38,14 @@ class _AboutUserSectionState extends State<AboutUserSection> {
_friendStatus = await FriendsHelper().getFriendshipStatus(widget.user.id);
}
void _toggleRefresh() => _screenKey.currentState.refresh();
void _toggleRefresh() => _screenKey.currentState!.refresh();
@override
Widget build(BuildContext context) => AsyncScreenWidget(
key: _screenKey,
onReload: _init,
onBuild: _buildList,
errorMessage: tr("Failed to load user information!"));
errorMessage: tr("Failed to load user information!")!);
Widget _buildList() => ListView(
children: [
@ -58,7 +58,7 @@ class _AboutUserSectionState extends State<AboutUserSection> {
widget.user.hasPersonalWebsite
? ListTile(
leading: Icon(Icons.link),
title: Text(tr("Personal Website")),
title: Text(tr("Personal Website")!),
subtitle: Text(widget.user.personalWebsite),
onTap: () => launch(widget.user.personalWebsite),
)
@ -68,7 +68,7 @@ class _AboutUserSectionState extends State<AboutUserSection> {
widget.user.hasPublicNote
? ListTile(
leading: Icon(Icons.note),
title: Text(tr("Note")),
title: Text(tr("Note")!),
subtitle: TextWidget(
content: DisplayedString(widget.user.publicNote)),
)
@ -78,7 +78,7 @@ class _AboutUserSectionState extends State<AboutUserSection> {
widget.user.hasVirtualDirectory
? ListTile(
leading: Icon(Icons.alternate_email),
title: Text(tr("Virtual directory")),
title: Text(tr("Virtual directory")!),
subtitle: Text("@${widget.user.virtualDirectory}"))
: Container(),
@ -87,10 +87,10 @@ class _AboutUserSectionState extends State<AboutUserSection> {
? Container()
: ListTile(
leading: Icon(Icons.email_outlined),
title: Text(tr("Email address")),
subtitle: Text(widget.user.emailAddress),
title: Text(tr("Email address")!),
subtitle: Text(widget.user.emailAddress!),
onTap: () =>
copyToClipboard(context, widget.user.emailAddress),
copyToClipboard(context, widget.user.emailAddress!),
),
// User location
@ -98,16 +98,16 @@ class _AboutUserSectionState extends State<AboutUserSection> {
? Container()
: ListTile(
leading: Icon(Icons.location_on),
title: Text(tr("Location")),
subtitle: Text(widget.user.location),
onTap: () => copyToClipboard(context, widget.user.location),
title: Text(tr("Location")!),
subtitle: Text(widget.user.location!),
onTap: () => copyToClipboard(context, widget.user.location!),
),
// Number of friends
widget.user.isFriendsListPublic
? ListTile(
leading: Icon(Icons.group),
title: Text(tr("Number of friends")),
title: Text(tr("Number of friends")!),
subtitle: Text(widget.user.numberFriends.toString()),
)
: Container(),
@ -115,20 +115,20 @@ class _AboutUserSectionState extends State<AboutUserSection> {
// Member for
ListTile(
leading: Icon(Icons.access_time_rounded),
title: Text(tr("Member for")),
title: Text(tr("Member for")!),
subtitle:
Text(diffTimeFromNowToStr(widget.user.accountCreationTime)),
Text(diffTimeFromNowToStr(widget.user.accountCreationTime)!),
),
// Account visibility
ListTile(
leading: Icon(Icons.remove_red_eye),
title: Text(tr("Account visibility")),
title: Text(tr("Account visibility")!),
subtitle: Text(widget.user.pageVisibility == UserPageVisibility.OPEN
? tr("Open page")
? tr("Open page")!
: (widget.user.pageVisibility == UserPageVisibility.PUBLIC
? tr("Public page")
: tr("Private page"))),
? tr("Public page")!
: tr("Private page")!)),
),
],
);

View File

@ -14,9 +14,9 @@ class UserPageHeader extends StatelessWidget {
final Color bgColor;
const UserPageHeader({
Key key,
@required this.user,
@required this.bgColor,
Key? key,
required this.user,
required this.bgColor,
}) : assert(user != null),
super(key: key);

View File

@ -13,8 +13,8 @@ class UserPostsSection extends StatefulWidget {
final AdvancedUserInfo user;
const UserPostsSection({
Key key,
@required this.user,
Key? key,
required this.user,
}) : assert(user != null),
super(key: key);
@ -23,7 +23,7 @@ class UserPostsSection extends StatefulWidget {
}
class _UserPostsSectionState extends State<UserPostsSection> {
int get _userID => widget.user.id;
int? get _userID => widget.user.id;
final _postsKey = GlobalKey<PostsListWidgetState>();
@ -34,7 +34,7 @@ class _UserPostsSectionState extends State<UserPostsSection> {
widget.user.canPostTexts
? PostCreateFormWidget(
postTarget: PostTarget.USER_PAGE,
targetID: _userID,
targetID: _userID!,
onCreated: _postCreated,
)
: Container()
@ -45,6 +45,6 @@ class _UserPostsSectionState extends State<UserPostsSection> {
);
void _postCreated() {
_postsKey.currentState.loadPostsList(getOlder: false);
_postsKey.currentState!.loadPostsList(getOlder: false);
}
}