1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-10-22 22:43:22 +00:00

Start to fix null safety migration errors

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

View File

@ -8,16 +8,16 @@ import 'package:comunic/models/advanced_group_info.dart';
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
AdvancedGroupInfo _forezGroup; AdvancedGroupInfo? _forezGroup;
class ForezGroupHelper { class ForezGroupHelper {
static Future<void> setId(int groupID) async { static Future<void> setId(int groupID) async {
(await PreferencesHelper.getInstance()) (await PreferencesHelper.getInstance())!
.setInt(PreferencesKeyList.FOREZ_GROUP, groupID); .setInt(PreferencesKeyList.FOREZ_GROUP, groupID);
} }
static Future<int> getId() async { static Future<int?> getId() async {
return (await PreferencesHelper.getInstance()) return (await PreferencesHelper.getInstance())!
.getInt(PreferencesKeyList.FOREZ_GROUP); .getInt(PreferencesKeyList.FOREZ_GROUP);
} }
@ -27,7 +27,7 @@ class ForezGroupHelper {
_forezGroup = res.info; _forezGroup = res.info;
} }
static AdvancedGroupInfo getGroup() => _forezGroup; static AdvancedGroupInfo? getGroup() => _forezGroup;
} }
AdvancedGroupInfo get forezGroup => ForezGroupHelper.getGroup(); AdvancedGroupInfo? get forezGroup => ForezGroupHelper.getGroup();

View File

@ -11,10 +11,10 @@ import 'package:flutter/material.dart';
class ForezConfig extends Config { class ForezConfig extends Config {
ForezConfig({ ForezConfig({
@required String apiServerName, required String apiServerName,
@required String apiServerUri, required String apiServerUri,
@required bool apiServerSecure, required bool apiServerSecure,
@required String clientName, required String clientName,
}) : super( }) : super(
apiServerName: apiServerName, apiServerName: apiServerName,
apiServerUri: apiServerUri, apiServerUri: apiServerUri,

View File

@ -11,7 +11,7 @@ import 'package:comunic/models/config.dart';
/// Fix HTTPS issue /// Fix HTTPS issue
class MyHttpOverride extends HttpOverrides { class MyHttpOverride extends HttpOverrides {
@override @override
HttpClient createHttpClient(SecurityContext context) { HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context) return super.createHttpClient(context)
..badCertificateCallback = (cert, host, port) { ..badCertificateCallback = (cert, host, port) {
return host == "devweb.local"; // Forcefully trust local website return host == "devweb.local"; // Forcefully trust local website

View File

@ -29,7 +29,7 @@ List<Widget> buildTour(TourRouteState state) {
msgTwo: tr("Let's first join a Forez group!"), msgTwo: tr("Let's first join a Forez group!"),
), ),
JoinForezGroupPane( JoinForezGroupPane(
key: state.pubKeys[_JOIN_GROUP_KEY_ID], key: state.pubKeys[_JOIN_GROUP_KEY_ID] as GlobalKey<JoinGroupPaneBodyState>?,
onUpdated: () => state.rebuild(), onUpdated: () => state.rebuild(),
), ),
FirstTourPane( FirstTourPane(
@ -51,7 +51,7 @@ List<Widget> buildTour(TourRouteState state) {
// Forez specific features // Forez specific features
PresentationPane( PresentationPane(
icon: Icons.calendar_today, icon: Icons.calendar_today,
title: tr("Presence in Forez"), title: tr("Presence in Forez")!,
text: tr( text: tr(
"Easily specify the days you are in Forez plain, so that everyone can know it!"), "Easily specify the days you are in Forez plain, so that everyone can know it!"),
actionTitle: tr("Do it now!"), actionTitle: tr("Do it now!"),
@ -62,7 +62,7 @@ List<Widget> buildTour(TourRouteState state) {
// Chat pane // Chat pane
PresentationPane( PresentationPane(
icon: Icons.question_answer, icon: Icons.question_answer,
title: tr("Conversations"), title: tr("Conversations")!,
text: tr( text: tr(
"#Forez now integrates the conversation system of Comunic, so you have access both to public and private conversations!"), "#Forez now integrates the conversation system of Comunic, so you have access both to public and private conversations!"),
), ),

View File

@ -16,17 +16,17 @@ import 'package:flutter/material.dart';
class JoinForezGroupPane extends PresentationPane { class JoinForezGroupPane extends PresentationPane {
JoinForezGroupPane({ JoinForezGroupPane({
@required Function() onUpdated, required Function() onUpdated,
@required GlobalKey<JoinGroupPaneBodyState> key, required GlobalKey<JoinGroupPaneBodyState>? key,
}) : super( }) : super(
icon: Icons.login, icon: Icons.login,
title: tr("Join a Forez group"), title: tr("Join a Forez group")!,
child: (c) => _JoinGroupPaneBody( child: (c) => _JoinGroupPaneBody(
key: key, key: key,
onUpdated: onUpdated, onUpdated: onUpdated,
), ),
canGoNext: key?.currentState?.canGoNext ?? false, canGoNext: key?.currentState?.canGoNext ?? false,
onTapNext: (c) => key.currentState.validateChoice(), onTapNext: (c) => key!.currentState!.validateChoice(),
); );
} }
@ -34,8 +34,8 @@ class _JoinGroupPaneBody extends StatefulWidget {
final Function() onUpdated; final Function() onUpdated;
const _JoinGroupPaneBody({ const _JoinGroupPaneBody({
Key key, Key? key,
@required this.onUpdated, required this.onUpdated,
}) : assert(onUpdated != null), }) : assert(onUpdated != null),
super(key: key); super(key: key);
@ -46,10 +46,10 @@ class _JoinGroupPaneBody extends StatefulWidget {
class JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> { class JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> {
final _key = GlobalKey<AsyncScreenWidgetState>(); final _key = GlobalKey<AsyncScreenWidgetState>();
List<Group> _groups; late List<Group> _groups;
int _currChoice; int? _currChoice;
bool get canGoNext => _currChoice != null && _currChoice > 0; bool get canGoNext => _currChoice != null && _currChoice! > 0;
Group get _currGroup => _groups.firstWhere((e) => e.id == _currChoice); Group get _currGroup => _groups.firstWhere((e) => e.id == _currChoice);
@ -65,17 +65,17 @@ class JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> {
key: _key, key: _key,
onReload: _load, onReload: _load,
onBuild: onBuild, onBuild: onBuild,
errorMessage: tr("Failed to load the list of Forez groups!")); errorMessage: tr("Failed to load the list of Forez groups!")!);
Widget onBuild() => ConstrainedBox( Widget onBuild() => ConstrainedBox(
constraints: BoxConstraints(maxWidth: 300), constraints: BoxConstraints(maxWidth: 300),
child: Column( child: Column(
children: [ children: [
Text(tr("Please choose now the Forez group you want to join...")), Text(tr("Please choose now the Forez group you want to join...")!),
]..addAll(_groups.map((e) => RadioListTile( ]..addAll(_groups.map((e) => RadioListTile(
value: e.id, value: e.id,
groupValue: _currChoice, groupValue: _currChoice,
onChanged: (v) => setState(() => _currChoice = e.id), onChanged: (dynamic v) => setState(() => _currChoice = e.id),
title: Text(e.name), title: Text(e.name),
subtitle: Text(e.membershipText), subtitle: Text(e.membershipText),
))), ))),
@ -112,7 +112,7 @@ class JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> {
await alert(context, await alert(context,
"${tr("You can not access this group yet, please wait for a member of the group to accept your request.")}\n${tr("Hopefully this will not be too long.")}\n${tr("Please check back soon!")}"); "${tr("You can not access this group yet, please wait for a member of the group to accept your request.")}\n${tr("Hopefully this will not be too long.")}\n${tr("Please check back soon!")}");
_key.currentState.refresh(); _key.currentState!.refresh();
return false; return false;
} }
@ -121,8 +121,8 @@ class JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> {
return true; return true;
} catch (e, s) { } catch (e, s) {
logError(e, s); logError(e, s);
snack(context, tr("Failed to register to group!")); snack(context, tr("Failed to register to group!")!);
_key.currentState.refresh(); _key.currentState!.refresh();
return false; return false;
} }
} }

View File

@ -24,8 +24,8 @@ class ForezMemberProfileRoute extends StatefulWidget {
final int userID; final int userID;
const ForezMemberProfileRoute({ const ForezMemberProfileRoute({
Key key, Key? key,
@required this.userID, required this.userID,
}) : assert(userID != null), }) : assert(userID != null),
super(key: key); super(key: key);
@ -39,13 +39,13 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
final _key = GlobalKey<AsyncScreenWidgetState>(); final _key = GlobalKey<AsyncScreenWidgetState>();
AdvancedUserInfo _user; late AdvancedUserInfo _user;
PresenceSet _presence; late PresenceSet _presence;
Future<void> _load() async { Future<void> _load() async {
_user = await ForezGroupsHelper.getMemberInfo(forezGroup.id, widget.userID); _user = await ForezGroupsHelper.getMemberInfo(forezGroup!.id, widget.userID);
_presence = _presence =
await ForezPresenceHelper.getForUser(forezGroup.id, widget.userID); await ForezPresenceHelper.getForUser(forezGroup!.id, widget.userID);
} }
@override @override
@ -56,25 +56,25 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
loadingWidget: _buildLoading(), loadingWidget: _buildLoading(),
errorWidget: _buildError(), errorWidget: _buildError(),
errorMessage: tr( errorMessage: tr(
"Failed to load user information, maybe it is not a Forez member yet?")); "Failed to load user information, maybe it is not a Forez member yet?")!);
Widget _buildLoading() => Scaffold( Widget _buildLoading() => Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(tr("Loading...")), title: Text(tr("Loading...")!),
), ),
body: buildCenteredProgressBar(), body: buildCenteredProgressBar(),
); );
Widget _buildError() => Scaffold( Widget _buildError() => Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(tr("Error")), title: Text(tr("Error")!),
), ),
body: buildErrorCard( body: buildErrorCard(
tr("Failed to load user information, maybe it is not a Forez member yet?"), tr("Failed to load user information, maybe it is not a Forez member yet?"),
actions: [ actions: [
MaterialButton( MaterialButton(
onPressed: () => _key.currentState.refresh(), onPressed: () => _key.currentState!.refresh(),
child: Text(tr("Try again")), child: Text(tr("Try again")!),
textColor: Colors.white, textColor: Colors.white,
) )
]), ]),
@ -101,7 +101,7 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
? Container() ? Container()
: CachedNetworkImage( : CachedNetworkImage(
fit: BoxFit.cover, fit: BoxFit.cover,
imageUrl: _user.accountImageURL, imageUrl: _user.accountImageURL!,
height: _appBarHeight, height: _appBarHeight,
), ),
// This gradient ensures that the toolbar icons are distinct // This gradient ensures that the toolbar icons are distinct
@ -135,7 +135,7 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
: ListTile( : ListTile(
leading: Icon(Icons.note), leading: Icon(Icons.note),
title: TextWidget(content: DisplayedString(_user.publicNote)), title: TextWidget(content: DisplayedString(_user.publicNote)),
subtitle: Text(tr("Note")), subtitle: Text(tr("Note")!),
), ),
// Email address // Email address
@ -143,9 +143,9 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
? Container() ? Container()
: ListTile( : ListTile(
leading: Icon(Icons.email), leading: Icon(Icons.email),
title: Text(_user.emailAddress), title: Text(_user.emailAddress!),
subtitle: Text(tr("Email address")), subtitle: Text(tr("Email address")!),
trailing: CopyIcon(_user.emailAddress), trailing: CopyIcon(_user.emailAddress!),
), ),
// Location // Location
@ -153,9 +153,9 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
? Container() ? Container()
: ListTile( : ListTile(
leading: Icon(Icons.location_on), leading: Icon(Icons.location_on),
title: Text(_user.location), title: Text(_user.location!),
subtitle: Text(tr("Location")), subtitle: Text(tr("Location")!),
trailing: CopyIcon(_user.location), trailing: CopyIcon(_user.location!),
), ),
// Website // Website
@ -164,7 +164,7 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
: ListTile( : ListTile(
leading: Icon(Icons.link), leading: Icon(Icons.link),
title: Text(_user.personalWebsite), title: Text(_user.personalWebsite),
subtitle: Text(tr("Website")), subtitle: Text(tr("Website")!),
trailing: IconButton( trailing: IconButton(
icon: Icon(Icons.open_in_new), icon: Icon(Icons.open_in_new),
onPressed: () => launch(_user.personalWebsite), onPressed: () => launch(_user.personalWebsite),
@ -174,10 +174,10 @@ class _ForezMemberProfileRouteState extends State<ForezMemberProfileRoute> {
Divider(), Divider(),
ListTile( ListTile(
leading: Icon(Icons.calendar_today), leading: Icon(Icons.calendar_today),
title: Text(tr("Presence in Forez")), title: Text(tr("Presence in Forez")!),
subtitle: Text(_presence.containsDate(DateTime.now()) subtitle: Text(_presence.containsDate(DateTime.now())
? tr("Present today") ? tr("Present today")!
: tr("Absent")), : tr("Absent")!),
), ),
PresenceCalendarWidget(presenceSet: _presence), PresenceCalendarWidget(presenceSet: _presence),
Divider(), Divider(),

View File

@ -21,7 +21,7 @@ import 'package:flutter/material.dart';
/// @author Pierre Hubert /// @author Pierre Hubert
class ForezRoute extends StatefulWidget implements MainRoute { class ForezRoute extends StatefulWidget implements MainRoute {
const ForezRoute({Key key}) : super(key: key); const ForezRoute({Key? key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => _MainRouteState(); State<StatefulWidget> createState() => _MainRouteState();
@ -40,7 +40,7 @@ class _MainRouteState extends MainController {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (forezGroup == null) return Text(tr("Missing Forez group!")); if (forezGroup == null) return Text(tr("Missing Forez group!")!);
return StatusWidget( return StatusWidget(
child: (c) => SafeArea( child: (c) => SafeArea(
@ -67,11 +67,11 @@ class _MainRouteState extends MainController {
@override @override
void openConversation(Conversation conv, {fullScreen: false}) { void openConversation(Conversation conv, {fullScreen: false}) {
// Forcefully open conversations in a "normal" way (do not display groups) // Forcefully open conversations in a "normal" way (do not display groups)
openConversationById(conv.id, fullScreen: fullScreen); openConversationById(conv.id!, fullScreen: fullScreen);
} }
@override @override
void openGroup(int groupID, {int conversationID}) => _unsupportedFeature(); void openGroup(int groupID, {int? conversationID}) => _unsupportedFeature();
@override @override
void openUserPage(int userID) => pushPage(PageInfo( void openUserPage(int userID) => pushPage(PageInfo(
@ -92,7 +92,7 @@ class _MainRouteState extends MainController {
enum _PopupMenuItems { ACTION_SETTINGS, ACTION_SIGN_OUT } enum _PopupMenuItems { ACTION_SETTINGS, ACTION_SIGN_OUT }
class ForezRouteBody extends StatefulWidget { class ForezRouteBody extends StatefulWidget {
ForezRouteBody({Key key}) : super(key: key); ForezRouteBody({Key? key}) : super(key: key);
@override @override
_ForezRouteBodyState createState() => _ForezRouteBodyState(); _ForezRouteBodyState createState() => _ForezRouteBodyState();
@ -112,7 +112,7 @@ class _ForezRouteBodyState extends SafeState<ForezRouteBody> {
length: _tabs.length, length: _tabs.length,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(forezGroup.name), title: Text(forezGroup!.name),
actions: <Widget>[_buildPopupMenuButton()], actions: <Widget>[_buildPopupMenuButton()],
bottom: TabBar(tabs: _tabs), bottom: TabBar(tabs: _tabs),
), ),
@ -129,11 +129,11 @@ class _ForezRouteBodyState extends SafeState<ForezRouteBody> {
Widget _buildPopupMenuButton() => PopupMenuButton<_PopupMenuItems>( Widget _buildPopupMenuButton() => PopupMenuButton<_PopupMenuItems>(
itemBuilder: (c) => [ itemBuilder: (c) => [
PopupMenuItem( PopupMenuItem(
child: Text(tr("Settings")), child: Text(tr("Settings")!),
value: _PopupMenuItems.ACTION_SETTINGS, value: _PopupMenuItems.ACTION_SETTINGS,
), ),
PopupMenuItem( PopupMenuItem(
child: Text(tr("Sign out")), child: Text(tr("Sign out")!),
value: _PopupMenuItems.ACTION_SIGN_OUT, value: _PopupMenuItems.ACTION_SIGN_OUT,
), ),
], ],
@ -143,10 +143,10 @@ class _ForezRouteBodyState extends SafeState<ForezRouteBody> {
void _onMenuSelection(_PopupMenuItems value) { void _onMenuSelection(_PopupMenuItems value) {
switch (value) { switch (value) {
case _PopupMenuItems.ACTION_SETTINGS: case _PopupMenuItems.ACTION_SETTINGS:
MainController.of(context).openSettings(); MainController.of(context)!.openSettings();
break; break;
case _PopupMenuItems.ACTION_SIGN_OUT: case _PopupMenuItems.ACTION_SIGN_OUT:
MainController.of(context).requestLogout(); MainController.of(context)!.requestLogout();
break; break;
} }
} }
@ -155,29 +155,29 @@ class _ForezRouteBodyState extends SafeState<ForezRouteBody> {
// Posts tab // Posts tab
_Tab( _Tab(
icon: Icons.auto_stories, icon: Icons.auto_stories,
title: tr("Posts"), title: tr("Posts")!,
widget: () => GroupPostsSection(group: forezGroup), widget: () => GroupPostsSection(group: forezGroup!),
), ),
// Presence tab // Presence tab
_Tab( _Tab(
icon: Icons.calendar_today, icon: Icons.calendar_today,
title: tr("Presence"), title: tr("Presence")!,
widget: () => ForezPresenceSection(groupID: forezGroup.id), widget: () => ForezPresenceSection(groupID: forezGroup!.id),
), ),
// Conversations tab // Conversations tab
_Tab( _Tab(
icon: Icons.question_answer, icon: Icons.question_answer,
title: tr("Conversations"), title: tr("Conversations")!,
widget: () => ConversationsListScreen(), widget: () => ConversationsListScreen(),
isUnread: (c) => StatusWidgetState.of(c).unreadConversations > 0, isUnread: (c) => StatusWidgetState.of(c)!.unreadConversations! > 0,
), ),
// Directory tab // Directory tab
_Tab( _Tab(
icon: Icons.import_contacts, icon: Icons.import_contacts,
title: tr("Directory"), title: tr("Directory")!,
widget: () => ForezDirectoryScreen(), widget: () => ForezDirectoryScreen(),
), ),
]; ];
@ -203,12 +203,12 @@ class _Tab {
final IconData icon; final IconData icon;
final String title; final String title;
final Widget Function() widget; final Widget Function() widget;
final bool Function(BuildContext) isUnread; final bool Function(BuildContext)? isUnread;
const _Tab({ const _Tab({
@required this.icon, required this.icon,
@required this.title, required this.title,
@required this.widget, required this.widget,
this.isUnread, this.isUnread,
}) : assert(icon != null), }) : assert(icon != null),
assert(title != null), assert(title != null),

View File

@ -7,18 +7,18 @@ import 'package:flutter/material.dart';
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
Future<User> searchUser(BuildContext context, UsersList users) async { Future<User?> searchUser(BuildContext context, UsersList users) async {
return await showSearch<User>( return await showSearch<User?>(
context: context, delegate: _SearchDelegate(users)); context: context, delegate: _SearchDelegate(users));
} }
class _SearchDelegate extends SearchDelegate<User> { class _SearchDelegate extends SearchDelegate<User?> {
final UsersList _usersList; final UsersList _usersList;
_SearchDelegate(this._usersList) : assert(_usersList != null); _SearchDelegate(this._usersList) : assert(_usersList != null);
@override @override
List<Widget> buildActions(BuildContext context) => null; List<Widget>? buildActions(BuildContext context) => null;
@override @override
Widget buildLeading(BuildContext context) => IconButton( Widget buildLeading(BuildContext context) => IconButton(
@ -28,7 +28,7 @@ class _SearchDelegate extends SearchDelegate<User> {
@override @override
Widget buildSuggestions(BuildContext context) { Widget buildSuggestions(BuildContext context) {
final list = _usersList final List<User> list = _usersList
.where((element) => .where((element) =>
element.fullName.toLowerCase().contains(query.toLowerCase())) element.fullName.toLowerCase().contains(query.toLowerCase()))
.toList(); .toList();

View File

@ -35,11 +35,11 @@ class ForezDirectoryScreen extends StatefulWidget {
class _ForezDirectoryScreenState extends State<ForezDirectoryScreen> { class _ForezDirectoryScreenState extends State<ForezDirectoryScreen> {
final _key = GlobalKey<AsyncScreenWidgetState>(); final _key = GlobalKey<AsyncScreenWidgetState>();
UsersList _users; late UsersList _users;
GroupMembersList _members; late GroupMembersList _members;
Future<void> _load() async { Future<void> _load() async {
_members = await GroupsHelper.getMembersList(forezGroup.id); _members = await GroupsHelper.getMembersList(forezGroup!.id);
_users = await UsersHelper().getListWithThrow(_members.usersID); _users = await UsersHelper().getListWithThrow(_members.usersID);
} }
@ -49,7 +49,7 @@ class _ForezDirectoryScreenState extends State<ForezDirectoryScreen> {
AsyncScreenWidget( AsyncScreenWidget(
onReload: _load, onReload: _load,
onBuild: onBuild, onBuild: onBuild,
errorMessage: tr("Failed to load members list!"), errorMessage: tr("Failed to load members list!")!,
key: _key, key: _key,
), ),
Positioned( Positioned(
@ -88,13 +88,13 @@ class _ForezDirectoryScreenState extends State<ForezDirectoryScreen> {
"Do you really want to cancel the invitation sent to %u%?", "Do you really want to cancel the invitation sent to %u%?",
args: {"u": user.fullName}))) return; args: {"u": user.fullName}))) return;
await GroupsHelper.cancelInvitation(forezGroup.id, user.id); await GroupsHelper.cancelInvitation(forezGroup!.id, user.id);
_key.currentState.refresh(); _key.currentState!.refresh();
break; break;
case _PopupMenuActions.ACCEPT_REQUEST: case _PopupMenuActions.ACCEPT_REQUEST:
await GroupsHelper.respondRequest(forezGroup.id, user.id, true); await GroupsHelper.respondRequest(forezGroup!.id, user.id, true);
_key.currentState.refresh(); _key.currentState!.refresh();
break; break;
case _PopupMenuActions.REJECT_REQUEST: case _PopupMenuActions.REJECT_REQUEST:
@ -104,13 +104,13 @@ class _ForezDirectoryScreenState extends State<ForezDirectoryScreen> {
"Do you really want to reject the request of %u% to join the Forez group?", "Do you really want to reject the request of %u% to join the Forez group?",
args: {"u": user.fullName}))) return; args: {"u": user.fullName}))) return;
await GroupsHelper.respondRequest(forezGroup.id, user.id, false); await GroupsHelper.respondRequest(forezGroup!.id, user.id, false);
_key.currentState.refresh(); _key.currentState!.refresh();
break; break;
} }
} catch (e, s) { } catch (e, s) {
logError(e, s); logError(e, s);
snack(context, tr("Error while processing action!")); snack(context, tr("Error while processing action!")!);
} }
} }
@ -125,7 +125,7 @@ class _ForezDirectoryScreenState extends State<ForezDirectoryScreen> {
} }
void _openUserProfile(User user) => void _openUserProfile(User user) =>
MainController.of(context).openUserPage(user.id); MainController.of(context)!.openUserPage(user.id!);
} }
class _ForezMemberTile extends StatelessWidget { class _ForezMemberTile extends StatelessWidget {
@ -135,11 +135,11 @@ class _ForezMemberTile extends StatelessWidget {
final Function(User) onTap; final Function(User) onTap;
const _ForezMemberTile({ const _ForezMemberTile({
Key key, Key? key,
@required this.user, required this.user,
@required this.member, required this.member,
@required this.selectedAction, required this.selectedAction,
@required this.onTap, required this.onTap,
}) : super(key: key); }) : super(key: key);
@override @override
@ -147,7 +147,7 @@ class _ForezMemberTile extends StatelessWidget {
leading: AccountImageWidget(user: user), leading: AccountImageWidget(user: user),
title: Text(user.fullName), title: Text(user.fullName),
subtitle: Text(member.membershipText), subtitle: Text(member.membershipText),
trailing: !member.isAtLeastMember && forezGroup.isAtLeastModerator trailing: !member.isAtLeastMember && forezGroup!.isAtLeastModerator
? (member.isInvited ? (member.isInvited
? _buildInvitedButton() ? _buildInvitedButton()
: _buildRequestedButton()) : _buildRequestedButton())
@ -155,7 +155,7 @@ class _ForezMemberTile extends StatelessWidget {
onTap: member.isAtLeastMember ? () => onTap(user) : null, onTap: member.isAtLeastMember ? () => onTap(user) : null,
); );
Widget _buildConversationButton() => user.id == userID() Widget? _buildConversationButton() => user.id == userID()
? null ? null
: IconButton( : IconButton(
icon: Icon(Icons.message), icon: Icon(Icons.message),
@ -201,12 +201,12 @@ class _MembershipButton extends StatelessWidget {
final IconData icon; final IconData icon;
const _MembershipButton({ const _MembershipButton({
Key key, Key? key,
@required this.user, required this.user,
@required this.action, required this.action,
@required this.onTap, required this.onTap,
@required this.color, required this.color,
@required this.icon, required this.icon,
}) : assert(user != null), }) : assert(user != null),
assert(action != null), assert(action != null),
assert(onTap != null), assert(onTap != null),

View File

@ -26,14 +26,14 @@ enum CreateAccountResult {
class AccountHelper { class AccountHelper {
// Current user ID // Current user ID
static int _currentUserID = -1; static int? _currentUserID = -1;
/// Checkout whether current user is signed in or not /// Checkout whether current user is signed in or not
/// ///
/// Warning : This method MUST BE CALLED AT LEAST ONCE AFTER APP START !!! /// Warning : This method MUST BE CALLED AT LEAST ONCE AFTER APP START !!!
Future<bool> signedIn() async { Future<bool> signedIn() async {
bool signedIn = bool signedIn =
(await PreferencesHelper.getInstance()).getLoginToken() != null; (await PreferencesHelper.getInstance())!.getLoginToken() != null;
// Load current user ID for later use // Load current user ID for later use
if (signedIn && _currentUserID == -1) await _loadCurrentUserID(); if (signedIn && _currentUserID == -1) await _loadCurrentUserID();
@ -56,8 +56,8 @@ class AccountHelper {
else if (response.code != 200) return AuthResult.NETWORK_ERROR; else if (response.code != 200) return AuthResult.NETWORK_ERROR;
// Save login token // Save login token
await (await PreferencesHelper.getInstance()) await (await PreferencesHelper.getInstance())!
.setLoginToken(response.getObject()["token"]); .setLoginToken(response.getObject()!["token"]);
// Get current user ID // Get current user ID
final userID = await _downloadCurrentUserID(); final userID = await _downloadCurrentUserID();
@ -67,7 +67,7 @@ class AccountHelper {
} }
// Save current user ID // Save current user ID
final preferences = await PreferencesHelper.getInstance(); final preferences = await (PreferencesHelper.getInstance());
await preferences.setInt(PreferencesKeyList.USER_ID, userID); await preferences.setInt(PreferencesKeyList.USER_ID, userID);
_currentUserID = userID; _currentUserID = userID;
@ -130,27 +130,27 @@ class AccountHelper {
.getObject()["exists"]; .getObject()["exists"];
/// Get current user email address /// Get current user email address
static Future<String> getCurrentAccountEmailAddress() async => static Future<String?> getCurrentAccountEmailAddress() async =>
(await APIRequest.withLogin("account/mail") (await APIRequest.withLogin("account/mail")
.execWithThrowGetObject())["mail"]; .execWithThrowGetObject())!["mail"];
/// Check out whether security questions have been set for an account or not /// Check out whether security questions have been set for an account or not
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<bool> hasSecurityQuestions(String email) async => static Future<bool?> hasSecurityQuestions(String email) async =>
(await APIRequest.withoutLogin("account/has_security_questions") (await APIRequest.withoutLogin("account/has_security_questions")
.addString("email", email) .addString("email", email)
.execWithThrow()) .execWithThrow())
.getObject()["defined"]; .getObject()!["defined"];
/// Get the security questions of the user /// Get the security questions of the user
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<List<String>> getSecurityQuestions(String email) async => static Future<List<String>?> getSecurityQuestions(String? email) async =>
((await APIRequest.withoutLogin("account/get_security_questions") ((await APIRequest.withoutLogin("account/get_security_questions")
.addString("email", email) .addString("email", email)
.execWithThrow()) .execWithThrow())
.getObject()["questions"]) .getObject()!["questions"])
.cast<String>(); .cast<String>();
/// Validate given security answers /// Validate given security answers
@ -158,14 +158,14 @@ class AccountHelper {
/// Throws an [Exception] in case of failure /// Throws an [Exception] in case of failure
/// ///
/// Returns a password reset token in case of success /// Returns a password reset token in case of success
static Future<String> checkAnswers( static Future<String?> checkAnswers(
String email, List<String> answers) async => String? email, List<String> answers) async =>
(await APIRequest.withoutLogin("account/check_security_answers") (await APIRequest.withoutLogin("account/check_security_answers")
.addString("email", email) .addString("email", email)
.addString("answers", .addString("answers",
answers.map((f) => Uri.encodeComponent(f)).join("&")) answers.map((f) => Uri.encodeComponent(f)).join("&"))
.execWithThrow()) .execWithThrow())
.getObject()["reset_token"]; .getObject()!["reset_token"];
/// Check a password reset token /// Check a password reset token
/// ///
@ -195,25 +195,26 @@ class AccountHelper {
.execWithThrow(); .execWithThrow();
/// Get current user ID from the server /// Get current user ID from the server
Future<int> _downloadCurrentUserID() async { Future<int?> _downloadCurrentUserID() async {
final response = await APIRequest.withLogin("account/id").exec(); final response = await APIRequest.withLogin("account/id").exec();
if (response.code != 200) return null; if (response.code != 200) return null;
return response.getObject()["userID"]; return response.getObject()!["userID"];
} }
/// Get the ID of the currently signed in user /// Get the ID of the currently signed in user
Future<void> _loadCurrentUserID() async { Future<void> _loadCurrentUserID() async {
final preferences = await PreferencesHelper.getInstance(); final preferences =
await PreferencesHelper.getInstance();
_currentUserID = preferences.getInt(PreferencesKeyList.USER_ID); _currentUserID = preferences.getInt(PreferencesKeyList.USER_ID);
} }
/// Check if current user ID is loaded or not /// Check if current user ID is loaded or not
static bool get isUserIDLoaded => _currentUserID > 0; static bool get isUserIDLoaded => _currentUserID! > 0;
/// Get the ID of the currently signed in user /// Get the ID of the currently signed in user
static int getCurrentUserID() { static int? getCurrentUserID() {
if (_currentUserID == -1) throw "Current user ID has not been loaded yet!"; if (_currentUserID == -1) throw "Current user ID has not been loaded yet!";
return _currentUserID; return _currentUserID;
} }

View File

@ -23,7 +23,7 @@ class APIHelper {
//Add user token (if required) //Add user token (if required)
if (request.needLogin) { if (request.needLogin) {
final token = (await PreferencesHelper.getInstance()).getLoginToken(); final token = (await PreferencesHelper.getInstance())!.getLoginToken();
if (token == null) { if (token == null) {
EventsHelper.emit(InvalidLoginTokensEvent()); EventsHelper.emit(InvalidLoginTokensEvent());
@ -41,13 +41,13 @@ class APIHelper {
else else
url = Uri.https(config().apiServerName, path); url = Uri.https(config().apiServerName, path);
final data = FormData.fromMap(request.args); final data = FormData.fromMap(request.args!);
// Process files (if required) // Process files (if required)
if (multipart) { if (multipart) {
// Process filesystem files // Process filesystem files
for (final key in request.files.keys) { for (final key in request.files.keys) {
var v = request.files[key]; var v = request.files[key]!;
data.files.add(MapEntry( data.files.add(MapEntry(
key, key,
await MultipartFile.fromFile(v.path, await MultipartFile.fromFile(v.path,
@ -56,11 +56,11 @@ class APIHelper {
// Process in-memory files // Process in-memory files
for (final key in request.bytesFiles.keys) { for (final key in request.bytesFiles.keys) {
var v = request.bytesFiles[key]; var v = request.bytesFiles[key]!;
data.files.add(MapEntry( data.files.add(MapEntry(
key, key,
MultipartFile.fromBytes( MultipartFile.fromBytes(
v.bytes, v.bytes!,
filename: v.filename.split("/").last, filename: v.filename.split("/").last,
contentType: v.type, contentType: v.type,
))); )));
@ -85,9 +85,9 @@ class APIHelper {
EventsHelper.emit(InvalidLoginTokensEvent()); EventsHelper.emit(InvalidLoginTokensEvent());
if (response.statusCode != HttpStatus.ok) if (response.statusCode != HttpStatus.ok)
return APIResponse(response.statusCode, response.data); return APIResponse(response.statusCode!, response.data);
return APIResponse(response.statusCode, response.data); return APIResponse(response.statusCode!, response.data);
} catch (e, stack) { } catch (e, stack) {
print(e.toString()); print(e.toString());
print("Could not execute a request!"); print("Could not execute a request!");

View File

@ -39,12 +39,12 @@ class CallsHelper {
.cast<CallMember>()); .cast<CallMember>());
/// Request an offer to access another peer's stream /// Request an offer to access another peer's stream
static Future<void> requestOffer(int callID, int peerID) async => static Future<void> requestOffer(int callID, int? peerID) async =>
await ws("calls/request_offer", {"callID": callID, "peerID": peerID}); await ws("calls/request_offer", {"callID": callID, "peerID": peerID});
/// Send a Session Description message to the server /// Send a Session Description message to the server
static Future<void> sendSessionDescription( static Future<void> sendSessionDescription(
int callID, int peerID, RTCSessionDescription sdp) async => int callID, int? peerID, RTCSessionDescription sdp) async =>
await ws("calls/signal", { await ws("calls/signal", {
"callID": callID, "callID": callID,
"peerID": peerID, "peerID": peerID,
@ -54,7 +54,7 @@ class CallsHelper {
/// Send an IceCandidate /// Send an IceCandidate
static Future<void> sendIceCandidate( static Future<void> sendIceCandidate(
int callID, int peerID, RTCIceCandidate candidate) async => int callID, int? peerID, RTCIceCandidate candidate) async =>
await ws("calls/signal", { await ws("calls/signal", {
"callID": callID, "callID": callID,
"peerID": peerID, "peerID": peerID,

View File

@ -27,7 +27,7 @@ class CommentsHelper {
} }
/// Get a single comment from the server, specified by its [id] /// Get a single comment from the server, specified by its [id]
Future<Comment> getSingle(int id) async { Future<Comment?> getSingle(int id) async {
final response = await APIRequest( final response = await APIRequest(
uri: "comments/get_single", uri: "comments/get_single",
needLogin: true, needLogin: true,
@ -39,7 +39,7 @@ class CommentsHelper {
} }
/// Update comment content /// Update comment content
Future<bool> updateContent(int id, String newContent) async { Future<bool> updateContent(int id, String? newContent) async {
return (await APIRequest(uri: "comments/edit", needLogin: true, args: { return (await APIRequest(uri: "comments/edit", needLogin: true, args: {
"commentID": id.toString(), "commentID": id.toString(),
"content": newContent, "content": newContent,

View File

@ -21,7 +21,6 @@ import 'package:comunic/utils/account_utils.dart';
import 'package:comunic/utils/color_utils.dart'; import 'package:comunic/utils/color_utils.dart';
import 'package:comunic/utils/dart_color.dart'; import 'package:comunic/utils/dart_color.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:meta/meta.dart';
/// Conversation helper /// Conversation helper
/// ///
@ -47,13 +46,13 @@ class ConversationsHelper {
.addBool("canEveryoneAddMembers", settings.canEveryoneAddMembers) .addBool("canEveryoneAddMembers", settings.canEveryoneAddMembers)
.execWithThrow(); .execWithThrow();
return response.getObject()["conversationID"]; return response.getObject()!["conversationID"];
} }
/// Add a member to a conversation. /// Add a member to a conversation.
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> addMember(int convID, int userID) async => static Future<void> addMember(int? convID, int? userID) async =>
await APIRequest.withLogin("conversations/addMember") await APIRequest.withLogin("conversations/addMember")
.addInt("convID", convID) .addInt("convID", convID)
.addInt("userID", userID) .addInt("userID", userID)
@ -62,7 +61,7 @@ class ConversationsHelper {
/// Remove a member from a conversation. /// Remove a member from a conversation.
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> removeMember(int convID, int userID) async => static Future<void> removeMember(int? convID, int? userID) async =>
await APIRequest.withLogin("conversations/removeMember") await APIRequest.withLogin("conversations/removeMember")
.addInt("convID", convID) .addInt("convID", convID)
.addInt("userID", userID) .addInt("userID", userID)
@ -71,7 +70,7 @@ class ConversationsHelper {
/// Update admin status of a user in a conversation /// Update admin status of a user in a conversation
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> setAdmin(int/*!*/ convID, int/*!*/ userID, bool admin) async => static Future<void> setAdmin(int convID, int userID, bool admin) async =>
await APIRequest.withLogin("conversations/setAdmin") await APIRequest.withLogin("conversations/setAdmin")
.addInt("convID", convID) .addInt("convID", convID)
.addInt("userID", userID) .addInt("userID", userID)
@ -91,7 +90,7 @@ class ConversationsHelper {
if (settings.isComplete) if (settings.isComplete)
request request
.addString("name", settings.name ?? "") .addString("name", settings.name ?? "")
.addBool("canEveryoneAddMembers", settings.canEveryoneAddMembers) .addBool("canEveryoneAddMembers", settings.canEveryoneAddMembers!)
.addString("color", colorToHex(settings.color)); .addString("color", colorToHex(settings.color));
await request.execWithThrow(); await request.execWithThrow();
@ -104,7 +103,7 @@ class ConversationsHelper {
/// Set a new conversation logo /// Set a new conversation logo
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> changeImage(int convID, BytesFile file) async => static Future<void> changeImage(int? convID, BytesFile file) async =>
await APIRequest.withLogin("conversations/change_image") await APIRequest.withLogin("conversations/change_image")
.addInt("convID", convID) .addInt("convID", convID)
.addBytesFile("file", file) .addBytesFile("file", file)
@ -113,13 +112,13 @@ class ConversationsHelper {
/// Remove conversation logo /// Remove conversation logo
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> removeLogo(int convID) async => static Future<void> removeLogo(int? convID) async =>
await APIRequest.withLogin("conversations/delete_image") await APIRequest.withLogin("conversations/delete_image")
.addInt("convID", convID) .addInt("convID", convID)
.execWithThrow(); .execWithThrow();
/// Delete a conversation specified by its [id] /// Delete a conversation specified by its [id]
Future<void> deleteConversation(int id) async => Future<void> deleteConversation(int? id) async =>
await APIRequest.withLogin("conversations/delete") await APIRequest.withLogin("conversations/delete")
.addInt("conversationID", id) .addInt("conversationID", id)
.execWithThrow(); .execWithThrow();
@ -132,7 +131,7 @@ class ConversationsHelper {
await APIRequest.withLogin("conversations/getList").execWithThrow(); await APIRequest.withLogin("conversations/getList").execWithThrow();
ConversationsList list = ConversationsList(); ConversationsList list = ConversationsList();
response.getArray().forEach((f) => list.add(apiToConversation(f))); response.getArray()!.forEach((f) => list.add(apiToConversation(f)));
// Update the database // Update the database
await ConversationsSerializationHelper().setList(list); await ConversationsSerializationHelper().setList(list);
@ -148,13 +147,13 @@ class ConversationsHelper {
} }
/// Get information about a single conversation specified by its [id] /// Get information about a single conversation specified by its [id]
Future<Conversation> _downloadSingle(int id) async { Future<Conversation> _downloadSingle(int? id) async {
final response = await APIRequest( final response = await APIRequest(
uri: "conversations/get_single", uri: "conversations/get_single",
needLogin: true, needLogin: true,
args: {"conversationID": id.toString()}).execWithThrow(); args: {"conversationID": id.toString()}).execWithThrow();
final conversation = apiToConversation(response.getObject()); final conversation = apiToConversation(response.getObject()!);
await ConversationsSerializationHelper() await ConversationsSerializationHelper()
.insertOrReplaceElement((c) => c.id == conversation.id, conversation); .insertOrReplaceElement((c) => c.id == conversation.id, conversation);
@ -167,7 +166,7 @@ class ConversationsHelper {
/// case of failure /// case of failure
/// ///
/// Return value of this method is never null. /// Return value of this method is never null.
Future<Conversation> getSingle(int id, {bool force = false}) async { Future<Conversation> getSingle(int? id, {bool force = false}) async {
if (force || if (force ||
!await ConversationsSerializationHelper().any((c) => c.id == id)) !await ConversationsSerializationHelper().any((c) => c.id == id))
return await _downloadSingle(id); return await _downloadSingle(id);
@ -178,19 +177,19 @@ class ConversationsHelper {
/// Get the name of a [conversation]. This requires information /// Get the name of a [conversation]. This requires information
/// about the users of this conversation /// about the users of this conversation
static String getConversationName( static String getConversationName(
Conversation conversation, UsersList users) { Conversation conversation, UsersList? users) {
if (conversation.hasName) return conversation.name; if (conversation.hasName) return conversation.name!;
String name = ""; String name = "";
int count = 0; int count = 0;
for (int i = 0; i < 3 && i < conversation.members.length; i++) for (int i = 0; i < 3 && i < conversation.members!.length; i++)
if (conversation.members[i].userID != userID()) { if (conversation.members![i].userID != userID()) {
name += (count > 0 ? ", " : "") + name += (count > 0 ? ", " : "") +
users.getUser(conversation.members[i].userID).fullName; users!.getUser(conversation.members![i].userID).fullName;
count++; count++;
} }
if (conversation.members.length > 3) name += ", ..."; if (conversation.members!.length > 3) name += ", ...";
return name; return name;
} }
@ -200,7 +199,7 @@ class ConversationsHelper {
/// true /// true
/// ///
/// Throws an exception in case of failure /// Throws an exception in case of failure
Future<int> getPrivate(int userID, {bool allowCreate = true}) async { Future<int> getPrivate(int? userID, {bool allowCreate = true}) async {
final response = await APIRequest( final response = await APIRequest(
uri: "conversations/getPrivate", uri: "conversations/getPrivate",
needLogin: true, needLogin: true,
@ -211,7 +210,7 @@ class ConversationsHelper {
).execWithThrow(); ).execWithThrow();
// Get and return conversation ID // Get and return conversation ID
return int.parse(response.getObject()["conversationsID"][0].toString()); return int.parse(response.getObject()!["conversationsID"][0].toString());
} }
/// Asynchronously get the name of the conversation /// Asynchronously get the name of the conversation
@ -222,7 +221,7 @@ class ConversationsHelper {
/// Throws an exception in case of failure /// Throws an exception in case of failure
static Future<String> getConversationNameAsync( static Future<String> getConversationNameAsync(
Conversation conversation) async { Conversation conversation) async {
if (conversation.hasName) return conversation.name; if (conversation.hasName) return conversation.name!;
//Get information about the members of the conversation //Get information about the members of the conversation
final members = await UsersHelper().getList(conversation.membersID); final members = await UsersHelper().getList(conversation.membersID);
@ -273,7 +272,7 @@ class ConversationsHelper {
// Parse the response of the server // Parse the response of the server
ConversationMessagesList list = ConversationMessagesList(); ConversationMessagesList list = ConversationMessagesList();
response.getArray().forEach((f) { response.getArray()!.forEach((f) {
list.add( list.add(
apiToConversationMessage(f), apiToConversationMessage(f),
); );
@ -294,7 +293,7 @@ class ConversationsHelper {
/// Throws an exception in case of failure /// Throws an exception in case of failure
Future<ConversationMessagesList> _downloadNewMessagesSingle( Future<ConversationMessagesList> _downloadNewMessagesSingle(
int conversationID, int conversationID,
{int lastMessageID = 0}) async { {int? lastMessageID = 0}) async {
// Execute the request on the server // Execute the request on the server
final response = await APIRequest( final response = await APIRequest(
uri: "conversations/refresh_single", uri: "conversations/refresh_single",
@ -311,8 +310,8 @@ class ConversationsHelper {
/// ///
/// Throws in case of failure /// Throws in case of failure
Future<ConversationMessagesList> getOlderMessages({ Future<ConversationMessagesList> getOlderMessages({
@required int conversationID, required int conversationID,
@required int oldestMessagesID, required int? oldestMessagesID,
int limit = 15, int limit = 15,
}) async { }) async {
// Perform the request online // Perform the request online
@ -334,8 +333,8 @@ class ConversationsHelper {
/// ///
/// Throws in case of failure /// Throws in case of failure
Future<ConversationMessagesList> getNewMessages( Future<ConversationMessagesList> getNewMessages(
{@required int conversationID, {required int conversationID,
int lastMessageID = 0, int? lastMessageID = 0,
bool online = true}) async { bool online = true}) async {
if (online) if (online)
return await _downloadNewMessagesSingle(conversationID, return await _downloadNewMessagesSingle(conversationID,
@ -348,8 +347,8 @@ class ConversationsHelper {
/// Send a new message to the server /// Send a new message to the server
Future<SendMessageResult> sendMessage( Future<SendMessageResult> sendMessage(
NewConversationMessage message, { NewConversationMessage message, {
ProgressCallback sendProgress, ProgressCallback? sendProgress,
CancelToken cancelToken, CancelToken? cancelToken,
}) async { }) async {
final request = APIRequest.withLogin("conversations/sendMessage") final request = APIRequest.withLogin("conversations/sendMessage")
.addInt("conversationID", message.conversationID) .addInt("conversationID", message.conversationID)
@ -388,7 +387,7 @@ class ConversationsHelper {
await ConversationsMessagesSerializationHelper(msg.convID).remove(msg); await ConversationsMessagesSerializationHelper(msg.convID).remove(msg);
/// Update a message content /// Update a message content
Future<bool> updateMessage(int id, String newContent) async { Future<bool> updateMessage(int? id, String newContent) async {
final response = await APIRequest( final response = await APIRequest(
uri: "conversations/updateMessage", uri: "conversations/updateMessage",
needLogin: true, needLogin: true,
@ -400,7 +399,7 @@ class ConversationsHelper {
} }
/// Delete permanently a message specified by its [id] /// Delete permanently a message specified by its [id]
Future<bool> deleteMessage(int id) async { Future<bool> deleteMessage(int? id) async {
// Delete the message online // Delete the message online
final response = await APIRequest( final response = await APIRequest(
uri: "conversations/deleteMessage", uri: "conversations/deleteMessage",
@ -418,7 +417,7 @@ class ConversationsHelper {
static Future<UnreadConversationsList> getListUnread() async { static Future<UnreadConversationsList> getListUnread() async {
final list = (await APIRequest.withLogin("conversations/get_list_unread") final list = (await APIRequest.withLogin("conversations/get_list_unread")
.execWithThrow()) .execWithThrow())
.getArray(); .getArray()!;
return UnreadConversationsList() return UnreadConversationsList()
..addAll(list.map((f) => UnreadConversation( ..addAll(list.map((f) => UnreadConversation(
@ -431,7 +430,7 @@ class ConversationsHelper {
/// conversation through WebSocket /// conversation through WebSocket
Future<void> registerConversationEvents(int id) async { Future<void> registerConversationEvents(int id) async {
if (_registeredConversations.containsKey(id)) if (_registeredConversations.containsKey(id))
_registeredConversations[id]++; _registeredConversations.update(id, (value) => value + 1);
else { else {
_registeredConversations[id] = 1; _registeredConversations[id] = 1;
await ws("\$main/register_conv", {"convID": id}); await ws("\$main/register_conv", {"convID": id});
@ -442,16 +441,16 @@ class ConversationsHelper {
Future<void> unregisterConversationEvents(int id) async { Future<void> unregisterConversationEvents(int id) async {
if (!_registeredConversations.containsKey(id)) return; if (!_registeredConversations.containsKey(id)) return;
_registeredConversations[id]--; _registeredConversations.update(id, (value) => value - 1);
if (_registeredConversations[id] <= 0) { if (_registeredConversations[id]! <= 0) {
_registeredConversations.remove(id); _registeredConversations.remove(id);
await ws("\$main/unregister_conv", {"convID": id}); await ws("\$main/unregister_conv", {"convID": id});
} }
} }
/// Send a notification to inform that the user is writing a message /// Send a notification to inform that the user is writing a message
static Future<void> sendWritingEvent(int convID) async => static Future<void> sendWritingEvent(int? convID) async =>
await ws("conversations/is_writing", {"convID": convID}); await ws("conversations/is_writing", {"convID": convID});
/// Turn an API response into a ConversationMessage object /// Turn an API response into a ConversationMessage object

View File

@ -9,11 +9,11 @@ import 'package:sqflite/sqflite.dart';
/// @author Pierre HUBERT /// @author Pierre HUBERT
abstract class DatabaseHelper { abstract class DatabaseHelper {
static Database _db; static Database? _db;
/// Open the database /// Open the database
static Future<void> open() async { static Future<void> open() async {
if (_db != null && _db.isOpen) return; if (_db != null && _db!.isOpen) return;
var databasePath = await getDatabasesPath(); var databasePath = await getDatabasesPath();
_db = await openDatabase( _db = await openDatabase(
@ -24,7 +24,7 @@ abstract class DatabaseHelper {
} }
/// Get a database instance /// Get a database instance
static Future<Database> get() async { static Future<Database?> get() async {
await open(); await open();
return _db; return _db;
} }

View File

@ -18,12 +18,12 @@ abstract class ModelDatabaseHelper<T extends CacheModel> {
/// Insert an entry in the database /// Insert an entry in the database
Future<void> _insertDB(T el) async { Future<void> _insertDB(T el) async {
await (await DatabaseHelper.get()).insert(tableName(), el.toMap()); await (await DatabaseHelper.get())!.insert(tableName(), el.toMap());
} }
/// Update an element in the database /// Update an element in the database
Future<void> _updateDB(T el) async { Future<void> _updateDB(T el) async {
await (await DatabaseHelper.get()).update( await (await DatabaseHelper.get())!.update(
tableName(), tableName(),
el.toMap(), el.toMap(),
where: "${BaseTableContract.C_ID} = ?", where: "${BaseTableContract.C_ID} = ?",
@ -34,14 +34,14 @@ abstract class ModelDatabaseHelper<T extends CacheModel> {
/// Get an element from the database with a specified [id] /// Get an element from the database with a specified [id]
/// ///
/// Returns null if none found /// Returns null if none found
Future<T> get(int id) async { Future<T?> get(int id) async {
List<Map> maps = await (await DatabaseHelper.get()).query( List<Map> maps = await (await DatabaseHelper.get())!.query(
tableName(), tableName(),
where: '${BaseTableContract.C_ID} = ?', where: '${BaseTableContract.C_ID} = ?',
whereArgs: [id], whereArgs: [id],
); );
if (maps.length > 0) return initializeFromMap(maps[0]); if (maps.length > 0) return initializeFromMap(maps[0] as Map<String, dynamic>);
return null; return null;
} }
@ -50,7 +50,7 @@ abstract class ModelDatabaseHelper<T extends CacheModel> {
/// ///
/// Return true if at least one entry was deleted / false else /// Return true if at least one entry was deleted / false else
Future<bool> delete(int id) async { Future<bool> delete(int id) async {
return await (await DatabaseHelper.get()).delete( return await (await DatabaseHelper.get())!.delete(
tableName(), tableName(),
where: '${BaseTableContract.C_ID} = ?', where: '${BaseTableContract.C_ID} = ?',
whereArgs: [id], whereArgs: [id],
@ -59,22 +59,22 @@ abstract class ModelDatabaseHelper<T extends CacheModel> {
/// Get all the entries from the table /// Get all the entries from the table
Future<List<T>> getAll() async { Future<List<T>> getAll() async {
List<Map> maps = await (await DatabaseHelper.get()).query(tableName()); List<Map> maps = await (await DatabaseHelper.get())!.query(tableName());
return maps.map((f) => initializeFromMap(f)).toList(); return maps.map((f) => initializeFromMap(f as Map<String, dynamic>)).toList();
} }
/// Get some entries from the table based on some conditions /// Get some entries from the table based on some conditions
Future<List<T>> getMultiple( Future<List<T>> getMultiple(
{bool distinct, {bool? distinct,
List<String> columns, List<String>? columns,
String where, String? where,
List<dynamic> whereArgs, List<dynamic>? whereArgs,
String groupBy, String? groupBy,
String having, String? having,
String orderBy, String? orderBy,
int limit, int? limit,
int offset}) async { int? offset}) async {
List<Map> maps = await (await DatabaseHelper.get()).query( List<Map> maps = await (await DatabaseHelper.get())!.query(
tableName(), tableName(),
distinct: distinct, distinct: distinct,
columns: columns, columns: columns,
@ -86,12 +86,12 @@ abstract class ModelDatabaseHelper<T extends CacheModel> {
limit: limit, limit: limit,
offset: offset, offset: offset,
); );
return maps.map((f) => initializeFromMap(f)).toList(); return maps.map((f) => initializeFromMap(f as Map<String, dynamic>)).toList();
} }
/// Empty the table /// Empty the table
Future<void> clearTable() async { Future<void> clearTable() async {
await (await DatabaseHelper.get()).execute("DELETE FROM ${tableName()}"); await (await DatabaseHelper.get())!.execute("DELETE FROM ${tableName()}");
} }
/// Check out whether an element specified with its [id] is present /// Check out whether an element specified with its [id] is present

View File

@ -17,14 +17,14 @@ class WSClosedEvent {}
/// New number of notifications /// New number of notifications
class NewNumberNotifsEvent { class NewNumberNotifsEvent {
final int newNum; final int? newNum;
NewNumberNotifsEvent(this.newNum); NewNumberNotifsEvent(this.newNum);
} }
/// New number of unread conversations /// New number of unread conversations
class NewNumberUnreadConversations { class NewNumberUnreadConversations {
final int newNum; final int? newNum;
NewNumberUnreadConversations(this.newNum); NewNumberUnreadConversations(this.newNum);
} }
@ -45,15 +45,15 @@ class UpdatedCommentEvent {
/// Deleted comment /// Deleted comment
class DeletedCommentEvent { class DeletedCommentEvent {
final int commentID; final int? commentID;
DeletedCommentEvent(this.commentID); DeletedCommentEvent(this.commentID);
} }
/// Writing message in conversation event /// Writing message in conversation event
class WritingMessageInConversationEvent { class WritingMessageInConversationEvent {
final int convID; final int? convID;
final int userID; final int? userID;
WritingMessageInConversationEvent(this.convID, this.userID); WritingMessageInConversationEvent(this.convID, this.userID);
} }
@ -81,31 +81,31 @@ class DeletedConversationMessageEvent {
/// Remove user from conversation /// Remove user from conversation
class RemovedUserFromConversationEvent { class RemovedUserFromConversationEvent {
final int convID; final int? convID;
final int userID; final int? userID;
RemovedUserFromConversationEvent(this.convID, this.userID); RemovedUserFromConversationEvent(this.convID, this.userID);
} }
/// Deleted conversation /// Deleted conversation
class DeletedConversationEvent { class DeletedConversationEvent {
final int convID; final int? convID;
DeletedConversationEvent(this.convID); DeletedConversationEvent(this.convID);
} }
/// User joined call event /// User joined call event
class UserJoinedCallEvent { class UserJoinedCallEvent {
final int callID; final int? callID;
final int userID; final int? userID;
UserJoinedCallEvent(this.callID, this.userID); UserJoinedCallEvent(this.callID, this.userID);
} }
/// User left call event /// User left call event
class UserLeftCallEvent { class UserLeftCallEvent {
final int callID; final int? callID;
final int userID; final int? userID;
UserLeftCallEvent(this.callID, this.userID); UserLeftCallEvent(this.callID, this.userID);
} }
@ -114,12 +114,12 @@ class UserLeftCallEvent {
class NewCallSignalEvent { class NewCallSignalEvent {
final int callID; final int callID;
final int peerID; final int peerID;
final RTCSessionDescription sessionDescription; final RTCSessionDescription? sessionDescription;
final RTCIceCandidate candidate; final RTCIceCandidate? candidate;
const NewCallSignalEvent({ const NewCallSignalEvent({
this.callID, required this.callID,
this.peerID, required this.peerID,
this.sessionDescription, this.sessionDescription,
this.candidate, this.candidate,
}) : assert(callID != null), }) : assert(callID != null),
@ -129,23 +129,23 @@ class NewCallSignalEvent {
/// Call peer ready event /// Call peer ready event
class CallPeerReadyEvent { class CallPeerReadyEvent {
final int callID; final int? callID;
final int peerID; final int? peerID;
CallPeerReadyEvent(this.callID, this.peerID); CallPeerReadyEvent(this.callID, this.peerID);
} }
/// Call peer interrupted streaming event /// Call peer interrupted streaming event
class CallPeerInterruptedStreamingEvent { class CallPeerInterruptedStreamingEvent {
final int callID; final int? callID;
final int peerID; final int? peerID;
CallPeerInterruptedStreamingEvent(this.callID, this.peerID); CallPeerInterruptedStreamingEvent(this.callID, this.peerID);
} }
/// Call closed event /// Call closed event
class CallClosedEvent { class CallClosedEvent {
final int callID; final int? callID;
CallClosedEvent(this.callID); CallClosedEvent(this.callID);
} }

View File

@ -20,7 +20,7 @@ class FirebaseMessagingHelper {
} }
/// Get a Firebase access token /// Get a Firebase access token
static Future<String> getToken() async { static Future<String?> getToken() async {
return await FirebaseMessaging.instance.getToken(); return await FirebaseMessaging.instance.getToken();
} }
} }

View File

@ -11,7 +11,7 @@ import 'package:comunic/models/group.dart';
class ForezGroupsHelper { class ForezGroupsHelper {
static Future<List<Group>> getForezGroups() async { static Future<List<Group>> getForezGroups() async {
return (await APIRequest.withLogin("forez/get_groups").execWithThrow()) return (await APIRequest.withLogin("forez/get_groups").execWithThrow())
.getArray() .getArray()!
.cast<Map<String, dynamic>>() .cast<Map<String, dynamic>>()
.map(GroupsHelper.getGroupFromAPI) .map(GroupsHelper.getGroupFromAPI)
.toList(); .toList();
@ -21,10 +21,10 @@ class ForezGroupsHelper {
/// ///
/// This methods throws an exception in case of failure /// This methods throws an exception in case of failure
static Future<AdvancedUserInfo> getMemberInfo(int groupID, int userID) async { static Future<AdvancedUserInfo> getMemberInfo(int groupID, int userID) async {
final response = await APIRequest.withLogin("forez/get_member_info") final response = await (APIRequest.withLogin("forez/get_member_info")
.addInt("group", groupID) .addInt("group", groupID)
.addInt("user", userID) .addInt("user", userID)
.execWithThrowGetObject(); .execWithThrowGetObject());
return UsersHelper.apiToAdvancedUserInfo(response); return UsersHelper.apiToAdvancedUserInfo(response);
} }

View File

@ -6,8 +6,8 @@ import 'package:comunic/models/forez_presence.dart';
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
int _cachedGroup; int? _cachedGroup;
PresenceSet _cache; PresenceSet? _cache;
class ForezPresenceHelper { class ForezPresenceHelper {
/// Refresh presence cache /// Refresh presence cache
@ -40,16 +40,16 @@ class ForezPresenceHelper {
/// Get the presences of a given user /// Get the presences of a given user
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<PresenceSet> getForUser(int groupID, int userID) async { static Future<PresenceSet> getForUser(int groupID, int? userID) async {
await _checkCache(groupID); await _checkCache(groupID);
return _cache.getForUser(userID); return _cache!.getForUser(userID);
} }
/// Get all the available presences /// Get all the available presences
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<PresenceSet> getAll(int groupID) async { static Future<PresenceSet?> getAll(int groupID) async {
await _checkCache(groupID); await _checkCache(groupID);
return _cache; return _cache;
} }

View File

@ -3,7 +3,6 @@ import 'package:comunic/lists/friends_list.dart';
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/friend.dart'; import 'package:comunic/models/friend.dart';
import 'package:comunic/models/friend_status.dart'; import 'package:comunic/models/friend_status.dart';
import 'package:meta/meta.dart';
/// Friends helper /// Friends helper
/// ///
@ -16,7 +15,7 @@ class FriendsHelper {
/// ///
/// Returns the list of friends in case of success, or null if an error /// Returns the list of friends in case of success, or null if an error
/// occurred /// occurred
Future<FriendsList> _downloadList() async { Future<FriendsList?> _downloadList() async {
final response = await APIRequest( final response = await APIRequest(
uri: "friends/getList", uri: "friends/getList",
needLogin: true, needLogin: true,
@ -30,7 +29,7 @@ class FriendsHelper {
// Parse and return the list of friends // Parse and return the list of friends
FriendsList list = FriendsList() FriendsList list = FriendsList()
..addAll(response ..addAll(response
.getArray() .getArray()!
.cast<Map<String, dynamic>>() .cast<Map<String, dynamic>>()
.map(apiToFriend) .map(apiToFriend)
.toList()); .toList());
@ -54,7 +53,7 @@ class FriendsHelper {
} }
/// Get the list, either from an online or an offline source /// Get the list, either from an online or an offline source
Future<FriendsList> getList({@required bool online}) async { Future<FriendsList?> getList({required bool online}) async {
if (online) if (online)
return await _downloadList(); return await _downloadList();
else else
@ -108,7 +107,7 @@ class FriendsHelper {
if (response.code != 200) if (response.code != 200)
throw Exception("Could not get friendship status!"); throw Exception("Could not get friendship status!");
final obj = response.getObject(); final obj = response.getObject()!;
return FriendStatus( return FriendStatus(
userID: userID, userID: userID,
@ -132,7 +131,7 @@ class FriendsHelper {
if (response.code != 200) if (response.code != 200)
throw new Exception("Could not get the list of friends of this user!"); throw new Exception("Could not get the list of friends of this user!");
return Set<int>.from(response.getArray()); return Set<int>.from(response.getArray()!);
} }
/// Send a friendship request to a specified user /// Send a friendship request to a specified user

View File

@ -49,7 +49,7 @@ enum GetAdvancedInfoStatus { SUCCESS, ACCESS_DENIED }
class GetAdvancedInfoResult { class GetAdvancedInfoResult {
final GetAdvancedInfoStatus status; final GetAdvancedInfoStatus status;
final AdvancedGroupInfo info; final AdvancedGroupInfo? info;
GetAdvancedInfoResult(this.status, this.info) : assert(status != null); GetAdvancedInfoResult(this.status, this.info) : assert(status != null);
} }
@ -57,7 +57,7 @@ class GetAdvancedInfoResult {
/// Groups helper /// Groups helper
class GroupsHelper { class GroupsHelper {
/// Download a list of groups information from the server /// Download a list of groups information from the server
Future<GroupsList> _downloadList(Set<int> groups) async { Future<GroupsList?> _downloadList(Set<int?> groups) async {
final response = await APIRequest( final response = await APIRequest(
uri: "groups/get_multiple_info", uri: "groups/get_multiple_info",
needLogin: true, needLogin: true,
@ -69,7 +69,7 @@ class GroupsHelper {
final list = GroupsList(); final list = GroupsList();
response response
.getObject() .getObject()!
.forEach((k, d) => list[int.parse(k)] = getGroupFromAPI(d)); .forEach((k, d) => list[int.parse(k)] = getGroupFromAPI(d));
return list; return list;
@ -77,7 +77,7 @@ class GroupsHelper {
/// Get a list of groups from the server. In case of error, this method throws /// Get a list of groups from the server. In case of error, this method throws
/// an exception /// an exception
Future<GroupsList> getListOrThrow(Set<int> groups, Future<GroupsList> getListOrThrow(Set<int?> groups,
{bool force = false}) async { {bool force = false}) async {
final list = await getList(groups, force: force); final list = await getList(groups, force: force);
@ -87,11 +87,11 @@ class GroupsHelper {
} }
/// Get a list of groups from the server /// Get a list of groups from the server
Future<GroupsList> getList(Set<int> groups, {bool force = false}) async { Future<GroupsList?> getList(Set<int?> groups, {bool force = false}) async {
final list = GroupsList(); final list = GroupsList();
// Check which groups information to download // Check which groups information to download
final toDownload = Set<int>(); final toDownload = Set<int?>();
groups.forEach((groupID) { groups.forEach((groupID) {
if (!force && _groupsListCache.containsKey(groupID)) if (!force && _groupsListCache.containsKey(groupID))
list[groupID] = _groupsListCache[groupID]; list[groupID] = _groupsListCache[groupID];
@ -122,10 +122,10 @@ class GroupsHelper {
} }
/// Get the list of groups of a user /// Get the list of groups of a user
Future<Set<int>> getListUser() async => Future<Set<int?>> getListUser() async =>
(await APIRequest(uri: "groups/get_my_list", needLogin: true).exec()) (await APIRequest(uri: "groups/get_my_list", needLogin: true).exec())
.assertOk() .assertOk()
.getArray() .getArray()!
.map((f) => cast<int>(f)) .map((f) => cast<int>(f))
.toSet(); .toSet();
@ -142,7 +142,7 @@ class GroupsHelper {
/// Perform a simple membership request /// Perform a simple membership request
static Future<bool> _simpleMembershipRequest(int groupID, String uri, static Future<bool> _simpleMembershipRequest(int groupID, String uri,
{Map<String, String> args}) async => {Map<String, String>? args}) async =>
(await (APIRequest.withLogin(uri) (await (APIRequest.withLogin(uri)
..addInt("id", groupID) ..addInt("id", groupID)
..addArgs(args == null ? Map() : args)) ..addArgs(args == null ? Map() : args))
@ -176,7 +176,7 @@ class GroupsHelper {
.isOK; .isOK;
/// Get advanced information about the user /// Get advanced information about the user
Future<GetAdvancedInfoResult> getAdvancedInfo(int groupID) async { Future<GetAdvancedInfoResult> getAdvancedInfo(int? groupID) async {
// Get advanced information about the user // Get advanced information about the user
final result = final result =
await (APIRequest(uri: "groups/get_advanced_info", needLogin: true) await (APIRequest(uri: "groups/get_advanced_info", needLogin: true)
@ -189,7 +189,7 @@ class GroupsHelper {
case 200: case 200:
return GetAdvancedInfoResult(GetAdvancedInfoStatus.SUCCESS, return GetAdvancedInfoResult(GetAdvancedInfoStatus.SUCCESS,
_getAdvancedGroupInfoFromAPI(result.getObject())); _getAdvancedGroupInfoFromAPI(result.getObject()!));
default: default:
throw Exception("Could not get advanced group information!"); throw Exception("Could not get advanced group information!");
@ -202,7 +202,7 @@ class GroupsHelper {
/// change in the future /// change in the future
/// ///
/// Throws in case of error /// Throws in case of error
Future<AdvancedGroupInfo> getSettings(int groupID) async { Future<AdvancedGroupInfo?> getSettings(int groupID) async {
final groupInfo = await getAdvancedInfo(groupID); final groupInfo = await getAdvancedInfo(groupID);
if (groupInfo.status != GetAdvancedInfoStatus.SUCCESS) if (groupInfo.status != GetAdvancedInfoStatus.SUCCESS)
@ -239,7 +239,7 @@ class GroupsHelper {
"posts_level", "posts_level",
invertMap( invertMap(
_APIGroupsPostsCreationLevelsMap)[settings.postCreationLevel]) _APIGroupsPostsCreationLevelsMap)[settings.postCreationLevel])
.addBool("is_members_list_public", settings.isMembersListPublic) .addBool("is_members_list_public", settings.isMembersListPublic!)
.addString("description", settings.description) .addString("description", settings.description)
.addString("url", settings.url) .addString("url", settings.url)
.execWithThrow(); .execWithThrow();
@ -248,7 +248,7 @@ class GroupsHelper {
/// Upload a new logo /// Upload a new logo
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> uploadNewLogo(int groupID, Uint8List bytes) async => static Future<void> uploadNewLogo(int groupID, Uint8List? bytes) async =>
await APIRequest(uri: "groups/upload_logo", needLogin: true) await APIRequest(uri: "groups/upload_logo", needLogin: true)
.addInt("id", groupID) .addInt("id", groupID)
.addBytesFile("logo", BytesFile("logo.png", bytes)) .addBytesFile("logo", BytesFile("logo.png", bytes))
@ -279,7 +279,7 @@ class GroupsHelper {
..addAll((await APIRequest(uri: "groups/get_members", needLogin: true) ..addAll((await APIRequest(uri: "groups/get_members", needLogin: true)
.addInt("id", groupID) .addInt("id", groupID)
.execWithThrow()) .execWithThrow())
.getArray() .getArray()!
.map((f) => _apiToGroupMembership(f)) .map((f) => _apiToGroupMembership(f))
.toList()); .toList());
@ -295,7 +295,7 @@ class GroupsHelper {
/// Cancel a group membership invitation /// Cancel a group membership invitation
/// ///
/// Throws an exception in case of failure /// Throws an exception in case of failure
static Future<void> cancelInvitation(int groupID, int userID) async => static Future<void> cancelInvitation(int groupID, int? userID) async =>
await APIRequest.withLogin("groups/cancel_invitation") await APIRequest.withLogin("groups/cancel_invitation")
.addInt("groupID", groupID) .addInt("groupID", groupID)
.addInt("userID", userID) .addInt("userID", userID)
@ -305,7 +305,7 @@ class GroupsHelper {
/// ///
/// Throws an exception in case of failure /// Throws an exception in case of failure
static Future<void> respondRequest( static Future<void> respondRequest(
int groupID, int userID, bool accept) async => int groupID, int? userID, bool accept) async =>
await APIRequest.withLogin("groups/respond_request") await APIRequest.withLogin("groups/respond_request")
.addInt("groupID", groupID) .addInt("groupID", groupID)
.addInt("userID", userID) .addInt("userID", userID)
@ -351,7 +351,7 @@ class GroupsHelper {
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> setConversationVisibility( static Future<void> setConversationVisibility(
int convID, GroupMembershipLevel newLevel) async => int? convID, GroupMembershipLevel? newLevel) async =>
await APIRequest.withLogin("groups/set_conversation_visibility") await APIRequest.withLogin("groups/set_conversation_visibility")
.addInt("conv_id", convID) .addInt("conv_id", convID)
.addString( .addString(
@ -364,7 +364,7 @@ class GroupsHelper {
/// Delete a group's conversation /// Delete a group's conversation
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> deleteConversation(int convID) async => static Future<void> deleteConversation(int? convID) async =>
await APIRequest.withLogin("groups/delete_conversation") await APIRequest.withLogin("groups/delete_conversation")
.addInt("conv_id", convID) .addInt("conv_id", convID)
.execWithThrow(); .execWithThrow();
@ -376,11 +376,11 @@ class GroupsHelper {
name: map["name"], name: map["name"],
iconURL: map["icon_url"], iconURL: map["icon_url"],
numberMembers: map["number_members"], numberMembers: map["number_members"],
membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]], membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]]!,
visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]], visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]]!,
registrationLevel: registrationLevel:
_APIGroupsRegistrationLevelsMap[map["registration_level"]], _APIGroupsRegistrationLevelsMap[map["registration_level"]]!,
postCreationLevel: _APIGroupsPostsCreationLevelsMap[map["posts_level"]], postCreationLevel: _APIGroupsPostsCreationLevelsMap[map["posts_level"]]!,
virtualDirectory: nullToEmpty(map["virtual_directory"]), virtualDirectory: nullToEmpty(map["virtual_directory"]),
following: map["following"]); following: map["following"]);
} }
@ -392,11 +392,11 @@ class GroupsHelper {
name: map["name"], name: map["name"],
iconURL: map["icon_url"], iconURL: map["icon_url"],
numberMembers: map["number_members"], numberMembers: map["number_members"],
membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]], membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]]!,
visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]], visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]]!,
registrationLevel: registrationLevel:
_APIGroupsRegistrationLevelsMap[map["registration_level"]], _APIGroupsRegistrationLevelsMap[map["registration_level"]]!,
postCreationLevel: _APIGroupsPostsCreationLevelsMap[map["posts_level"]], postCreationLevel: _APIGroupsPostsCreationLevelsMap[map["posts_level"]]!,
isMembersListPublic: map["is_members_list_public"], isMembersListPublic: map["is_members_list_public"],
virtualDirectory: nullToEmpty(map["virtual_directory"]), virtualDirectory: nullToEmpty(map["virtual_directory"]),
following: map["following"], following: map["following"],
@ -418,6 +418,6 @@ class GroupsHelper {
userID: row["user_id"], userID: row["user_id"],
groupID: row["group_id"], groupID: row["group_id"],
timeCreate: row["time_create"], timeCreate: row["time_create"],
level: APIGroupsMembershipLevelsMap[row["level"]], level: APIGroupsMembershipLevelsMap[row["level"]]!,
); );
} }

View File

@ -29,7 +29,7 @@ class IndependentPushNotificationsHelper {
} }
/// Configure independent push notification services with a pull URL /// Configure independent push notification services with a pull URL
static Future<void> configure(String wsURL) async { static Future<void> configure(String? wsURL) async {
await platform.invokeMethod("configure", wsURL); await platform.invokeMethod("configure", wsURL);
} }

View File

@ -1,6 +1,5 @@
import 'package:comunic/enums/likes_type.dart'; import 'package:comunic/enums/likes_type.dart';
import 'package:comunic/helpers/websocket_helper.dart'; import 'package:comunic/helpers/websocket_helper.dart';
import 'package:meta/meta.dart';
/// Likes helper /// Likes helper
/// ///
@ -16,9 +15,9 @@ const LikesAPIMap = {
class LikesHelper { class LikesHelper {
/// Update liking status of an element /// Update liking status of an element
Future<void> setLiking({ Future<void> setLiking({
@required LikesType type, required LikesType type,
@required bool like, required bool like,
@required int id, required int id,
}) async { }) async {
return (await ws("likes/update", { return (await ws("likes/update", {
"type": LikesAPIMap[type], "type": LikesAPIMap[type],

View File

@ -55,7 +55,7 @@ class NotificationsHelper {
await APIRequest(uri: "notifications/count_all_news", needLogin: true) await APIRequest(uri: "notifications/count_all_news", needLogin: true)
.exec(); .exec();
final content = response.assertOk().getObject(); final content = response.assertOk().getObject()!;
return CountUnreadNotifications( return CountUnreadNotifications(
notifications: content["notifications"], notifications: content["notifications"],
@ -75,15 +75,15 @@ class NotificationsHelper {
// Parse the list of notifications // Parse the list of notifications
return NotificationsList() return NotificationsList()
..addAll(response ..addAll(response
.getArray() .getArray()!
.map((f) => Notification( .map((f) => Notification(
id: f["id"], id: f["id"],
timeCreate: f["time_create"], timeCreate: f["time_create"],
seen: f["seen"], seen: f["seen"],
fromUser: f["from_user_id"], fromUser: f["from_user_id"],
onElemId: f["on_elem_id"], onElemId: f["on_elem_id"],
onElemType: _NotificationElementTypeAPImapping[f["on_elem_type"]], onElemType: _NotificationElementTypeAPImapping[f["on_elem_type"]]!,
type: _NotificationsTypeAPImapping[f["type"]], type: _NotificationsTypeAPImapping[f["type"]]!,
fromContainerId: f["from_container_id"], fromContainerId: f["from_container_id"],
fromContainerType: f["from_container_type"] == "" fromContainerType: f["from_container_type"] == ""
? null ? null

View File

@ -55,7 +55,7 @@ class PostsHelper {
/// Get the list of latest posts. Return the list of posts or null in case of /// Get the list of latest posts. Return the list of posts or null in case of
/// failure /// failure
Future<PostsList> getLatest({int from = 0}) async { Future<PostsList?> getLatest({int from = 0}) async {
final response = final response =
await APIRequest(uri: "posts/get_latest", needLogin: true, args: { await APIRequest(uri: "posts/get_latest", needLogin: true, args: {
"include_groups": true.toString(), "include_groups": true.toString(),
@ -66,7 +66,8 @@ class PostsHelper {
try { try {
// Parse & return the list of posts // Parse & return the list of posts
return PostsList()..addAll(response.getArray().map((f) => _apiToPost(f))); return PostsList()
..addAll(response.getArray()!.map((f) => _apiToPost(f)));
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
return null; return null;
@ -74,7 +75,7 @@ class PostsHelper {
} }
/// Get the list of posts of a user /// Get the list of posts of a user
Future<PostsList> getUserPosts(int userID, {int from = 0}) async { Future<PostsList?> getUserPosts(int? userID, {int from = 0}) async {
final response = await (APIRequest(uri: "posts/get_user", needLogin: true) final response = await (APIRequest(uri: "posts/get_user", needLogin: true)
..addInt("userID", userID) ..addInt("userID", userID)
..addInt("startFrom", from == 0 ? 0 : from - 1)) ..addInt("startFrom", from == 0 ? 0 : from - 1))
@ -84,7 +85,8 @@ class PostsHelper {
try { try {
// Parse & return the list of posts // Parse & return the list of posts
return PostsList()..addAll(response.getArray().map((f) => _apiToPost(f))); return PostsList()
..addAll(response.getArray()!.map((f) => _apiToPost(f)));
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
return null; return null;
@ -92,7 +94,7 @@ class PostsHelper {
} }
/// Get the list of posts of a group /// Get the list of posts of a group
Future<PostsList> getGroupPosts(int groupID, {int from = 0}) async { Future<PostsList?> getGroupPosts(int groupID, {int from = 0}) async {
final response = await (APIRequest(uri: "posts/get_group", needLogin: true) final response = await (APIRequest(uri: "posts/get_group", needLogin: true)
..addInt("groupID", groupID) ..addInt("groupID", groupID)
..addInt("startFrom", from == 0 ? 0 : from - 1)) ..addInt("startFrom", from == 0 ? 0 : from - 1))
@ -102,7 +104,8 @@ class PostsHelper {
try { try {
// Parse & return the list of posts // Parse & return the list of posts
return PostsList()..addAll(response.getArray().map((f) => _apiToPost(f))); return PostsList()
..addAll(response.getArray()!.map((f) => _apiToPost(f)));
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
return null; return null;
@ -120,7 +123,7 @@ class PostsHelper {
if (!response.isOK) if (!response.isOK)
throw Exception("Could not get information about the post!"); throw Exception("Could not get information about the post!");
return _apiToPost(response.getObject()); return _apiToPost(response.getObject()!);
} }
/// Create a new post /// Create a new post
@ -158,13 +161,14 @@ class PostsHelper {
case PostKind.COUNTDOWN: case PostKind.COUNTDOWN:
request.addInt( request.addInt(
"time-end", (post.timeEnd.millisecondsSinceEpoch / 1000).floor()); "time-end", (post.timeEnd!.millisecondsSinceEpoch / 1000).floor());
break; break;
case PostKind.SURVEY: case PostKind.SURVEY:
request.addString("question", post.survey.question); request.addString("question", post.survey!.question);
request.addString("answers", post.survey.answers.join("<>")); request.addString("answers", post.survey!.answers.join("<>"));
request.addBool("allowNewAnswers", post.survey.allowNewChoicesCreation); request.addBool(
"allowNewAnswers", post.survey!.allowNewChoicesCreation);
break; break;
case PostKind.YOUTUBE: case PostKind.YOUTUBE:
@ -221,7 +225,7 @@ class PostsHelper {
/// Register to a post events /// Register to a post events
Future<void> registerPostEvents(int id) async { Future<void> registerPostEvents(int id) async {
if (_registeredPosts.containsKey(id)) if (_registeredPosts.containsKey(id))
_registeredPosts[id]++; _registeredPosts.update(id, (v) => v + 1);
else { else {
_registeredPosts[id] = 1; _registeredPosts[id] = 1;
await ws("\$main/register_post", {"postID": id}); await ws("\$main/register_post", {"postID": id});
@ -232,9 +236,9 @@ class PostsHelper {
Future<void> unregisterPostEvents(int id) async { Future<void> unregisterPostEvents(int id) async {
if (!_registeredPosts.containsKey(id)) return; if (!_registeredPosts.containsKey(id)) return;
_registeredPosts[id]--; _registeredPosts.update(id, (v) => v - 1);
if (_registeredPosts[id] <= 0) { if (_registeredPosts[id]! <= 0) {
_registeredPosts.remove(id); _registeredPosts.remove(id);
await ws("\$main/unregister_post", {"postID": id}); await ws("\$main/unregister_post", {"postID": id});
} }
@ -242,14 +246,14 @@ class PostsHelper {
/// Turn an API entry into a [Post] object /// Turn an API entry into a [Post] object
Post _apiToPost(Map<String, dynamic> map) { Post _apiToPost(Map<String, dynamic> map) {
final postKind = _APIPostsKindsMap[map["kind"]]; final postKind = _APIPostsKindsMap[map["kind"]]!;
// Parse comments // Parse comments
CommentsList comments; CommentsList? comments;
if (map["comments"] != null) { if (map["comments"] != null) {
comments = CommentsList(); comments = CommentsList();
map["comments"] map["comments"]
.forEach((v) => comments.add(CommentsHelper.apiToComment(v))); .forEach((v) => comments!.add(CommentsHelper.apiToComment(v)));
} }
final survey = postKind == PostKind.SURVEY final survey = postKind == PostKind.SURVEY
@ -263,7 +267,7 @@ class PostsHelper {
groupID: map["group_id"], groupID: map["group_id"],
timeSent: map["post_time"], timeSent: map["post_time"],
content: DisplayedString(map["content"]), content: DisplayedString(map["content"]),
visibilityLevel: _APIPostsVisibilityLevelMap[map["visibility_level"]], visibilityLevel: _APIPostsVisibilityLevelMap[map["visibility_level"]]!,
kind: postKind, kind: postKind,
fileSize: map["file_size"], fileSize: map["file_size"],
fileType: map["file_type"], fileType: map["file_type"],
@ -276,7 +280,7 @@ class PostsHelper {
linkImage: map["link_image"], linkImage: map["link_image"],
likes: map["likes"], likes: map["likes"],
userLike: map["userlike"], userLike: map["userlike"],
access: _APIUserAccessMap[map["user_access"]], access: _APIUserAccessMap[map["user_access"]]!,
comments: comments, comments: comments,
survey: survey); survey: survey);
} }

View File

@ -30,7 +30,7 @@ const _PreferenceKeysName = {
}; };
class PreferencesHelper { class PreferencesHelper {
static PreferencesHelper _instance; static PreferencesHelper? _instance;
static Future<PreferencesHelper> getInstance() async { static Future<PreferencesHelper> getInstance() async {
if (_instance == null) { if (_instance == null) {
@ -38,10 +38,10 @@ class PreferencesHelper {
await _init(); await _init();
} }
return _instance; return _instance!;
} }
static SharedPreferences _sharedPreferences; static late SharedPreferences _sharedPreferences;
PreferencesHelper._(); PreferencesHelper._();
@ -50,7 +50,7 @@ class PreferencesHelper {
} }
/// Set new login tokens /// Set new login tokens
Future<void> setLoginToken(String token) async { Future<void> setLoginToken(String? token) async {
if (token != null) if (token != null)
await setString(PreferencesKeyList.LOGIN_TOKEN, token); await setString(PreferencesKeyList.LOGIN_TOKEN, token);
else else
@ -58,7 +58,7 @@ class PreferencesHelper {
} }
/// Get current [LoginTokens]. Returns null if none or in case of failure /// Get current [LoginTokens]. Returns null if none or in case of failure
String getLoginToken() { String? getLoginToken() {
try { try {
final string = getString(PreferencesKeyList.LOGIN_TOKEN); final string = getString(PreferencesKeyList.LOGIN_TOKEN);
return string; return string;
@ -69,35 +69,35 @@ class PreferencesHelper {
} }
bool containsKey(PreferencesKeyList key) { bool containsKey(PreferencesKeyList key) {
return _sharedPreferences.containsKey(_PreferenceKeysName[key]); return _sharedPreferences.containsKey(_PreferenceKeysName[key]!);
} }
Future<bool> removeKey(PreferencesKeyList key) async { Future<bool> removeKey(PreferencesKeyList key) async {
return await _sharedPreferences.remove(_PreferenceKeysName[key]); return await _sharedPreferences.remove(_PreferenceKeysName[key]!);
} }
Future<bool> setString(PreferencesKeyList key, String value) async { Future<bool> setString(PreferencesKeyList key, String value) async {
return await _sharedPreferences.setString(_PreferenceKeysName[key], value); return await _sharedPreferences.setString(_PreferenceKeysName[key]!, value);
} }
String getString(PreferencesKeyList key) { String? getString(PreferencesKeyList key) {
return _sharedPreferences.getString(_PreferenceKeysName[key]); return _sharedPreferences.getString(_PreferenceKeysName[key]!);
} }
Future<bool> setBool(PreferencesKeyList key, bool value) async { Future<bool> setBool(PreferencesKeyList key, bool value) async {
return await _sharedPreferences.setBool(_PreferenceKeysName[key], value); return await _sharedPreferences.setBool(_PreferenceKeysName[key]!, value);
} }
Future<bool> setInt(PreferencesKeyList key, int value) async { Future<bool> setInt(PreferencesKeyList key, int value) async {
return await _sharedPreferences.setInt(_PreferenceKeysName[key], value); return await _sharedPreferences.setInt(_PreferenceKeysName[key]!, value);
} }
int getInt(PreferencesKeyList key) { int? getInt(PreferencesKeyList key) {
return _sharedPreferences.getInt(_PreferenceKeysName[key]); return _sharedPreferences.getInt(_PreferenceKeysName[key]!);
} }
bool getBool(PreferencesKeyList key, {bool alternative = false}) { bool getBool(PreferencesKeyList key, {bool alternative = false}) {
final v = _sharedPreferences.getBool(_PreferenceKeysName[key]); final v = _sharedPreferences.getBool(_PreferenceKeysName[key]!);
return v == null ? alternative : v; return v == null ? alternative : v;
} }
@ -115,7 +115,7 @@ class PreferencesHelper {
} }
} }
PreferencesHelper preferences() { PreferencesHelper? preferences() {
if (PreferencesHelper._instance == null) if (PreferencesHelper._instance == null)
throw Exception("Try to get preference before their initialization!"); throw Exception("Try to get preference before their initialization!");

View File

@ -21,14 +21,14 @@ const _PushNotificationsAPIMap = {
class PushNotificationsHelper { class PushNotificationsHelper {
/// Get cached status of push notifications /// Get cached status of push notifications
static Future<PushNotificationsStatus> getLocalStatus() async { static Future<PushNotificationsStatus?> getLocalStatus() async {
final pref = await PreferencesHelper.getInstance(); final pref = await PreferencesHelper.getInstance();
if (!pref.containsKey(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS)) if (!pref.containsKey(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS))
return PushNotificationsStatus.UNDEFINED; return PushNotificationsStatus.UNDEFINED;
return _PushNotificationsAPIMap[ return _PushNotificationsAPIMap[
pref.getString(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS)]; pref.getString(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS)!];
} }
/// Refresh local status with information from server /// Refresh local status with information from server
@ -47,13 +47,13 @@ class PushNotificationsHelper {
response["independent_push_url"]); response["independent_push_url"]);
} }
await (await PreferencesHelper.getInstance()).setString( await (await PreferencesHelper.getInstance())!.setString(
PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS, response["status"]); PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS, response["status"]);
} }
/// Clear local push notifications status /// Clear local push notifications status
static Future<void> clearLocalStatus() async { static Future<void> clearLocalStatus() async {
await (await PreferencesHelper.getInstance()) await (await PreferencesHelper.getInstance())!
.removeKey(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS); .removeKey(PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS);
// Stop local refresh notification refresh // Stop local refresh notification refresh
@ -62,8 +62,8 @@ class PushNotificationsHelper {
/// Configure push notifications /// Configure push notifications
static Future<void> configure( static Future<void> configure(
BuildContext context, PushNotificationsStatus newStatus) async { BuildContext context, PushNotificationsStatus? newStatus) async {
String firebaseToken = ""; String? firebaseToken = "";
switch (newStatus) { switch (newStatus) {
case PushNotificationsStatus.DISABLED: case PushNotificationsStatus.DISABLED:
break; break;
@ -90,8 +90,8 @@ class PushNotificationsHelper {
/// Set new push notification status on the server /// Set new push notification status on the server
static Future<void> setNewStatus( static Future<void> setNewStatus(
PushNotificationsStatus newStatus, { PushNotificationsStatus? newStatus, {
String firebaseToken = "", String? firebaseToken = "",
}) async => }) async =>
await APIRequest.withLogin("push_notifications/configure") await APIRequest.withLogin("push_notifications/configure")
.addString( .addString(
@ -104,6 +104,6 @@ class PushNotificationsHelper {
/// Is true if possible if push notifications are configurable /// Is true if possible if push notifications are configurable
static bool get arePushNotificationsAvailable => static bool get arePushNotificationsAvailable =>
srvConfig.notificationsPolicy.hasFirebase || srvConfig!.notificationsPolicy.hasFirebase ||
(isAndroid && srvConfig.notificationsPolicy.hasIndependent); (isAndroid && srvConfig!.notificationsPolicy.hasIndependent);
} }

View File

@ -13,7 +13,7 @@ class SearchHelper {
/// Search for user. This method returns information about the target users /// Search for user. This method returns information about the target users
/// ///
/// Returns information about the target users or null if an error occurred /// Returns information about the target users or null if an error occurred
Future<UsersList> searchUser(String query) async { Future<UsersList?> searchUser(String query) async {
// Execute the query on the server // Execute the query on the server
final response = await APIRequest( final response = await APIRequest(
uri: "user/search", needLogin: true, args: {"query": query}).exec(); uri: "user/search", needLogin: true, args: {"query": query}).exec();
@ -21,7 +21,7 @@ class SearchHelper {
if (response.code != 200) return null; if (response.code != 200) return null;
return await UsersHelper() return await UsersHelper()
.getUsersInfo(response.getArray().map((f) => cast<int>(f)).toList()); .getUsersInfo(response.getArray()!.map((f) => cast<int>(f)).toList());
} }
/// Perform a global search /// Perform a global search
@ -31,7 +31,7 @@ class SearchHelper {
result.assertOk(); result.assertOk();
return SearchResultsList()..addAll(result.getArray().map((f) { return SearchResultsList()..addAll(result.getArray()!.map((f) {
switch (f["kind"]) { switch (f["kind"]) {
case "user": case "user":
return SearchResult(id: f["id"], kind: SearchResultKind.USER); return SearchResult(id: f["id"], kind: SearchResultKind.USER);

View File

@ -17,7 +17,7 @@ abstract class SerializableElement<T> extends Comparable<T> {
abstract class BaseSerializationHelper<T extends SerializableElement> { abstract class BaseSerializationHelper<T extends SerializableElement> {
/// List cache /// List cache
List<T> _cache; List<T>? _cache;
/// The name of the type of data to serialise /// The name of the type of data to serialise
String get type; String get type;
@ -48,12 +48,15 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
try { try {
final file = await _getFilePath(); final file = await _getFilePath();
if (!await file.exists()) return _cache = []; if (!await file.exists()) {
_cache = [];
return;
}
final List<dynamic> json = jsonDecode(await file.readAsString()); final List<dynamic> json = jsonDecode(await file.readAsString());
_cache = json.cast<Map<String, dynamic>>().map(parse).toList(); _cache = json.cast<Map<String, dynamic>>().map(parse).toList();
_cache.sort(); _cache!.sort();
} catch (e, s) { } catch (e, s) {
logError(e, s); logError(e, s);
print("Failed to read serialized data!"); print("Failed to read serialized data!");
@ -67,8 +70,10 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
try { try {
final file = await _getFilePath(); final file = await _getFilePath();
await file.writeAsString(jsonEncode( await file.writeAsString(jsonEncode(_cache!
_cache.map((e) => e.toJson()).toList().cast<Map<String, dynamic>>())); .map((e) => e.toJson())
.toList()
.cast<Map<String, dynamic>>()));
} catch (e, s) { } catch (e, s) {
print("Failed to write file!"); print("Failed to write file!");
logError(e, s); logError(e, s);
@ -78,7 +83,7 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
/// Get the current list of elements /// Get the current list of elements
Future<List<T>> getList() async { Future<List<T>> getList() async {
await _loadCache(); await _loadCache();
return List.from(_cache); return List.from(_cache!);
} }
/// Set a new list of conversations /// Set a new list of conversations
@ -90,23 +95,23 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
/// Insert new element /// Insert new element
Future<void> insert(T el) async { Future<void> insert(T el) async {
await _loadCache(); await _loadCache();
_cache.add(el); _cache!.add(el);
_cache.sort(); _cache!.sort();
await _saveCache(); await _saveCache();
} }
/// Insert new element /// Insert new element
Future<void> insertMany(List<T> els) async { Future<void> insertMany(List<T> els) async {
await _loadCache(); await _loadCache();
_cache.addAll(els); _cache!.addAll(els);
_cache.sort(); _cache!.sort();
await _saveCache(); await _saveCache();
} }
/// Check if any entry in the last match the predicate /// Check if any entry in the last match the predicate
Future<bool> any(bool isContained(T t)) async { Future<bool> any(bool isContained(T t)) async {
await _loadCache(); await _loadCache();
return _cache.any((element) => isContained(element)); return _cache!.any((element) => isContained(element));
} }
Future<bool> has(T el) => any((t) => t == el); Future<bool> has(T el) => any((t) => t == el);
@ -114,7 +119,7 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
/// Check if any entry in the last match the predicate /// Check if any entry in the last match the predicate
Future<T> first(bool filter(T t)) async { Future<T> first(bool filter(T t)) async {
await _loadCache(); await _loadCache();
return _cache.firstWhere((element) => filter(element)); return _cache!.firstWhere((element) => filter(element));
} }
/// Replace an element with another one /// Replace an element with another one
@ -122,10 +127,10 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
await _loadCache(); await _loadCache();
// Insert or replace the element // Insert or replace the element
_cache = _cache.where((element) => !isToReplace(element)).toList(); _cache = _cache!.where((element) => !isToReplace(element)).toList();
_cache.add(newEl); _cache!.add(newEl);
_cache.sort(); _cache!.sort();
await _saveCache(); await _saveCache();
} }
@ -133,8 +138,8 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
Future<void> insertOrReplaceElements(List<T> list) async { Future<void> insertOrReplaceElements(List<T> list) async {
await _loadCache(); await _loadCache();
_cache.removeWhere((element) => list.any((newEl) => element == newEl)); _cache!.removeWhere((element) => list.any((newEl) => element == newEl));
_cache.addAll(list); _cache!.addAll(list);
await _saveCache(); await _saveCache();
} }
@ -142,7 +147,7 @@ abstract class BaseSerializationHelper<T extends SerializableElement> {
/// Remove elements /// Remove elements
Future<void> removeElement(bool isToRemove(T t)) async { Future<void> removeElement(bool isToRemove(T t)) async {
await _loadCache(); await _loadCache();
_cache.removeWhere((element) => isToRemove(element)); _cache!.removeWhere((element) => isToRemove(element));
await _saveCache(); await _saveCache();
} }

View File

@ -8,7 +8,7 @@ import 'package:comunic/models/conversation_message.dart';
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
HashMap<int, ConversationsMessagesSerializationHelper> _instances; HashMap<int?, ConversationsMessagesSerializationHelper>? _instances;
class ConversationsMessagesSerializationHelper class ConversationsMessagesSerializationHelper
extends BaseSerializationHelper<ConversationMessage> { extends BaseSerializationHelper<ConversationMessage> {
@ -18,13 +18,13 @@ class ConversationsMessagesSerializationHelper
: convID = convID, : convID = convID,
assert(convID != null); assert(convID != null);
factory ConversationsMessagesSerializationHelper(int convID) { factory ConversationsMessagesSerializationHelper(int? convID) {
if (_instances == null) _instances = HashMap(); if (_instances == null) _instances = HashMap();
if (!_instances.containsKey(convID)) if (!_instances!.containsKey(convID))
_instances[convID] = ConversationsMessagesSerializationHelper._(convID); _instances![convID] = ConversationsMessagesSerializationHelper._(convID!);
return _instances[convID]; return _instances![convID]!;
} }
@override @override

View File

@ -28,5 +28,5 @@ class ConversationsSerializationHelper
ConversationsList()..addAll(await super.getList()); ConversationsList()..addAll(await super.getList());
/// Get a conversation /// Get a conversation
Future<Conversation> get(int id) => first((t) => t.id == id); Future<Conversation> get(int? id) => first((t) => t.id == id);
} }

View File

@ -5,7 +5,7 @@ import 'package:comunic/models/user.dart';
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
UsersListSerialisationHelper _singleton; UsersListSerialisationHelper? _singleton;
class UsersListSerialisationHelper extends BaseSerializationHelper<User> { class UsersListSerialisationHelper extends BaseSerializationHelper<User> {
UsersListSerialisationHelper._(); UsersListSerialisationHelper._();
@ -13,7 +13,7 @@ class UsersListSerialisationHelper extends BaseSerializationHelper<User> {
factory UsersListSerialisationHelper() { factory UsersListSerialisationHelper() {
if (_singleton == null) _singleton = UsersListSerialisationHelper._(); if (_singleton == null) _singleton = UsersListSerialisationHelper._();
return _singleton; return _singleton!;
} }
@override @override
@ -23,6 +23,6 @@ class UsersListSerialisationHelper extends BaseSerializationHelper<User> {
User parse(Map<String, dynamic> m) => User.fromJson(m); User parse(Map<String, dynamic> m) => User.fromJson(m);
/// Remove a user by its ID /// Remove a user by its ID
Future<void> removeUserByID(int userID) => Future<void> removeUserByID(int? userID) =>
removeElement((t) => t.id == userID); removeElement((t) => t.id == userID);
} }

View File

@ -7,7 +7,7 @@ import 'package:version/version.dart';
/// @author Pierre Hubert /// @author Pierre Hubert
class ServerConfigurationHelper { class ServerConfigurationHelper {
static ServerConfig _config; static ServerConfig? _config;
/// Make sure the configuration has been correctly loaded /// Make sure the configuration has been correctly loaded
static Future<void> ensureLoaded() async { static Future<void> ensureLoaded() async {
@ -15,7 +15,7 @@ class ServerConfigurationHelper {
final response = final response =
(await APIRequest.withoutLogin("server/config").execWithThrow()) (await APIRequest.withoutLogin("server/config").execWithThrow())
.getObject(); .getObject()!;
final banner = response["banner"]; final banner = response["banner"];
final pushNotificationsPolicy = response["push_notifications"]; final pushNotificationsPolicy = response["push_notifications"];
@ -97,7 +97,7 @@ class ServerConfigurationHelper {
} }
/// Get current server configuration, throwing if it is not loaded yet /// Get current server configuration, throwing if it is not loaded yet
static ServerConfig get config { static ServerConfig? get config {
if (_config == null) if (_config == null)
throw Exception( throw Exception(
"Trying to access server configuration but it is not loaded yet!"); "Trying to access server configuration but it is not loaded yet!");
@ -107,6 +107,6 @@ class ServerConfigurationHelper {
} }
/// Shortcut for server configuration /// Shortcut for server configuration
ServerConfig get srvConfig => ServerConfigurationHelper.config; ServerConfig? get srvConfig => ServerConfigurationHelper.config;
bool get showBanner => srvConfig.banner != null && srvConfig.banner.visible; bool get showBanner => srvConfig!.banner != null && srvConfig!.banner!.visible;

View File

@ -25,7 +25,7 @@ class SettingsHelper {
final response = final response =
(await APIRequest(uri: "settings/get_general", needLogin: true).exec()) (await APIRequest(uri: "settings/get_general", needLogin: true).exec())
.assertOk() .assertOk()
.getObject(); .getObject()!;
return GeneralSettings( return GeneralSettings(
email: response["email"], email: response["email"],
@ -88,13 +88,13 @@ class SettingsHelper {
(await APIRequest(uri: "settings/get_account_image", needLogin: true) (await APIRequest(uri: "settings/get_account_image", needLogin: true)
.exec()) .exec())
.assertOk() .assertOk()
.getObject(); .getObject()!;
return AccountImageSettings( return AccountImageSettings(
hasImage: response["has_image"], hasImage: response["has_image"],
imageURL: response["image_url"], imageURL: response["image_url"],
visibility: visibility:
_APIAccountImageVisibilityAPILevels[response["visibility"]]); _APIAccountImageVisibilityAPILevels[response["visibility"]]!);
} }
/// Upload a new account image /// Upload a new account image
@ -143,7 +143,7 @@ class SettingsHelper {
/// Delete a custom emoji /// Delete a custom emoji
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> deleteCustomEmoji(int emojiID) async => static Future<void> deleteCustomEmoji(int? emojiID) async =>
(await APIRequest(uri: "settings/delete_custom_emoji", needLogin: true) (await APIRequest(uri: "settings/delete_custom_emoji", needLogin: true)
.addInt("emojiID", emojiID) .addInt("emojiID", emojiID)
.exec()) .exec())
@ -175,7 +175,7 @@ class SettingsHelper {
(await APIRequest(uri: "settings/get_security", needLogin: true) (await APIRequest(uri: "settings/get_security", needLogin: true)
.addString("password", password) .addString("password", password)
.execWithThrow()) .execWithThrow())
.getObject(); .getObject()!;
return SecuritySettings( return SecuritySettings(
securityQuestion1: response["security_question_1"], securityQuestion1: response["security_question_1"],
@ -207,7 +207,7 @@ class SettingsHelper {
final response = final response =
(await APIRequest.withLogin("settings/get_data_conservation_policy") (await APIRequest.withLogin("settings/get_data_conservation_policy")
.execWithThrow()) .execWithThrow())
.getObject(); .getObject()!;
return DataConservationPolicySettings( return DataConservationPolicySettings(
inactiveAccountLifeTime: response["inactive_account_lifetime"], inactiveAccountLifeTime: response["inactive_account_lifetime"],
@ -223,7 +223,7 @@ class SettingsHelper {
/// ///
/// Throws in case of failure /// Throws in case of failure
static Future<void> setDataConservationPolicy( static Future<void> setDataConservationPolicy(
String password, DataConservationPolicySettings newSettings) async { String? password, DataConservationPolicySettings newSettings) async {
await APIRequest( await APIRequest(
uri: "settings/set_data_conservation_policy", needLogin: true) uri: "settings/set_data_conservation_policy", needLogin: true)
.addString("password", password) .addString("password", password)

View File

@ -1,7 +1,6 @@
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/survey.dart'; import 'package:comunic/models/survey.dart';
import 'package:comunic/models/survey_choice.dart'; import 'package:comunic/models/survey_choice.dart';
import 'package:meta/meta.dart';
/// Survey helper /// Survey helper
/// ///
@ -13,7 +12,7 @@ class SurveyHelper {
apiToSurvey((await APIRequest.withLogin("surveys/get_info") apiToSurvey((await APIRequest.withLogin("surveys/get_info")
.addInt("postID", postID) .addInt("postID", postID)
.execWithThrow()) .execWithThrow())
.getObject()); .getObject()!);
/// Cancel the response of a user to a survey /// Cancel the response of a user to a survey
Future<bool> cancelResponse(Survey survey) async { Future<bool> cancelResponse(Survey survey) async {
@ -26,7 +25,7 @@ class SurveyHelper {
/// Send the response of a user to a survey /// Send the response of a user to a survey
Future<bool> respondToSurvey( Future<bool> respondToSurvey(
{@required Survey survey, @required SurveyChoice choice}) async { {required Survey survey, required SurveyChoice choice}) async {
assert(survey != null); assert(survey != null);
assert(choice != null); assert(choice != null);

View File

@ -31,7 +31,7 @@ class UsersHelper {
/// ///
/// Return the list of users information in case of success, null in case of /// Return the list of users information in case of success, null in case of
/// failure /// failure
Future<UsersList> _downloadInfo(List<int> users) async { Future<UsersList?> _downloadInfo(List<int?> users) async {
// Execute the request // Execute the request
final response = await APIRequest( final response = await APIRequest(
uri: "user/getInfoMultiple", uri: "user/getInfoMultiple",
@ -42,7 +42,7 @@ class UsersHelper {
if (response.code != 200) return null; if (response.code != 200) return null;
final list = UsersList(); final list = UsersList();
response.getObject().forEach( response.getObject()!.forEach(
(k, v) => list.add( (k, v) => list.add(
User( User(
id: v["userID"], id: v["userID"],
@ -69,7 +69,7 @@ class UsersHelper {
/// Get users information from a given [Set]. Throws an exception in case /// Get users information from a given [Set]. Throws an exception in case
/// of failure /// of failure
Future<UsersList> getListWithThrow(Set<int> users, Future<UsersList> getListWithThrow(Set<int?> users,
{bool forceDownload = false}) async { {bool forceDownload = false}) async {
final list = final list =
await getUsersInfo(users.toList(), forceDownload: forceDownload); await getUsersInfo(users.toList(), forceDownload: forceDownload);
@ -82,16 +82,16 @@ class UsersHelper {
} }
/// Get information about a single user. Throws in case of failure /// Get information about a single user. Throws in case of failure
Future<User> getSingleWithThrow(int user, Future<User> getSingleWithThrow(int? user,
{bool forceDownload = false}) async { {bool forceDownload = false}) async {
return (await getListWithThrow(Set<int>()..add(user), return (await getListWithThrow(Set<int?>()..add(user),
forceDownload: forceDownload))[0]; forceDownload: forceDownload))[0];
} }
/// Get users information from a given [Set] /// Get users information from a given [Set]
/// ///
/// Throws in case of failure /// Throws in case of failure
Future<UsersList> getList(Set<int> users, Future<UsersList> getList(Set<int?> users,
{bool forceDownload = false}) async { {bool forceDownload = false}) async {
final list = await getUsersInfo(users.toList()); final list = await getUsersInfo(users.toList());
@ -104,13 +104,13 @@ class UsersHelper {
/// ///
/// If [forceDownload] is set to true, the data will always be retrieved from /// If [forceDownload] is set to true, the data will always be retrieved from
/// the server, otherwise cached data will be used if available /// the server, otherwise cached data will be used if available
Future<UsersList> getUsersInfo(List<int> users, Future<UsersList?> getUsersInfo(List<int?> users,
{bool forceDownload = false}) async { {bool forceDownload = false}) async {
List<int> toDownload = []; List<int?> toDownload = [];
UsersList list = UsersList(); UsersList list = UsersList();
// Check cache // Check cache
for (int userID in users) { for (int? userID in users) {
if (!forceDownload && if (!forceDownload &&
await UsersListSerialisationHelper().any((u) => u.id == userID)) await UsersListSerialisationHelper().any((u) => u.id == userID))
list.add( list.add(
@ -151,7 +151,7 @@ class UsersHelper {
throw new GetUserAdvancedUserError(cause); throw new GetUserAdvancedUserError(cause);
} }
return apiToAdvancedUserInfo(response.getObject()); return apiToAdvancedUserInfo(response.getObject()!);
} }
/// Parse the list of custom emojies /// Parse the list of custom emojies

View File

@ -7,15 +7,15 @@ import 'package:version/version.dart';
/// @author Pierre Hubert /// @author Pierre Hubert
class VersionHelper { class VersionHelper {
static PackageInfo _info; static PackageInfo? _info;
static Future<void> ensureLoaded() async { static Future<void> ensureLoaded() async {
if (!isWeb) _info = await PackageInfo.fromPlatform(); if (!isWeb) _info = await PackageInfo.fromPlatform();
} }
/// Get current version information /// Get current version information
static PackageInfo get info => _info; static PackageInfo? get info => _info;
/// Get current application version, in parsed format /// Get current application version, in parsed format
static Version get version => Version.parse(info.version); static Version get version => Version.parse(info!.version);
} }

View File

@ -1,5 +1,4 @@
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
import 'package:flutter/material.dart';
/// Virtual directory helper /// Virtual directory helper
/// ///
@ -9,10 +8,10 @@ enum VirtualDirectoryType { USER, GROUP, NONE }
class VirtualDirectoryResult { class VirtualDirectoryResult {
final VirtualDirectoryType type; final VirtualDirectoryType type;
final int id; final int? id;
const VirtualDirectoryResult({ const VirtualDirectoryResult({
@required this.type, required this.type,
this.id, this.id,
}) : assert(type != null); }) : assert(type != null);
} }
@ -30,8 +29,8 @@ class VirtualDirectoryHelper {
return VirtualDirectoryResult(type: VirtualDirectoryType.NONE); return VirtualDirectoryResult(type: VirtualDirectoryType.NONE);
case 200: case 200:
final id = response.getObject()["id"]; final id = response.getObject()!["id"];
final kind = response.getObject()["kind"]; final kind = response.getObject()!["kind"];
switch (kind) { switch (kind) {
case "user": case "user":
return VirtualDirectoryResult( return VirtualDirectoryResult(

View File

@ -15,7 +15,7 @@ class WebAppHelper {
static Future<MembershipList> getMemberships() async { static Future<MembershipList> getMemberships() async {
final response = final response =
(await APIRequest.withLogin("webApp/getMemberships").execWithThrow()) (await APIRequest.withLogin("webApp/getMemberships").execWithThrow())
.getArray(); .getArray()!;
return MembershipList() return MembershipList()
..addAll(response ..addAll(response
@ -26,7 +26,7 @@ class WebAppHelper {
} }
/// Turn an API entry into a membership entry /// Turn an API entry into a membership entry
static Membership _apiToMembership(Map<String, dynamic> entry) { static Membership? _apiToMembership(Map<String, dynamic> entry) {
switch (entry["type"]) { switch (entry["type"]) {
case "conversation": case "conversation":
return Membership.conversation( return Membership.conversation(

View File

@ -15,7 +15,7 @@ import 'package:web_socket_channel/web_socket_channel.dart';
/// @author Pierre Hubert /// @author Pierre Hubert
class WebSocketHelper { class WebSocketHelper {
static WebSocketChannel _ws; static WebSocketChannel? _ws;
static int _counter = 0; static int _counter = 0;
@ -23,14 +23,14 @@ class WebSocketHelper {
/// Check out whether we are currently connected to WebSocket or not /// Check out whether we are currently connected to WebSocket or not
static bool isConnected() { static bool isConnected() {
return _ws != null && _ws.closeCode == null; return _ws != null && _ws!.closeCode == null;
} }
/// Get WebSocket access token /// Get WebSocket access token
static Future<String> _getWsToken() async => static Future<String?> _getWsToken() async =>
(await APIRequest(uri: "ws/token", needLogin: true).exec()) (await APIRequest(uri: "ws/token", needLogin: true).exec())
.assertOk() .assertOk()
.getObject()["token"]; .getObject()!["token"];
/// Connect to WebSocket /// Connect to WebSocket
static connect() async { static connect() async {
@ -47,7 +47,7 @@ class WebSocketHelper {
// Connect // Connect
_ws = WebSocketChannel.connect(wsURI); _ws = WebSocketChannel.connect(wsURI);
_ws.stream.listen( _ws!.stream.listen(
// When we got data // When we got data
(data) { (data) {
print("WS New data: $data"); print("WS New data: $data");
@ -75,7 +75,7 @@ class WebSocketHelper {
/// Close current WebSocket (if any) /// Close current WebSocket (if any)
static close() { static close() {
if (isConnected()) _ws.sink.close(); if (isConnected()) _ws!.sink.close();
} }
/// Send a new message /// Send a new message
@ -93,7 +93,7 @@ class WebSocketHelper {
print("WS Send message: $msg"); print("WS Send message: $msg");
_ws.sink.add(msg); _ws!.sink.add(msg);
_requests[id] = completer; _requests[id] = completer;
return completer.future; return completer.future;
@ -240,11 +240,11 @@ class WebSocketHelper {
// Handles errors // Handles errors
if (msg.title != "success") { if (msg.title != "success") {
completer.completeError(Exception("Could not process request!")); completer!.completeError(Exception("Could not process request!"));
return; return;
} }
completer.complete(msg.data); completer!.complete(msg.data);
} }
} }

View File

@ -16,4 +16,7 @@ class AbstractList<E> extends ListBase<E> {
@override @override
void operator []=(int index, E value) => _list[index] = value; void operator []=(int index, E value) => _list[index] = value;
@override
void add(E element) => _list.add(element);
} }

View File

@ -11,7 +11,7 @@ class BaseSet<T> extends SetBase<T> {
bool add(T value) => _set.add(value); bool add(T value) => _set.add(value);
@override @override
bool contains(Object element) => _set.contains(element); bool contains(Object? element) => _set.contains(element);
@override @override
Iterator<T> get iterator => _set.iterator; Iterator<T> get iterator => _set.iterator;
@ -20,10 +20,10 @@ class BaseSet<T> extends SetBase<T> {
int get length => _set.length; int get length => _set.length;
@override @override
T lookup(Object element) => _set.lookup(element); T? lookup(Object? element) => _set.lookup(element);
@override @override
bool remove(Object value) => _set.remove(value); bool remove(Object? value) => _set.remove(value);
@override @override
Set<T> toSet() => _set.toSet(); Set<T> toSet() => _set.toSet();

View File

@ -10,10 +10,10 @@ class CallMembersList extends AbstractList<CallMember> {
Set<int> get usersID => this.map((f) => f.userID).toSet(); Set<int> get usersID => this.map((f) => f.userID).toSet();
/// Remove a specific member from this list /// Remove a specific member from this list
void removeUser(int userID) => this.removeWhere((f) => f.userID == userID); void removeUser(int? userID) => this.removeWhere((f) => f.userID == userID);
/// Get the connection of a specific user /// Get the connection of a specific user
CallMember getUser(int userID) => this.firstWhere((f) => f.userID == userID); CallMember getUser(int? userID) => this.firstWhere((f) => f.userID == userID);
/// Extract ready peers from this list /// Extract ready peers from this list
CallMembersList get readyPeers => CallMembersList get readyPeers =>

View File

@ -1,31 +1,14 @@
import 'dart:collection'; import 'package:comunic/lists/abstract_list.dart';
import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/models/conversation_message.dart';
/// Conversations messages list /// Conversations messages list
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
class ConversationMessagesList extends ListBase<ConversationMessage> { class ConversationMessagesList extends AbstractList<ConversationMessage> {
final List<ConversationMessage> _list = [];
set length(int v) => _list.length = v;
int get length => _list.length;
@override
ConversationMessage operator [](int index) {
return _list[index];
}
@override
void operator []=(int index, ConversationMessage value) {
_list[index] = value;
}
/// Get the list of the users ID who own a message in this list /// Get the list of the users ID who own a message in this list
Set<int> getUsersID() { Set<int?> getUsersID() {
final Set<int> users = Set(); final Set<int?> users = Set();
for (ConversationMessage message in this) users.addAll(message.usersID); for (ConversationMessage message in this) users.addAll(message.usersID);
@ -33,18 +16,18 @@ class ConversationMessagesList extends ListBase<ConversationMessage> {
} }
/// Get the ID of the last message present in this list /// Get the ID of the last message present in this list
int get lastMessageID { int? get lastMessageID {
int lastMessageID = 0; int? lastMessageID = 0;
for (ConversationMessage message in this) for (ConversationMessage message in this)
if (message.id > lastMessageID) lastMessageID = message.id; if (message.id! > lastMessageID!) lastMessageID = message.id;
return lastMessageID; return lastMessageID;
} }
/// Get the ID of the first message present in this list /// Get the ID of the first message present in this list
int get firstMessageID { int? get firstMessageID {
int firstMessageID = this[0].id; int? firstMessageID = this[0].id;
for (ConversationMessage message in this) for (ConversationMessage message in this)
if (message.id < firstMessageID) firstMessageID = message.id; if (message.id! < firstMessageID!) firstMessageID = message.id;
return firstMessageID; return firstMessageID;
} }
@ -55,5 +38,5 @@ class ConversationMessagesList extends ListBase<ConversationMessage> {
} }
/// Remove a message from this list /// Remove a message from this list
void removeMsg(int id) => removeWhere((f) => f.id == id); void removeMsg(int? id) => removeWhere((f) => f.id == id);
} }

View File

@ -22,12 +22,15 @@ class ConversationsList extends ListBase<Conversation> {
/// Get the entire lists of users ID in this list /// Get the entire lists of users ID in this list
Set<int> get allUsersID { Set<int> get allUsersID {
final Set<int> list = Set(); final Set<int> list = Set();
forEach((c) => c.members.forEach((member) => list.add(member.userID))); forEach((c) => c.members!.forEach((member) => list.add(member.userID)));
return list; return list;
} }
/// Get the entire lists of groups ID in this list /// Get the entire lists of groups ID in this list
Set<int> get allGroupsID => where((element) => element.isGroupConversation) Set<int?> get allGroupsID => where((element) => element.isGroupConversation)
.map((e) => e.groupID) .map((e) => e.groupID)
.toSet(); .toSet();
@override
void add(Conversation element) => _list.add(element);
} }

View File

@ -7,8 +7,7 @@ import 'package:comunic/models/custom_emoji.dart';
class CustomEmojiesList extends AbstractList<CustomEmoji> { class CustomEmojiesList extends AbstractList<CustomEmoji> {
/// Check if an emoji, identified by its shortcut, is present in this list /// Check if an emoji, identified by its shortcut, is present in this list
bool hasShortcut(String shortcut) => bool hasShortcut(String shortcut) => any((f) => f.shortcut == shortcut);
firstWhere((f) => f.shortcut == shortcut, orElse: () => null) != null;
/// Serialize this list /// Serialize this list
List<Map<String, dynamic>> toSerializableList() => List<Map<String, dynamic>> toSerializableList() =>

View File

@ -7,7 +7,7 @@ import 'package:comunic/models/forez_presence.dart';
class PresenceSet extends BaseSet<Presence> { class PresenceSet extends BaseSet<Presence> {
/// Get the presence of a specific user /// Get the presence of a specific user
PresenceSet getForUser(int userID) => PresenceSet getForUser(int? userID) =>
PresenceSet()..addAll(where((element) => element.userID == userID)); PresenceSet()..addAll(where((element) => element.userID == userID));
bool containsDate(DateTime dt) => any( bool containsDate(DateTime dt) => any(
@ -24,11 +24,11 @@ class PresenceSet extends BaseSet<Presence> {
element.day == dt.day, element.day == dt.day,
); );
void toggleDate(DateTime dt, int userID) { void toggleDate(DateTime dt, int? userID) {
if (containsDate(dt)) if (containsDate(dt))
removeDate(dt); removeDate(dt);
else else
add(Presence.fromDateTime(dt, userID)); add(Presence.fromDateTime(dt, userID!));
} }
int countAtDate(DateTime dt) => where( int countAtDate(DateTime dt) => where(

View File

@ -6,23 +6,23 @@ import 'package:comunic/models/group.dart';
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
class GroupsList extends MapBase<int, Group> { class GroupsList extends MapBase<int?, Group> {
final Map<int, Group> _groups = Map(); final Map<int?, Group?> _groups = Map();
@override @override
Group operator [](Object key) => _groups[key]; Group? operator [](Object? key) => _groups[key];
@override @override
void operator []=(int key, Group value) => _groups[key] = value; void operator []=(int? key, Group? value) => _groups[key] = value;
@override @override
void clear() => _groups.clear(); void clear() => _groups.clear();
@override @override
Iterable<int> get keys => _groups.keys; Iterable<int?> get keys => _groups.keys;
@override @override
Group remove(Object key) => _groups.remove(key); Group? remove(Object? key) => _groups.remove(key);
Group getGroup(int id) => this[id]; Group? getGroup(int? id) => this[id];
} }

View File

@ -5,20 +5,20 @@ import 'package:comunic/models/membership.dart';
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
class MembershipList extends AbstractList<Membership> { class MembershipList extends AbstractList<Membership?> {
/// Get the IDs of all the users included in some way in this list /// Get the IDs of all the users included in some way in this list
Set<int> get usersId { Set<int?> get usersId {
final s = Set<int>(); final s = Set<int?>();
forEach((m) { forEach((m) {
switch (m.type) { switch (m!.type) {
case MembershipType.FRIEND: case MembershipType.FRIEND:
s.add(m.friend.id); s.add(m.friend!.id);
break; break;
case MembershipType.GROUP: case MembershipType.GROUP:
break; break;
case MembershipType.CONVERSATION: case MembershipType.CONVERSATION:
s.addAll(m.conversation.membersID); s.addAll(m.conversation!.membersID);
break; break;
} }
}); });
@ -27,16 +27,16 @@ class MembershipList extends AbstractList<Membership> {
} }
/// Get the ID of the groups included in this list /// Get the ID of the groups included in this list
Set<int> get groupsId => where((f) => f.type == MembershipType.GROUP) Set<int?> get groupsId => where((f) => f!.type == MembershipType.GROUP)
.map((f) => f.groupID) .map((f) => f!.groupID)
.toSet(); .toSet();
/// Remove a friend membership from the list /// Remove a friend membership from the list
void removeFriend(int friendID) => remove(firstWhere( void removeFriend(int friendID) => remove(firstWhere(
(f) => f.type == MembershipType.FRIEND && f.friend.id == friendID)); (f) => f!.type == MembershipType.FRIEND && f.friend!.id == friendID));
/// Get the list of conversations of a group /// Get the list of conversations of a group
Set<Membership> getGroupConversations(int groupID) => where((element) => Set<Membership?> getGroupConversations(int groupID) => where((element) =>
element.type == MembershipType.CONVERSATION && element!.type == MembershipType.CONVERSATION &&
element.conversation.groupID == groupID).toSet(); element.conversation!.groupID == groupID).toSet();
} }

View File

@ -8,8 +8,8 @@ import 'package:comunic/models/notification.dart';
class NotificationsList extends AbstractList<Notification> { class NotificationsList extends AbstractList<Notification> {
/// Get the ID of all the users related to the notifications /// Get the ID of all the users related to the notifications
/// included in the list /// included in the list
Set<int> get usersIds { Set<int?> get usersIds {
final list = Set<int>(); final list = Set<int?>();
forEach((n) { forEach((n) {
list.add(n.fromUser); list.add(n.fromUser);
@ -28,8 +28,8 @@ class NotificationsList extends AbstractList<Notification> {
/// Get the ID of all the groups related to the notifications /// Get the ID of all the groups related to the notifications
/// included in the list /// included in the list
Set<int> get groupsIds { Set<int?> get groupsIds {
final list = Set<int>(); final list = Set<int?>();
forEach((n) { forEach((n) {
if (n.onElemType == NotificationElementType.GROUP_PAGE) if (n.onElemType == NotificationElementType.GROUP_PAGE)

View File

@ -22,23 +22,23 @@ class PostsList extends ListBase<Post> {
void operator []=(int index, Post value) => _list[index] = value; void operator []=(int index, Post value) => _list[index] = value;
// Get the list of users ID in this set // Get the list of users ID in this set
Set<int> get usersID { Set<int?> get usersID {
Set<int> set = Set(); Set<int?> set = Set();
forEach((p) { forEach((p) {
set.add(p.userID); set.add(p.userID);
if (p.userPageID != null && p.userPageID > 0) set.add(p.userPageID); if (p.userPageID != null && p.userPageID! > 0) set.add(p.userPageID);
if (p.comments != null) set.addAll(p.comments.usersID); if (p.comments != null) set.addAll(p.comments!.usersID);
}); });
return set; return set;
} }
/// Get the list of groups in this list of posts /// Get the list of groups in this list of posts
Set<int> get groupsID { Set<int?> get groupsID {
Set<int> set = Set(); Set<int?> set = Set();
forEach((p) { forEach((p) {
if (p.isGroupPost) set.add(p.groupID); if (p.isGroupPost) set.add(p.groupID);

View File

@ -7,8 +7,8 @@ import 'package:comunic/models/unread_conversation.dart';
class UnreadConversationsList extends AbstractList<UnreadConversation> { class UnreadConversationsList extends AbstractList<UnreadConversation> {
/// Get the ID of the users included in this list /// Get the ID of the users included in this list
Set<int> get usersID { Set<int?> get usersID {
final set = Set<int>(); final set = Set<int?>();
forEach((element) { forEach((element) {
set.addAll(element.conv.membersID); set.addAll(element.conv.membersID);
set.addAll(element.message.usersID); set.addAll(element.message.usersID);
@ -17,8 +17,8 @@ class UnreadConversationsList extends AbstractList<UnreadConversation> {
} }
/// Get the ID of the groups references ind this list /// Get the ID of the groups references ind this list
Set<int> get groupsID { Set<int?> get groupsID {
final set = Set<int>(); final set = Set<int?>();
forEach((element) { forEach((element) {
if (element.conv.isGroupConversation) set.add(element.conv.groupID); if (element.conv.isGroupConversation) set.add(element.conv.groupID);
}); });

View File

@ -24,7 +24,7 @@ class UsersList extends ListBase<User> {
} }
/// Find a user with a specific ID /// Find a user with a specific ID
User getUser(int userID) { User getUser(int? userID) {
for (int i = 0; i < this.length; i++) for (int i = 0; i < this.length; i++)
if (this[i].id == userID) return this[i]; if (this[i].id == userID) return this[i];
@ -32,8 +32,11 @@ class UsersList extends ListBase<User> {
} }
/// Check if the user is included in this list or not /// Check if the user is included in this list or not
bool hasUser(int userID) => any((f) => f.id == userID); bool hasUser(int? userID) => any((f) => f.id == userID);
/// Get the list of users ID present in this list /// Get the list of users ID present in this list
List<int> get usersID => List.generate(length, (i) => this[i].id); List<int?> get usersID => List.generate(length, (i) => this[i].id);
@override
void add(User element) => _list.add(element);
} }

View File

@ -44,8 +44,8 @@ class ComunicApplication extends StatefulWidget {
final PreferencesHelper preferences; final PreferencesHelper preferences;
const ComunicApplication({ const ComunicApplication({
Key key, Key? key,
@required this.preferences, required this.preferences,
}) : assert(preferences != null), }) : assert(preferences != null),
super(key: key); super(key: key);

View File

@ -11,7 +11,7 @@ import 'package:comunic/utils/flutter_utils.dart';
/// Fix HTTPS issue /// Fix HTTPS issue
class MyHttpOverride extends HttpOverrides { class MyHttpOverride extends HttpOverrides {
@override @override
HttpClient createHttpClient(SecurityContext context) { HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context) return super.createHttpClient(context)
..badCertificateCallback = (cert, host, port) { ..badCertificateCallback = (cert, host, port) {
return host == "devweb.local"; // Forcefully trust local website return host == "devweb.local"; // Forcefully trust local website

View File

@ -1,4 +1,4 @@
import 'package:flutter/widgets.dart';
/// Account image settings /// Account image settings
/// ///
@ -7,14 +7,14 @@ import 'package:flutter/widgets.dart';
enum AccountImageVisibilityLevels { EVERYONE, COMUNIC_USERS, FRIENDS_ONLY } enum AccountImageVisibilityLevels { EVERYONE, COMUNIC_USERS, FRIENDS_ONLY }
class AccountImageSettings { class AccountImageSettings {
final bool/*!*/ hasImage; final bool hasImage;
final String/*!*/ imageURL; final String imageURL;
final AccountImageVisibilityLevels/*!*/ visibility; final AccountImageVisibilityLevels visibility;
const AccountImageSettings({ const AccountImageSettings({
@required this.hasImage, required this.hasImage,
@required this.imageURL, required this.imageURL,
@required this.visibility, required this.visibility,
}) : assert(hasImage != null), }) : assert(hasImage != null),
assert(imageURL != null), assert(imageURL != null),
assert(visibility != null); assert(visibility != null);

View File

@ -1,7 +1,6 @@
import 'package:comunic/enums/likes_type.dart'; import 'package:comunic/enums/likes_type.dart';
import 'package:comunic/models/conversation.dart'; import 'package:comunic/models/conversation.dart';
import 'package:comunic/models/like_element.dart'; import 'package:comunic/models/like_element.dart';
import 'package:flutter/material.dart';
import 'group.dart'; import 'group.dart';
@ -10,34 +9,34 @@ import 'group.dart';
/// @author Pierre Hubert /// @author Pierre Hubert
class AdvancedGroupInfo extends Group implements LikeElement { class AdvancedGroupInfo extends Group implements LikeElement {
bool isMembersListPublic; bool? isMembersListPublic;
final int timeCreate; final int? timeCreate;
String description; String description;
String url; String url;
int likes; int likes;
bool userLike; bool userLike;
List<Conversation> conversations; List<Conversation>? conversations;
bool/*!*/ isForezGroup; bool isForezGroup;
AdvancedGroupInfo({ AdvancedGroupInfo({
@required int id, required int id,
@required String name, required String name,
@required String iconURL, required String iconURL,
@required int numberMembers, required int numberMembers,
@required GroupMembershipLevel membershipLevel, required GroupMembershipLevel membershipLevel,
@required GroupVisibilityLevel visibilityLevel, required GroupVisibilityLevel visibilityLevel,
@required GroupRegistrationLevel registrationLevel, required GroupRegistrationLevel registrationLevel,
@required GroupPostCreationLevel postCreationLevel, required GroupPostCreationLevel postCreationLevel,
@required String virtualDirectory, required String virtualDirectory,
@required bool following, required bool following,
@required this.isMembersListPublic, required this.isMembersListPublic,
@required this.timeCreate, required this.timeCreate,
@required this.description, required this.description,
@required this.url, required this.url,
@required this.likes, required this.likes,
@required this.userLike, required this.userLike,
@required this.conversations, required this.conversations,
@required this.isForezGroup, required this.isForezGroup,
}) : assert(isForezGroup != null), }) : assert(isForezGroup != null),
super( super(
id: id, id: id,

View File

@ -3,42 +3,41 @@ import 'package:comunic/enums/user_page_visibility.dart';
import 'package:comunic/lists/custom_emojies_list.dart'; import 'package:comunic/lists/custom_emojies_list.dart';
import 'package:comunic/models/like_element.dart'; import 'package:comunic/models/like_element.dart';
import 'package:comunic/models/user.dart'; import 'package:comunic/models/user.dart';
import 'package:meta/meta.dart';
/// Advanced user information /// Advanced user information
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
class AdvancedUserInfo extends User implements LikeElement { class AdvancedUserInfo extends User implements LikeElement {
final String emailAddress; final String? emailAddress;
final String/*!*/ publicNote; final String publicNote;
final bool/*!*/ canPostTexts; final bool canPostTexts;
final bool/*!*/ isFriendsListPublic; final bool isFriendsListPublic;
final int/*!*/ numberFriends; final int numberFriends;
final int/*!*/ accountCreationTime; final int accountCreationTime;
final String/*!*/ personalWebsite; final String personalWebsite;
final String location; final String? location;
bool/*!*/ userLike; bool userLike;
int/*!*/ likes; int likes;
AdvancedUserInfo({ AdvancedUserInfo({
@required int id, required int id,
@required String firstName, required String firstName,
@required String lastName, required String lastName,
@required UserPageVisibility pageVisibility, required UserPageVisibility pageVisibility,
@required String virtualDirectory, required String? virtualDirectory,
@required String accountImageURL, required String accountImageURL,
@required CustomEmojiesList customEmojies, required CustomEmojiesList customEmojies,
@required this.emailAddress, required this.emailAddress,
@required this.publicNote, required this.publicNote,
@required this.canPostTexts, required this.canPostTexts,
@required this.isFriendsListPublic, required this.isFriendsListPublic,
@required this.numberFriends, required this.numberFriends,
@required this.accountCreationTime, required this.accountCreationTime,
@required this.personalWebsite, required this.personalWebsite,
@required this.location, required this.location,
@required this.userLike, required this.userLike,
@required this.likes, required this.likes,
}) : assert(publicNote != null), }) : assert(publicNote != null),
assert(canPostTexts != null), assert(canPostTexts != null),
assert(isFriendsListPublic != null), assert(isFriendsListPublic != null),
@ -60,9 +59,9 @@ class AdvancedUserInfo extends User implements LikeElement {
bool get hasPersonalWebsite => personalWebsite.isNotEmpty; bool get hasPersonalWebsite => personalWebsite.isNotEmpty;
bool get hasEmailAddress => emailAddress != null && emailAddress.isNotEmpty; bool get hasEmailAddress => emailAddress != null && emailAddress!.isNotEmpty;
bool get hasLocation => location != null && location.isNotEmpty; bool get hasLocation => location != null && location!.isNotEmpty;
@override @override
LikesType get likeType => LikesType.USER; LikesType get likeType => LikesType.USER;

View File

@ -4,7 +4,6 @@ import 'package:comunic/helpers/api_helper.dart';
import 'package:comunic/models/api_response.dart'; import 'package:comunic/models/api_response.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';
import 'package:meta/meta.dart';
/// API Request model /// API Request model
/// ///
@ -14,8 +13,8 @@ import 'package:meta/meta.dart';
class BytesFile { class BytesFile {
final String filename; final String filename;
final List<int> bytes; final List<int>? bytes;
final MediaType type; final MediaType? type;
const BytesFile( const BytesFile(
this.filename, this.filename,
@ -25,15 +24,15 @@ class BytesFile {
} }
class APIRequest { class APIRequest {
final String/*!*/ uri; final String uri;
final bool/*!*/ needLogin; final bool needLogin;
ProgressCallback progressCallback; ProgressCallback? progressCallback;
CancelToken cancelToken; CancelToken? cancelToken;
Map<String, String> args; Map<String, String?>? args;
Map<String, File> files = Map(); Map<String, File> files = Map();
Map<String, BytesFile> bytesFiles = Map(); Map<String, BytesFile?> bytesFiles = Map();
APIRequest({@required this.uri, this.needLogin = false, this.args}) APIRequest({required this.uri, this.needLogin = false, this.args})
: assert(uri != null), : assert(uri != null),
assert(needLogin != null) { assert(needLogin != null) {
if (this.args == null) this.args = Map(); if (this.args == null) this.args = Map();
@ -51,18 +50,18 @@ class APIRequest {
if (args == null) this.args = Map(); if (args == null) this.args = Map();
} }
APIRequest addString(String name, String value) { APIRequest addString(String name, String? value) {
args[name] = value; args![name] = value;
return this; return this;
} }
APIRequest addInt(String name, int value) { APIRequest addInt(String name, int? value) {
args[name] = value.toString(); args![name] = value.toString();
return this; return this;
} }
APIRequest addBool(String name, bool value) { APIRequest addBool(String name, bool value) {
args[name] = value ? "true" : "false"; args![name] = value ? "true" : "false";
return this; return this;
} }
@ -71,12 +70,12 @@ class APIRequest {
return this; return this;
} }
APIRequest addBytesFile(String name, BytesFile file) { APIRequest addBytesFile(String name, BytesFile? file) {
this.bytesFiles[name] = file; this.bytesFiles[name] = file;
return this; return this;
} }
void addArgs(Map<String, String> newArgs) => args.addAll(newArgs); void addArgs(Map<String, String> newArgs) => args!.addAll(newArgs);
/// Execute the request /// Execute the request
Future<APIResponse> exec() async => APIHelper().exec(this); Future<APIResponse> exec() async => APIHelper().exec(this);

View File

@ -5,14 +5,14 @@ import 'dart:convert';
/// @author Pierre HUBERT /// @author Pierre HUBERT
class APIResponse { class APIResponse {
final int/*!*/ code; final int code;
final String content; final String? content;
const APIResponse(this.code, this.content) : assert(code != null); const APIResponse(this.code, this.content);
List<dynamic> getArray() => jsonDecode(this.content); List<dynamic>? getArray() => jsonDecode(this.content!);
Map<String, dynamic> getObject() => jsonDecode(this.content); Map<String, dynamic> getObject() => jsonDecode(this.content!);
/// Check if the request is successful or not /// Check if the request is successful or not
bool get isOK => code == 200; bool get isOK => code == 200;

View File

@ -1,18 +1,18 @@
import 'package:flutter/cupertino.dart';
/// Application settings /// Application settings
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
class ApplicationPreferences { class ApplicationPreferences {
bool/*!*/ enableDarkMode; bool enableDarkMode;
bool/*!*/ forceMobileMode; bool forceMobileMode;
bool/*!*/ showPerformancesOverlay; bool showPerformancesOverlay;
ApplicationPreferences({ ApplicationPreferences({
@required this.enableDarkMode, required this.enableDarkMode,
@required this.forceMobileMode, required this.forceMobileMode,
@required this.showPerformancesOverlay, required this.showPerformancesOverlay,
}) : assert(enableDarkMode != null), }) : assert(enableDarkMode != null),
assert(forceMobileMode != null), assert(forceMobileMode != null),
assert(showPerformancesOverlay != null); assert(showPerformancesOverlay != null);

View File

@ -1,14 +1,14 @@
import 'package:meta/meta.dart';
/// Authentication details /// Authentication details
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
class AuthenticationDetails { class AuthenticationDetails {
final String/*!*/ email; final String email;
final String/*!*/ password; final String password;
const AuthenticationDetails({@required this.email, @required this.password}) const AuthenticationDetails({required this.email, required this.password})
: assert(email != null), : assert(email != null),
assert(password != null); assert(password != null);
} }

View File

@ -1,14 +1,13 @@
import 'package:comunic/helpers/database/database_contract.dart'; import 'package:comunic/helpers/database/database_contract.dart';
import 'package:meta/meta.dart';
/// Cache base model /// Cache base model
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
abstract class CacheModel { abstract class CacheModel {
final int/*!*/ id; final int id;
const CacheModel({@required this.id}) : assert(id != null); const CacheModel({required this.id}) : assert(id != null);
/// Initialize a CacheModel from a map /// Initialize a CacheModel from a map
CacheModel.fromMap(Map<String, dynamic> map) CacheModel.fromMap(Map<String, dynamic> map)

View File

@ -1,14 +1,14 @@
import 'package:flutter/material.dart';
/// Call configuration /// Call configuration
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
class CallConfig { class CallConfig {
final List<String>/*!*/ iceServers; final List<String> iceServers;
const CallConfig({ const CallConfig({
@required this.iceServers, required this.iceServers,
}) : assert(iceServers != null); }) : assert(iceServers != null);
/// Turn this call configuration into the right for the WebRTC plugin /// Turn this call configuration into the right for the WebRTC plugin

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart';
/// Single call member information /// Single call member information
@ -8,16 +7,16 @@ import 'package:flutter_webrtc/flutter_webrtc.dart';
enum MemberStatus { JOINED, READY } enum MemberStatus { JOINED, READY }
class CallMember { class CallMember {
final int/*!*/ userID; final int userID;
MemberStatus/*!*/ status; MemberStatus status;
MediaStream stream; MediaStream? stream;
CallMember({ CallMember({
@required this.userID, required this.userID,
this.status = MemberStatus.JOINED, this.status = MemberStatus.JOINED,
}) : assert(userID != null), }) : assert(userID != null),
assert(status != null); assert(status != null);
bool get hasVideoStream => bool get hasVideoStream =>
stream != null && stream.getVideoTracks().length > 0; stream != null && stream!.getVideoTracks().length > 0;
} }

View File

@ -2,7 +2,6 @@ import 'package:comunic/enums/likes_type.dart';
import 'package:comunic/models/displayed_content.dart'; import 'package:comunic/models/displayed_content.dart';
import 'package:comunic/models/like_element.dart'; import 'package:comunic/models/like_element.dart';
import 'package:comunic/utils/account_utils.dart' as account; import 'package:comunic/utils/account_utils.dart' as account;
import 'package:meta/meta.dart';
/// Comments /// Comments
/// ///
@ -11,24 +10,24 @@ import 'package:meta/meta.dart';
/// @author Pierre HUBERT /// @author Pierre HUBERT
class Comment implements LikeElement { class Comment implements LikeElement {
final int/*!*/ id; final int id;
final int/*!*/ userID; final int userID;
final int/*!*/ postID; final int postID;
final int/*!*/ timeSent; final int timeSent;
DisplayedString/*!*/ content; DisplayedString content;
final String imageURL; final String? imageURL;
int/*!*/ likes; int likes;
bool/*!*/ userLike; bool userLike;
Comment({ Comment({
@required this.id, required this.id,
@required this.userID, required this.userID,
@required this.postID, required this.postID,
@required this.timeSent, required this.timeSent,
@required this.content, required this.content,
@required this.imageURL, required this.imageURL,
@required this.likes, required this.likes,
@required this.userLike, required this.userLike,
}) : assert(id != null), }) : assert(id != null),
assert(userID != null), assert(userID != null),
assert(postID != null), assert(postID != null),

View File

@ -16,27 +16,27 @@ class Config {
// Theme customization // Theme customization
final Color splashBackgroundColor; final Color splashBackgroundColor;
final Color primaryColor; final Color? primaryColor;
final Color primaryColorDark; final Color? primaryColorDark;
final String appName; final String appName;
final String appQuickDescription; final String? appQuickDescription;
final Color unreadConversationColor; final Color? unreadConversationColor;
final Color defaultConversationColor; final Color? defaultConversationColor;
// Entries for the welcome tour // Entries for the welcome tour
final TourEntriesBuilder toursEntriesBuilder; final TourEntriesBuilder? toursEntriesBuilder;
// Custom initialization // Custom initialization
final Future<void> Function() additionalLoading; final Future<void> Function()? additionalLoading;
// Custom main application route // Custom main application route
final Widget Function(BuildContext, GlobalKey) mainRouteBuilder; final Widget Function(BuildContext, GlobalKey)? mainRouteBuilder;
const Config({ const Config({
@required this.apiServerName, required this.apiServerName,
@required this.apiServerUri, required this.apiServerUri,
@required this.apiServerSecure, required this.apiServerSecure,
@required this.clientName, required this.clientName,
this.splashBackgroundColor = defaultColor, this.splashBackgroundColor = defaultColor,
this.primaryColor, this.primaryColor,
this.primaryColorDark, this.primaryColorDark,
@ -55,9 +55,9 @@ class Config {
assert(appName != null); assert(appName != null);
/// Get and set static configuration /// Get and set static configuration
static Config/*?*/ _config; static Config? _config;
static Config get() { static Config? get() {
return _config; return _config;
} }
@ -67,6 +67,6 @@ class Config {
} }
/// Get the current configuration of the application /// Get the current configuration of the application
Config/*!*/ config() { Config config() {
return Config.get(); return Config.get()!;
} }

View File

@ -1,3 +1,4 @@
import 'package:collection/collection.dart' show IterableExtension;
import 'package:comunic/helpers/serialization/base_serialization_helper.dart'; import 'package:comunic/helpers/serialization/base_serialization_helper.dart';
import 'package:comunic/models/conversation_member.dart'; import 'package:comunic/models/conversation_member.dart';
import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/account_utils.dart';
@ -12,28 +13,28 @@ import 'group.dart';
enum CallCapabilities { NONE, AUDIO, VIDEO } enum CallCapabilities { NONE, AUDIO, VIDEO }
class Conversation extends SerializableElement<Conversation> { class Conversation extends SerializableElement<Conversation> {
final int id; final int? id;
final int lastActivity; final int? lastActivity;
final String name; final String? name;
final Color color; final Color? color;
final String logoURL; final String? logoURL;
final int groupID; final int? groupID;
final GroupMembershipLevel groupMinMembershipLevel; final GroupMembershipLevel? groupMinMembershipLevel;
final List<ConversationMember> members; final List<ConversationMember>? members;
final bool canEveryoneAddMembers; final bool? canEveryoneAddMembers;
final CallCapabilities callCapabilities; final CallCapabilities callCapabilities;
final bool isHavingCall; final bool isHavingCall;
Conversation({ Conversation({
/*required*/ @required this.id, /*required*/ required int this.id,
/*required*/ @required this.lastActivity, /*required*/ required int this.lastActivity,
@required this.name, required this.name,
@required this.color, required this.color,
@required this.logoURL, required this.logoURL,
@required this.groupID, required this.groupID,
@required this.groupMinMembershipLevel, required this.groupMinMembershipLevel,
/*required*/ @required this.members, /*required*/ required List<ConversationMember> this.members,
/*required*/ @required this.canEveryoneAddMembers, /*required*/ required bool this.canEveryoneAddMembers,
this.callCapabilities = CallCapabilities.NONE, this.callCapabilities = CallCapabilities.NONE,
this.isHavingCall = false, this.isHavingCall = false,
}) : assert(id != null), }) : assert(id != null),
@ -49,7 +50,7 @@ class Conversation extends SerializableElement<Conversation> {
/// Get current user membership /// Get current user membership
ConversationMember get membership => ConversationMember get membership =>
members.firstWhere((m) => m.userID == userID()); members!.firstWhere((m) => m.userID == userID());
/// Check out whether current user of the application is an admin /// Check out whether current user of the application is an admin
bool get isAdmin => membership.isAdmin; bool get isAdmin => membership.isAdmin;
@ -61,17 +62,17 @@ class Conversation extends SerializableElement<Conversation> {
bool get following => membership.following; bool get following => membership.following;
/// Get the list of members in the conversation /// Get the list of members in the conversation
Set<int> get membersID => members.map((e) => e.userID).toSet(); Set<int?> get membersID => members!.map((e) => e.userID).toSet();
/// Get the list of admins in the conversation /// Get the list of admins in the conversation
Set<int> get adminsID => Set<int?> get adminsID =>
members.where((e) => e.isAdmin).map((e) => e.userID).toSet(); members!.where((e) => e.isAdmin).map((e) => e.userID).toSet();
/// Get the list of the OTHER members of the conversation (all except current user) /// Get the list of the OTHER members of the conversation (all except current user)
Set<int> get otherMembersID => membersID..remove(userID()); Set<int?> get otherMembersID => membersID..remove(userID());
/// Check if the last message has been seen or not /// Check if the last message has been seen or not
bool get sawLastMessage => lastActivity <= membership.lastAccessTime; bool get sawLastMessage => lastActivity! <= membership.lastAccessTime;
/// Check out whether a conversation is managed or not /// Check out whether a conversation is managed or not
bool get isManaged => isGroupConversation; bool get isManaged => isGroupConversation;
@ -86,9 +87,8 @@ class Conversation extends SerializableElement<Conversation> {
color = map["color"] == null ? null : Color(map["color"]), color = map["color"] == null ? null : Color(map["color"]),
logoURL = map["logoURL"], logoURL = map["logoURL"],
groupID = map["groupID"], groupID = map["groupID"],
groupMinMembershipLevel = GroupMembershipLevel.values.firstWhere( groupMinMembershipLevel = GroupMembershipLevel.values.firstWhereOrNull(
(element) => element.toString() == map["groupMinMembershipLevel"], (element) => element.toString() == map["groupMinMembershipLevel"]),
orElse: () => null),
lastActivity = map["lastActivity"], lastActivity = map["lastActivity"],
members = map["members"] members = map["members"]
.map((el) => ConversationMember.fromJSON(el)) .map((el) => ConversationMember.fromJSON(el))
@ -109,13 +109,13 @@ class Conversation extends SerializableElement<Conversation> {
"groupID": groupID, "groupID": groupID,
"groupMinMembershipLevel": groupMinMembershipLevel?.toString(), "groupMinMembershipLevel": groupMinMembershipLevel?.toString(),
"lastActivity": lastActivity, "lastActivity": lastActivity,
"members": members.map((e) => e.toJson()).toList(), "members": members!.map((e) => e.toJson()).toList(),
"canEveryoneAddMembers": canEveryoneAddMembers, "canEveryoneAddMembers": canEveryoneAddMembers,
}; };
} }
@override @override
int compareTo(Conversation other) { int compareTo(Conversation other) {
return other.lastActivity.compareTo(this.lastActivity); return other.lastActivity!.compareTo(this.lastActivity!);
} }
} }

View File

@ -1,22 +1,22 @@
import 'package:flutter/widgets.dart';
/// Conversation member /// Conversation member
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
class ConversationMember { class ConversationMember {
final int/*!*/ userID; final int userID;
final int/*!*/ lastMessageSeen; final int lastMessageSeen;
final int/*!*/ lastAccessTime; final int lastAccessTime;
final bool/*!*/ following; final bool following;
final bool/*!*/ isAdmin; final bool isAdmin;
const ConversationMember({ const ConversationMember({
/*required*/ @required this.userID, /*required*/ required this.userID,
/*required*/ @required this.lastMessageSeen, /*required*/ required this.lastMessageSeen,
/*required*/ @required this.lastAccessTime, /*required*/ required this.lastAccessTime,
/*required*/ @required this.following, /*required*/ required this.following,
/*required*/ @required this.isAdmin, /*required*/ required this.isAdmin,
}) : assert(userID != null), }) : assert(userID != null),
assert(lastMessageSeen != null), assert(lastMessageSeen != null),
assert(lastAccessTime != null), assert(lastAccessTime != null),

View File

@ -30,27 +30,27 @@ const _ConversationFileMimeTypeMapping = {
}; };
class ConversationMessageFile { class ConversationMessageFile {
final String url; final String? url;
final int size; final int? size;
final String name; final String? name;
final String thumbnail; final String? thumbnail;
final String type; final String? type;
const ConversationMessageFile({ const ConversationMessageFile({
@required this.url, required String this.url,
@required this.size, required int this.size,
@required this.name, required String this.name,
@required this.thumbnail, required this.thumbnail,
@required this.type, required String this.type,
}) : assert(url != null), }) : assert(url != null),
assert(size != null), assert(size != null),
assert(name != null), assert(name != null),
assert(type != null); assert(type != null);
/// Get the type of file /// Get the type of file
ConversationMessageFileType get fileType { ConversationMessageFileType? get fileType {
if (type != null && _ConversationFileMimeTypeMapping.containsKey(type)) if (type != null && _ConversationFileMimeTypeMapping.containsKey(type))
return _ConversationFileMimeTypeMapping[type]; return _ConversationFileMimeTypeMapping[type!];
else else
return ConversationMessageFileType.OTHER; return ConversationMessageFileType.OTHER;
} }
@ -102,19 +102,19 @@ enum ConversationServerMessageType {
class ConversationServerMessage { class ConversationServerMessage {
final ConversationServerMessageType type; final ConversationServerMessageType type;
final int userID; final int? userID;
final int userWhoAdded; final int? userWhoAdded;
final int userAdded; final int? userAdded;
final int userWhoRemoved; final int? userWhoRemoved;
final int userRemoved; final int? userRemoved;
const ConversationServerMessage({ const ConversationServerMessage({
@required this.type, required this.type,
@required this.userID, required this.userID,
@required this.userWhoAdded, required this.userWhoAdded,
@required this.userAdded, required this.userAdded,
@required this.userWhoRemoved, required this.userWhoRemoved,
@required this.userRemoved, required this.userRemoved,
}) : assert(type != null), }) : assert(type != null),
assert(userID != null || assert(userID != null ||
(type != ConversationServerMessageType.USER_CREATED_CONVERSATION && (type != ConversationServerMessageType.USER_CREATED_CONVERSATION &&
@ -124,7 +124,7 @@ class ConversationServerMessage {
assert((userWhoRemoved != null && userRemoved != null) || assert((userWhoRemoved != null && userRemoved != null) ||
type != ConversationServerMessageType.USER_REMOVED_ANOTHER_USER); type != ConversationServerMessageType.USER_REMOVED_ANOTHER_USER);
Set<int> get usersID { Set<int?> get usersID {
switch (type) { switch (type) {
case ConversationServerMessageType.USER_CREATED_CONVERSATION: case ConversationServerMessageType.USER_CREATED_CONVERSATION:
case ConversationServerMessageType.USER_LEFT_CONV: case ConversationServerMessageType.USER_LEFT_CONV:
@ -144,26 +144,26 @@ class ConversationServerMessage {
throw Exception("Unsupported server message type!"); throw Exception("Unsupported server message type!");
} }
String getText(UsersList list) { String? getText(UsersList? list) {
switch (type) { switch (type) {
case ConversationServerMessageType.USER_CREATED_CONVERSATION: case ConversationServerMessageType.USER_CREATED_CONVERSATION:
return tr("%1% created the conversation", return tr("%1% created the conversation",
args: {"1": list.getUser(userID).fullName}); args: {"1": list!.getUser(userID).fullName});
case ConversationServerMessageType.USER_ADDED_ANOTHER_USER: case ConversationServerMessageType.USER_ADDED_ANOTHER_USER:
return tr("%1% added %2% to the conversation", args: { return tr("%1% added %2% to the conversation", args: {
"1": list.getUser(userWhoAdded).fullName, "1": list!.getUser(userWhoAdded).fullName,
"2": list.getUser(userAdded).fullName, "2": list.getUser(userAdded).fullName,
}); });
case ConversationServerMessageType.USER_LEFT_CONV: case ConversationServerMessageType.USER_LEFT_CONV:
return tr("%1% left the conversation", args: { return tr("%1% left the conversation", args: {
"1": list.getUser(userID).fullName, "1": list!.getUser(userID).fullName,
}); });
case ConversationServerMessageType.USER_REMOVED_ANOTHER_USER: case ConversationServerMessageType.USER_REMOVED_ANOTHER_USER:
return tr("%1% removed %2% from the conversation", args: { return tr("%1% removed %2% from the conversation", args: {
"1": list.getUser(userWhoRemoved).fullName, "1": list!.getUser(userWhoRemoved).fullName,
"2": list.getUser(userRemoved).fullName, "2": list.getUser(userRemoved).fullName,
}); });
} }
@ -191,29 +191,29 @@ class ConversationServerMessage {
} }
class ConversationMessage extends SerializableElement<ConversationMessage> { class ConversationMessage extends SerializableElement<ConversationMessage> {
final int id; final int? id;
final int convID; final int? convID;
final int userID; final int? userID;
final int timeSent; final int? timeSent;
final DisplayedString message; final DisplayedString message;
final ConversationMessageFile file; final ConversationMessageFile? file;
final ConversationServerMessage serverMessage; final ConversationServerMessage? serverMessage;
ConversationMessage({ ConversationMessage({
@required this.id, required int this.id,
@required this.convID, required int this.convID,
@required this.userID, required this.userID,
@required this.timeSent, required int this.timeSent,
@required this.message, required this.message,
@required this.file, required this.file,
@required this.serverMessage, required this.serverMessage,
}) : assert(id != null), }) : assert(id != null),
assert(convID != null), assert(convID != null),
assert(userID != null || serverMessage != null), assert(userID != null || serverMessage != null),
assert(timeSent != null), assert(timeSent != null),
assert(message != null || file != null || serverMessage != null); assert(message != null || file != null || serverMessage != null);
DateTime get date => DateTime.fromMillisecondsSinceEpoch(timeSent * 1000); DateTime get date => DateTime.fromMillisecondsSinceEpoch(timeSent! * 1000);
bool get hasMessage => !message.isNull && message.length > 0; bool get hasMessage => !message.isNull && message.length > 0;
@ -224,16 +224,16 @@ class ConversationMessage extends SerializableElement<ConversationMessage> {
bool get isServerMessage => serverMessage != null; bool get isServerMessage => serverMessage != null;
/// Get the list of the ID of the users implied in this message /// Get the list of the ID of the users implied in this message
Set<int> get usersID { Set<int?> get usersID {
if (userID != null) return Set()..add(userID); if (userID != null) return Set()..add(userID);
if (serverMessage != null) return serverMessage.usersID; if (serverMessage != null) return serverMessage!.usersID;
return Set(); return Set();
} }
@override @override
int compareTo(ConversationMessage other) { int compareTo(ConversationMessage other) {
return id.compareTo(other.id); return id!.compareTo(other.id!);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {

View File

@ -3,12 +3,12 @@
/// @author Pierre Hubert /// @author Pierre Hubert
class CountUnreadNotifications { class CountUnreadNotifications {
int notifications; int? notifications;
int conversations; int? conversations;
CountUnreadNotifications({ CountUnreadNotifications({
this.notifications, required int this.notifications,
this.conversations, required int this.conversations,
}) : assert(notifications != null), }) : assert(notifications != null),
assert(conversations != null); assert(conversations != null);
} }

View File

@ -1,20 +1,20 @@
import 'package:flutter/material.dart';
/// Single custom emoji information /// Single custom emoji information
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
class CustomEmoji { class CustomEmoji {
final int id; final int? id;
final int userID; final int? userID;
final String shortcut; final String? shortcut;
final String url; final String? url;
const CustomEmoji({ const CustomEmoji({
@required this.id, required int this.id,
@required this.userID, required int this.userID,
@required this.shortcut, required String this.shortcut,
@required this.url, required String this.url,
}) : assert(id != null), }) : assert(id != null),
assert(userID != null), assert(userID != null),
assert(shortcut != null), assert(shortcut != null),

View File

@ -3,12 +3,12 @@
/// @author Pierre Hubert /// @author Pierre Hubert
class DataConservationPolicySettings { class DataConservationPolicySettings {
int inactiveAccountLifeTime; int? inactiveAccountLifeTime;
int notificationLifetime; int? notificationLifetime;
int commentsLifetime; int? commentsLifetime;
int postsLifetime; int? postsLifetime;
int conversationMessagesLifetime; int? conversationMessagesLifetime;
int likesLifetime; int? likesLifetime;
DataConservationPolicySettings({ DataConservationPolicySettings({
this.inactiveAccountLifeTime, this.inactiveAccountLifeTime,

View File

@ -5,32 +5,32 @@ import 'package:comunic/utils/ui_utils.dart';
/// @author Pierre Hubert /// @author Pierre Hubert
class DisplayedString { class DisplayedString {
String _string; String? _string;
String _parseCache; String? _parseCache;
DisplayedString(this._string); DisplayedString(this._string);
int get length => _string.length; int get length => _string!.length;
bool get isEmpty => _string.isEmpty; bool get isEmpty => _string!.isEmpty;
bool get isNull => _string == null; bool get isNull => _string == null;
String get content => _string; String? get content => _string;
set content(String content) { set content(String? content) {
_string = content; _string = content;
_parseCache = null; _parseCache = null;
} }
@override @override
String toString() { String toString() {
return _string; return _string!;
} }
String get parsedString { String? get parsedString {
if (_parseCache == null) { if (_parseCache == null) {
_parseCache = parseEmojies(this._string); _parseCache = parseEmojies(this._string!);
} }
return _parseCache; return _parseCache;

View File

@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
/// Single presence information /// Single presence information
/// ///
@ -11,10 +11,10 @@ class Presence {
final int day; final int day;
const Presence({ const Presence({
@required this.userID, required this.userID,
@required this.year, required this.year,
@required this.month, required this.month,
@required this.day, required this.day,
}) : assert(userID != null), }) : assert(userID != null),
assert(year != null), assert(year != null),
assert(month != null), assert(month != null),

View File

@ -1,7 +1,6 @@
import 'package:comunic/helpers/database/database_contract.dart'; import 'package:comunic/helpers/database/database_contract.dart';
import 'package:comunic/models/cache_model.dart'; import 'package:comunic/models/cache_model.dart';
import 'package:comunic/utils/date_utils.dart'; import 'package:comunic/utils/date_utils.dart';
import 'package:meta/meta.dart';
/// Single user Friend information /// Single user Friend information
/// ///
@ -9,16 +8,16 @@ import 'package:meta/meta.dart';
class Friend extends CacheModel implements Comparable<Friend> { class Friend extends CacheModel implements Comparable<Friend> {
bool accepted; bool accepted;
final int lastActive; final int? lastActive;
final bool following; final bool following;
final bool canPostTexts; final bool canPostTexts;
Friend({ Friend({
@required int id, required int id,
@required this.accepted, required this.accepted,
@required this.lastActive, required int this.lastActive,
@required this.following, required this.following,
@required this.canPostTexts, required this.canPostTexts,
}) : assert(id != null), }) : assert(id != null),
assert(accepted != null), assert(accepted != null),
assert(lastActive != null), assert(lastActive != null),
@ -27,10 +26,10 @@ class Friend extends CacheModel implements Comparable<Friend> {
super(id: id); super(id: id);
/// Check out whether friend is connected or not /// Check out whether friend is connected or not
bool get isConnected => time() - 30 < lastActive; bool get isConnected => time() - 30 < lastActive!;
@override @override
int compareTo(Friend other) => other.lastActive.compareTo(lastActive); int compareTo(Friend other) => other.lastActive!.compareTo(lastActive!);
@override @override
Map<String, dynamic> toMap() => { Map<String, dynamic> toMap() => {

View File

@ -1,4 +1,4 @@
import 'package:meta/meta.dart';
/// Simple friendship status /// Simple friendship status
/// ///
@ -12,11 +12,11 @@ class FriendStatus {
final bool following; final bool following;
const FriendStatus({ const FriendStatus({
@required this.userID, required this.userID,
@required this.areFriend, required this.areFriend,
@required this.sentRequest, required this.sentRequest,
@required this.receivedRequest, required this.receivedRequest,
@required this.following, required this.following,
}) : assert(userID != null), }) : assert(userID != null),
assert(areFriend != null), assert(areFriend != null),
assert(sentRequest != null), assert(sentRequest != null),

View File

@ -1,5 +1,4 @@
import 'package:comunic/enums/user_page_visibility.dart'; import 'package:comunic/enums/user_page_visibility.dart';
import 'package:flutter/material.dart';
/// General settings /// General settings
/// ///
@ -18,22 +17,22 @@ class GeneralSettings {
String virtualDirectory; String virtualDirectory;
String personalWebsite; String personalWebsite;
String publicNote; String publicNote;
String location; String? location;
GeneralSettings({ GeneralSettings({
@required this.email, required this.email,
@required this.firstName, required this.firstName,
@required this.lastName, required this.lastName,
@required this.pageVisibility, required this.pageVisibility,
@required this.allowComments, required this.allowComments,
@required this.allowPostsFromFriends, required this.allowPostsFromFriends,
@required this.allowComunicEmails, required this.allowComunicEmails,
@required this.publicFriendsList, required this.publicFriendsList,
@required this.publicEmail, required this.publicEmail,
@required this.virtualDirectory, required this.virtualDirectory,
@required this.personalWebsite, required this.personalWebsite,
@required this.publicNote, required this.publicNote,
@required this.location, required this.location,
}) : assert(email != null), }) : assert(email != null),
assert(firstName != null), assert(firstName != null),
assert(lastName != null), assert(lastName != null),

View File

@ -1,5 +1,4 @@
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:meta/meta.dart';
/// Group information /// Group information
/// ///
@ -14,20 +13,20 @@ enum GroupMembershipLevel {
VISITOR VISITOR
} }
String/*!*/ membershipToText(GroupMembershipLevel level) { String membershipToText(GroupMembershipLevel level) {
switch (level) { switch (level) {
case GroupMembershipLevel.ADMINISTRATOR: case GroupMembershipLevel.ADMINISTRATOR:
return tr("Administrator"); return tr("Administrator")!;
case GroupMembershipLevel.MODERATOR: case GroupMembershipLevel.MODERATOR:
return tr("Moderator"); return tr("Moderator")!;
case GroupMembershipLevel.MEMBER: case GroupMembershipLevel.MEMBER:
return tr("Member"); return tr("Member")!;
case GroupMembershipLevel.INVITED: case GroupMembershipLevel.INVITED:
return tr("Invited"); return tr("Invited")!;
case GroupMembershipLevel.PENDING: case GroupMembershipLevel.PENDING:
return tr("Requested"); return tr("Requested")!;
case GroupMembershipLevel.VISITOR: case GroupMembershipLevel.VISITOR:
return tr("Visitor"); return tr("Visitor")!;
} }
throw new Exception("Unreachable statement!"); throw new Exception("Unreachable statement!");
} }
@ -51,16 +50,16 @@ class Group implements Comparable<Group> {
bool following; bool following;
Group({ Group({
@required this.id, required this.id,
@required this.name, required this.name,
@required this.iconURL, required this.iconURL,
@required this.numberMembers, required this.numberMembers,
@required this.membershipLevel, required this.membershipLevel,
@required this.visibilityLevel, required this.visibilityLevel,
@required this.registrationLevel, required this.registrationLevel,
@required this.postCreationLevel, required this.postCreationLevel,
@required this.virtualDirectory, required this.virtualDirectory,
@required this.following, required this.following,
}) : assert(id != null), }) : assert(id != null),
assert(name != null), assert(name != null),
assert(iconURL != null), assert(iconURL != null),

View File

@ -1,5 +1,4 @@
import 'package:comunic/models/group.dart'; import 'package:comunic/models/group.dart';
import 'package:flutter/material.dart';
/// Group membership information /// Group membership information
/// ///
@ -12,10 +11,10 @@ class GroupMembership {
final GroupMembershipLevel level; final GroupMembershipLevel level;
const GroupMembership({ const GroupMembership({
@required this.userID, required this.userID,
@required this.groupID, required this.groupID,
@required this.timeCreate, required this.timeCreate,
@required this.level, required this.level,
}) : assert(userID != null), }) : assert(userID != null),
assert(groupID != null), assert(groupID != null),
assert(timeCreate != null), assert(timeCreate != null),

View File

@ -9,6 +9,6 @@ abstract class LikeElement {
int get id; int get id;
bool userLike; late bool userLike;
int likes; late int likes;
} }

View File

@ -1,6 +1,5 @@
import 'package:comunic/models/conversation.dart'; import 'package:comunic/models/conversation.dart';
import 'package:comunic/models/friend.dart'; import 'package:comunic/models/friend.dart';
import 'package:flutter/material.dart';
/// Membership information /// Membership information
/// ///
@ -10,40 +9,40 @@ enum MembershipType { FRIEND, GROUP, CONVERSATION }
class Membership { class Membership {
final MembershipType type; final MembershipType type;
final Conversation conversation; final Conversation? conversation;
final Friend friend; final Friend? friend;
final int groupID; final int? groupID;
final int groupLastActive; final int? groupLastActive;
Membership.conversation(this.conversation) Membership.conversation(Conversation this.conversation)
: type = MembershipType.CONVERSATION, : type = MembershipType.CONVERSATION,
friend = null, friend = null,
groupID = null, groupID = null,
groupLastActive = null, groupLastActive = null,
assert(conversation != null); assert(conversation != null);
Membership.friend(this.friend) Membership.friend(Friend this.friend)
: type = MembershipType.FRIEND, : type = MembershipType.FRIEND,
conversation = null, conversation = null,
groupID = null, groupID = null,
groupLastActive = null, groupLastActive = null,
assert(friend != null); assert(friend != null);
Membership.group({@required this.groupID, @required this.groupLastActive}) Membership.group({required int this.groupID, required int this.groupLastActive})
: type = MembershipType.GROUP, : type = MembershipType.GROUP,
conversation = null, conversation = null,
friend = null, friend = null,
assert(groupID != null), assert(groupID != null),
assert(groupLastActive != null); assert(groupLastActive != null);
int get lastActive { int? get lastActive {
switch (type) { switch (type) {
case MembershipType.FRIEND: case MembershipType.FRIEND:
return friend.lastActive; return friend!.lastActive;
case MembershipType.GROUP: case MembershipType.GROUP:
return groupLastActive; return groupLastActive;
case MembershipType.CONVERSATION: case MembershipType.CONVERSATION:
return conversation.lastActivity; return conversation!.lastActivity;
default: default:
throw Exception("Unreachable statment!"); throw Exception("Unreachable statment!");
} }

View File

@ -1,4 +1,4 @@
import 'package:flutter/widgets.dart';
/// New account information container /// New account information container
/// ///
@ -11,10 +11,10 @@ class NewAccount {
final String password; final String password;
NewAccount({ NewAccount({
@required this.firstName, required this.firstName,
@required this.lastName, required this.lastName,
@required this.email, required this.email,
@required this.password, required this.password,
}) : assert(firstName != null), }) : assert(firstName != null),
assert(lastName != null), assert(lastName != null),
assert(email != null), assert(email != null),

View File

@ -1,5 +1,3 @@
import 'package:meta/meta.dart';
import 'api_request.dart'; import 'api_request.dart';
/// New comment information /// New comment information
@ -9,12 +7,12 @@ import 'api_request.dart';
class NewComment { class NewComment {
final int postID; final int postID;
final String content; final String content;
final BytesFile image; final BytesFile? image;
const NewComment({ const NewComment({
@required this.postID, required this.postID,
@required this.content, required this.content,
@required this.image, required this.image,
}) : assert(postID != null); }) : assert(postID != null);
bool get hasContent => content != null && content.length > 0; bool get hasContent => content != null && content.length > 0;

View File

@ -6,17 +6,17 @@ import 'package:flutter/cupertino.dart';
class NewConversation { class NewConversation {
final String name; final String name;
final List<int> members; final List<int?> members;
final bool follow; final bool follow;
final bool canEveryoneAddMembers; final bool canEveryoneAddMembers;
final Color color; final Color? color;
const NewConversation({ const NewConversation({
@required this.name, required this.name,
@required this.members, required this.members,
@required this.follow, required this.follow,
@required this.canEveryoneAddMembers, required this.canEveryoneAddMembers,
@required this.color, required this.color,
}) : assert(members != null), }) : assert(members != null),
assert(members.length > 0), assert(members.length > 0),
assert(follow != null), assert(follow != null),

View File

@ -1,5 +1,4 @@
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
import 'package:meta/meta.dart';
/// New conversation message model /// New conversation message model
/// ///
@ -9,13 +8,13 @@ import 'package:meta/meta.dart';
class NewConversationMessage { class NewConversationMessage {
final int conversationID; final int conversationID;
final String message; final String? message;
final BytesFile file; final BytesFile? file;
final BytesFile thumbnail; final BytesFile? thumbnail;
NewConversationMessage({ NewConversationMessage({
@required this.conversationID, required this.conversationID,
@required this.message, required this.message,
this.file, this.file,
this.thumbnail, this.thumbnail,
}) : assert(conversationID != null), }) : assert(conversationID != null),

View File

@ -9,16 +9,16 @@ class NewConversationsSettings {
final bool following; final bool following;
final bool isComplete; final bool isComplete;
final String name; final String name;
final bool canEveryoneAddMembers; final bool? canEveryoneAddMembers;
final Color color; final Color? color;
const NewConversationsSettings({ const NewConversationsSettings({
@required this.convID, required this.convID,
@required this.following, required this.following,
@required this.isComplete, required this.isComplete,
@required this.name, required this.name,
@required this.canEveryoneAddMembers, required this.canEveryoneAddMembers,
@required this.color, required this.color,
}) : assert(convID != null), }) : assert(convID != null),
assert(convID > 0), assert(convID > 0),
assert(following != null), assert(following != null),

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'api_request.dart'; import 'api_request.dart';
/// New emoji information /// New emoji information
@ -11,8 +9,8 @@ class NewEmoji {
final BytesFile image; final BytesFile image;
const NewEmoji({ const NewEmoji({
@required this.shortcut, required this.shortcut,
@required this.image, required this.image,
}) : assert(shortcut != null), }) : assert(shortcut != null),
assert(image != null); assert(image != null);
} }

View File

@ -1,5 +1,4 @@
import 'package:comunic/models/group.dart'; import 'package:comunic/models/group.dart';
import 'package:flutter/foundation.dart';
/// This class contains information about a conversation linked to a group /// This class contains information about a conversation linked to a group
/// to create /// to create
@ -12,9 +11,9 @@ class NewGroupConversation {
final GroupMembershipLevel minMembershipLevel; final GroupMembershipLevel minMembershipLevel;
const NewGroupConversation({ const NewGroupConversation({
@required this.groupID, required this.groupID,
@required this.name, required this.name,
@required this.minMembershipLevel, required this.minMembershipLevel,
}) : assert(groupID != null), }) : assert(groupID != null),
assert(name != null), assert(name != null),
assert(minMembershipLevel != null); assert(minMembershipLevel != null);

View File

@ -1,7 +1,6 @@
import 'package:comunic/enums/post_kind.dart'; import 'package:comunic/enums/post_kind.dart';
import 'package:comunic/enums/post_target.dart'; import 'package:comunic/enums/post_target.dart';
import 'package:comunic/enums/post_visibility_level.dart'; import 'package:comunic/enums/post_visibility_level.dart';
import 'package:meta/meta.dart';
import 'api_request.dart'; import 'api_request.dart';
@ -15,9 +14,9 @@ class NewSurvey {
final bool allowNewChoicesCreation; final bool allowNewChoicesCreation;
const NewSurvey({ const NewSurvey({
@required this.question, required this.question,
@required this.answers, required this.answers,
@required this.allowNewChoicesCreation, required this.allowNewChoicesCreation,
}) : assert(question != null), }) : assert(question != null),
assert(answers.length > 1), assert(answers.length > 1),
assert(allowNewChoicesCreation != null); assert(allowNewChoicesCreation != null);
@ -28,26 +27,26 @@ class NewPost {
final int targetID; final int targetID;
final PostVisibilityLevel visibility; final PostVisibilityLevel visibility;
final String content; final String content;
final BytesFile image; final BytesFile? image;
final String url; final String? url;
final List<int> pdf; final List<int>? pdf;
final PostKind kind; final PostKind kind;
final DateTime timeEnd; final DateTime? timeEnd;
final NewSurvey survey; final NewSurvey? survey;
final String youtubeId; final String? youtubeId;
const NewPost({ const NewPost({
@required this.target, required this.target,
@required this.targetID, required this.targetID,
@required this.visibility, required this.visibility,
@required this.content, required this.content,
@required this.kind, required this.kind,
@required this.image, required this.image,
@required this.url, required this.url,
@required this.pdf, required this.pdf,
@required this.timeEnd, required this.timeEnd,
@required this.survey, required this.survey,
@required this.youtubeId, required this.youtubeId,
}) : assert(target != null), }) : assert(target != null),
assert(targetID != null), assert(targetID != null),
assert(visibility != null), assert(visibility != null),

View File

@ -1,4 +1,4 @@
import 'package:flutter/widgets.dart';
/// Notification model /// Notification model
/// ///
@ -45,19 +45,19 @@ class Notification {
final int onElemId; final int onElemId;
final NotificationElementType onElemType; final NotificationElementType onElemType;
final NotificationType type; final NotificationType type;
final int fromContainerId; final int? fromContainerId;
final NotificationElementType fromContainerType; final NotificationElementType? fromContainerType;
const Notification({ const Notification({
@required this.id, required this.id,
@required this.timeCreate, required this.timeCreate,
@required this.seen, required this.seen,
@required this.fromUser, required this.fromUser,
@required this.onElemId, required this.onElemId,
@required this.onElemType, required this.onElemType,
@required this.type, required this.type,
@required this.fromContainerId, required this.fromContainerId,
@required this.fromContainerType, required this.fromContainerType,
}) : assert(id != null), }) : assert(id != null),
assert(timeCreate != null), assert(timeCreate != null),
assert(seen != null), assert(seen != null),

View File

@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
/// Notifications settings /// Notifications settings
/// ///
@ -9,8 +9,8 @@ class NotificationsSettings {
bool allowNotificationsSound; bool allowNotificationsSound;
NotificationsSettings({ NotificationsSettings({
@required this.allowConversations, required this.allowConversations,
@required this.allowNotificationsSound, required this.allowNotificationsSound,
}) : assert(allowConversations != null), }) : assert(allowConversations != null),
assert(allowNotificationsSound != null); assert(allowNotificationsSound != null);
} }

View File

@ -6,7 +6,6 @@ import 'package:comunic/lists/comments_list.dart';
import 'package:comunic/models/displayed_content.dart'; import 'package:comunic/models/displayed_content.dart';
import 'package:comunic/models/like_element.dart'; import 'package:comunic/models/like_element.dart';
import 'package:comunic/models/survey.dart'; import 'package:comunic/models/survey.dart';
import 'package:meta/meta.dart';
/// Single post information /// Single post information
/// ///
@ -15,50 +14,50 @@ import 'package:meta/meta.dart';
class Post implements LikeElement { class Post implements LikeElement {
final int id; final int id;
final int userID; final int userID;
final int userPageID; final int? userPageID;
final int groupID; final int? groupID;
final int timeSent; final int timeSent;
DisplayedString content; DisplayedString content;
PostVisibilityLevel visibilityLevel; PostVisibilityLevel visibilityLevel;
final PostKind kind; final PostKind kind;
final int fileSize; final int? fileSize;
final String fileType; final String? fileType;
final String filePath; final String? filePath;
final String fileURL; final String? fileURL;
final int timeEnd; final int? timeEnd;
final String linkURL; final String? linkURL;
final String linkTitle; final String? linkTitle;
final String linkDescription; final String? linkDescription;
final String linkImage; final String? linkImage;
int likes; int likes;
bool userLike; bool userLike;
final UserAccessLevels access; final UserAccessLevels access;
final CommentsList comments; final CommentsList? comments;
Survey survey; Survey? survey;
Post( Post(
{@required this.id, {required this.id,
@required this.userID, required this.userID,
@required this.userPageID, required this.userPageID,
@required this.groupID, required this.groupID,
@required this.timeSent, required this.timeSent,
@required this.content, required this.content,
@required this.visibilityLevel, required this.visibilityLevel,
@required this.kind, required this.kind,
@required this.fileSize, required this.fileSize,
@required this.fileType, required this.fileType,
@required this.filePath, required this.filePath,
@required this.fileURL, required this.fileURL,
@required this.timeEnd, required this.timeEnd,
@required this.linkURL, required this.linkURL,
@required this.linkTitle, required this.linkTitle,
@required this.linkDescription, required this.linkDescription,
@required this.linkImage, required this.linkImage,
@required this.likes, required this.likes,
@required this.userLike, required this.userLike,
@required this.access, required this.access,
@required this.comments, required this.comments,
@required this.survey}) required this.survey})
: assert(id != null), : assert(id != null),
assert(userID != null), assert(userID != null),
assert(userPageID != 0 || groupID != 0), assert(userPageID != 0 || groupID != 0),
@ -72,7 +71,7 @@ class Post implements LikeElement {
assert(userLike != null), assert(userLike != null),
assert(access != null); assert(access != null);
bool get isGroupPost => groupID != null && groupID > 0; bool get isGroupPost => groupID != null && groupID! > 0;
bool get hasContent => content != null && !content.isNull; bool get hasContent => content != null && !content.isNull;

View File

@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
/// Check password reset token result /// Check password reset token result
/// ///
@ -10,9 +10,9 @@ class ResCheckPasswordToken {
final String email; final String email;
const ResCheckPasswordToken({ const ResCheckPasswordToken({
@required this.firstName, required this.firstName,
@required this.lastName, required this.lastName,
@required this.email, required this.email,
}) : assert(firstName != null), }) : assert(firstName != null),
assert(lastName != null), assert(lastName != null),
assert(email != null); assert(email != null);

View File

@ -1,4 +1,4 @@
import 'package:flutter/cupertino.dart';
/// Single search result /// Single search result
/// ///
@ -11,8 +11,8 @@ class SearchResult {
final SearchResultKind kind; final SearchResultKind kind;
SearchResult({ SearchResult({
@required this.id, required this.id,
@required this.kind, required this.kind,
}) : assert(id != null), }) : assert(id != null),
assert(kind != null); assert(kind != null);
} }

View File

@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
/// Security settings of the user /// Security settings of the user
/// ///
@ -11,10 +11,10 @@ class SecuritySettings {
final String securityAnswer2; final String securityAnswer2;
const SecuritySettings({ const SecuritySettings({
@required this.securityQuestion1, required this.securityQuestion1,
@required this.securityAnswer1, required this.securityAnswer1,
@required this.securityQuestion2, required this.securityQuestion2,
@required this.securityAnswer2, required this.securityAnswer2,
}) : assert(securityQuestion1 != null), }) : assert(securityQuestion1 != null),
assert(securityAnswer1 != null), assert(securityAnswer1 != null),
assert(securityQuestion2 != null), assert(securityQuestion2 != null),

View File

@ -1,5 +1,4 @@
import 'package:comunic/utils/date_utils.dart'; import 'package:comunic/utils/date_utils.dart';
import 'package:flutter/widgets.dart';
import 'package:version/version.dart'; import 'package:version/version.dart';
/// Server static configuration /// Server static configuration
@ -11,8 +10,8 @@ class NotificationsPolicy {
final bool hasIndependent; final bool hasIndependent;
const NotificationsPolicy({ const NotificationsPolicy({
@required this.hasFirebase, required this.hasFirebase,
@required this.hasIndependent, required this.hasIndependent,
}) : assert(hasFirebase != null), }) : assert(hasFirebase != null),
assert(hasIndependent != null); assert(hasIndependent != null);
} }
@ -28,14 +27,14 @@ class PasswordPolicy {
final int minCategoriesPresence; final int minCategoriesPresence;
const PasswordPolicy({ const PasswordPolicy({
@required this.allowMailInPassword, required this.allowMailInPassword,
@required this.allowNameInPassword, required this.allowNameInPassword,
@required this.minPasswordLength, required this.minPasswordLength,
@required this.minNumberUpperCaseLetters, required this.minNumberUpperCaseLetters,
@required this.minNumberLowerCaseLetters, required this.minNumberLowerCaseLetters,
@required this.minNumberDigits, required this.minNumberDigits,
@required this.minNumberSpecialCharacters, required this.minNumberSpecialCharacters,
@required this.minCategoriesPresence, required this.minCategoriesPresence,
}) : assert(allowMailInPassword != null), }) : assert(allowMailInPassword != null),
assert(allowNameInPassword != null), assert(allowNameInPassword != null),
assert(minPasswordLength != null), assert(minPasswordLength != null),
@ -55,12 +54,12 @@ class ServerDataConservationPolicy {
final int minLikesLifetime; final int minLikesLifetime;
const ServerDataConservationPolicy({ const ServerDataConservationPolicy({
@required this.minInactiveAccountLifetime, required this.minInactiveAccountLifetime,
@required this.minNotificationLifetime, required this.minNotificationLifetime,
@required this.minCommentsLifetime, required this.minCommentsLifetime,
@required this.minPostsLifetime, required this.minPostsLifetime,
@required this.minConversationMessagesLifetime, required this.minConversationMessagesLifetime,
@required this.minLikesLifetime, required this.minLikesLifetime,
}) : assert(minInactiveAccountLifetime != null), }) : assert(minInactiveAccountLifetime != null),
assert(minNotificationLifetime != null), assert(minNotificationLifetime != null),
assert(minCommentsLifetime != null), assert(minCommentsLifetime != null),
@ -85,19 +84,19 @@ class ConversationsPolicy {
final int maxLogoHeight; final int maxLogoHeight;
const ConversationsPolicy({ const ConversationsPolicy({
@required this.maxConversationNameLen, required this.maxConversationNameLen,
@required this.minMessageLen, required this.minMessageLen,
@required this.maxMessageLen, required this.maxMessageLen,
@required this.allowedFilesType, required this.allowedFilesType,
@required this.filesMaxSize, required this.filesMaxSize,
@required this.writingEventInterval, required this.writingEventInterval,
@required this.writingEventLifetime, required this.writingEventLifetime,
@required this.maxMessageImageWidth, required this.maxMessageImageWidth,
@required this.maxMessageImageHeight, required this.maxMessageImageHeight,
@required this.maxThumbnailWidth, required this.maxThumbnailWidth,
@required this.maxThumbnailHeight, required this.maxThumbnailHeight,
@required this.maxLogoWidth, required this.maxLogoWidth,
@required this.maxLogoHeight, required this.maxLogoHeight,
}) : assert(maxConversationNameLen != null), }) : assert(maxConversationNameLen != null),
assert(minMessageLen != null), assert(minMessageLen != null),
assert(maxMessageLen != null), assert(maxMessageLen != null),
@ -121,11 +120,11 @@ class AccountInformationPolicy {
final int maxLocationLength; final int maxLocationLength;
const AccountInformationPolicy({ const AccountInformationPolicy({
@required this.minFirstNameLength, required this.minFirstNameLength,
@required this.maxFirstNameLength, required this.maxFirstNameLength,
@required this.minLastNameLength, required this.minLastNameLength,
@required this.maxLastNameLength, required this.maxLastNameLength,
@required this.maxLocationLength, required this.maxLocationLength,
}) : assert(minFirstNameLength != null), }) : assert(minFirstNameLength != null),
assert(maxFirstNameLength != null), assert(maxFirstNameLength != null),
assert(minLastNameLength != null), assert(minLastNameLength != null),
@ -136,7 +135,7 @@ class AccountInformationPolicy {
enum BannerNature { Information, Warning, Success } enum BannerNature { Information, Warning, Success }
extension BannerNatureExt on BannerNature { extension BannerNatureExt on BannerNature {
static BannerNature fromStr(String s) { static BannerNature fromStr(String? s) {
switch (s) { switch (s) {
case "information": case "information":
return BannerNature.Information; return BannerNature.Information;
@ -151,22 +150,22 @@ extension BannerNatureExt on BannerNature {
class Banner { class Banner {
final bool enabled; final bool enabled;
final int expire; final int? expire;
final BannerNature nature; final BannerNature nature;
final Map<String, String> message; final Map<String, String> message;
final String link; final String? link;
const Banner({ const Banner({
@required this.enabled, required this.enabled,
@required this.expire, required this.expire,
@required this.nature, required this.nature,
@required this.message, required this.message,
@required this.link, required this.link,
}) : assert(enabled != null), }) : assert(enabled != null),
assert(nature != null), assert(nature != null),
assert(message != null); assert(message != null);
bool get visible => enabled && (expire == null || expire > time()); bool get visible => enabled && (expire == null || expire! > time());
} }
class ServerConfig { class ServerConfig {
@ -176,7 +175,7 @@ class ServerConfig {
final String contactEmail; final String contactEmail;
final String playStoreURL; final String playStoreURL;
final String androidDirectDownloadURL; final String androidDirectDownloadURL;
final Banner banner; final Banner? banner;
final NotificationsPolicy notificationsPolicy; final NotificationsPolicy notificationsPolicy;
final PasswordPolicy passwordPolicy; final PasswordPolicy passwordPolicy;
final ServerDataConservationPolicy dataConservationPolicy; final ServerDataConservationPolicy dataConservationPolicy;
@ -184,18 +183,18 @@ class ServerConfig {
final AccountInformationPolicy accountInformationPolicy; final AccountInformationPolicy accountInformationPolicy;
const ServerConfig({ const ServerConfig({
@required this.minSupportedMobileVersion, required this.minSupportedMobileVersion,
@required this.termsURL, required this.termsURL,
@required this.privacyPolicyURL, required this.privacyPolicyURL,
@required this.contactEmail, required this.contactEmail,
@required this.playStoreURL, required this.playStoreURL,
@required this.androidDirectDownloadURL, required this.androidDirectDownloadURL,
@required this.banner, required this.banner,
@required this.notificationsPolicy, required this.notificationsPolicy,
@required this.passwordPolicy, required this.passwordPolicy,
@required this.dataConservationPolicy, required this.dataConservationPolicy,
@required this.conversationsPolicy, required this.conversationsPolicy,
@required this.accountInformationPolicy, required this.accountInformationPolicy,
}) : assert(minSupportedMobileVersion != null), }) : assert(minSupportedMobileVersion != null),
assert(termsURL != null), assert(termsURL != null),
assert(privacyPolicyURL != null), assert(privacyPolicyURL != null),

View File

@ -1,6 +1,5 @@
import 'package:comunic/models/survey_choice.dart'; import 'package:comunic/models/survey_choice.dart';
import 'package:comunic/utils/account_utils.dart' as account; import 'package:comunic/utils/account_utils.dart' as account;
import 'package:meta/meta.dart';
/// Survey information /// Survey information
/// ///
@ -17,14 +16,14 @@ class Survey {
bool allowNewChoicesCreation; bool allowNewChoicesCreation;
Survey({ Survey({
@required this.id, required this.id,
@required this.userID, required this.userID,
@required this.postID, required this.postID,
@required this.creationTime, required this.creationTime,
@required this.question, required this.question,
@required this.userChoice, required this.userChoice,
@required this.choices, required this.choices,
@required this.allowNewChoicesCreation, required this.allowNewChoicesCreation,
}) : assert(id != null), }) : assert(id != null),
assert(userID != null), assert(userID != null),
assert(postID != null), assert(postID != null),
@ -43,14 +42,14 @@ class Survey {
bool get canBlockNewChoicesCreation => bool get canBlockNewChoicesCreation =>
allowNewChoicesCreation && account.userID() == this.userID; allowNewChoicesCreation && account.userID() == this.userID;
SurveyChoice get userResponse { SurveyChoice? get userResponse {
if (!hasResponded) return null; if (!hasResponded) return null;
return choices.firstWhere((e) => e.id == userChoice); return choices.firstWhere((e) => e.id == userChoice);
} }
void cancelUserResponse() { void cancelUserResponse() {
if (hasResponded) userResponse.responses--; if (hasResponded) userResponse!.responses--;
userChoice = 0; userChoice = 0;
} }

View File

@ -1,4 +1,4 @@
import 'package:meta/meta.dart';
/// Single survey choice /// Single survey choice
/// ///
@ -10,9 +10,9 @@ class SurveyChoice {
int responses; int responses;
SurveyChoice({ SurveyChoice({
@required this.id, required this.id,
@required this.name, required this.name,
@required this.responses, required this.responses,
}) : assert(id != null), }) : assert(id != null),
assert(name != null), assert(name != null),
assert(responses != null); assert(responses != null);

Some files were not shown because too many files have changed in this diff Show More