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:
@ -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);
|
||||
|
@ -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,
|
||||
),
|
||||
));
|
||||
|
@ -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")!),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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!")!);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -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();
|
||||
|
@ -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(),
|
||||
),
|
||||
|
@ -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(),
|
||||
);
|
||||
|
@ -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(),
|
||||
],
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
),
|
||||
],
|
||||
|
@ -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();
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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")!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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!")!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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!),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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!")!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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")!)),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user