mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-25 22:39:22 +00:00
Can update a conversation
This commit is contained in:
parent
92054d6e29
commit
e7c34e6e71
@ -8,7 +8,6 @@ import 'package:comunic/models/api_request.dart';
|
|||||||
import 'package:comunic/models/api_response.dart';
|
import 'package:comunic/models/api_response.dart';
|
||||||
import 'package:comunic/models/conversation.dart';
|
import 'package:comunic/models/conversation.dart';
|
||||||
import 'package:comunic/models/conversation_message.dart';
|
import 'package:comunic/models/conversation_message.dart';
|
||||||
import 'package:comunic/models/conversation_settings.dart';
|
|
||||||
import 'package:comunic/models/new_conversation_message.dart';
|
import 'package:comunic/models/new_conversation_message.dart';
|
||||||
import 'package:comunic/utils/account_utils.dart';
|
import 'package:comunic/utils/account_utils.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
@ -28,7 +27,7 @@ class ConversationsHelper {
|
|||||||
/// Create a new conversation
|
/// Create a new conversation
|
||||||
///
|
///
|
||||||
/// Return the ID of the newly created conversation or -1 in case of failure
|
/// Return the ID of the newly created conversation or -1 in case of failure
|
||||||
Future<int> createConversation(ConversationSettings settings) async {
|
Future<int> createConversation(Conversation settings) async {
|
||||||
final response =
|
final response =
|
||||||
await APIRequest(uri: "conversations/create", needLogin: true, args: {
|
await APIRequest(uri: "conversations/create", needLogin: true, args: {
|
||||||
"name": settings.hasName ? settings.name : "false",
|
"name": settings.hasName ? settings.name : "false",
|
||||||
@ -41,6 +40,27 @@ class ConversationsHelper {
|
|||||||
return response.getObject()["conversationID"];
|
return response.getObject()["conversationID"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update an existing conversation
|
||||||
|
///
|
||||||
|
/// Returns a boolean depending of the success of the operation
|
||||||
|
Future<bool> updateConversation(Conversation settings) async {
|
||||||
|
final request =
|
||||||
|
APIRequest(uri: "conversations/updateSettings", needLogin: true, args: {
|
||||||
|
"conversationID": settings.id.toString(),
|
||||||
|
"following": settings.following ? "true" : "false"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update all conversation settings, if possible
|
||||||
|
if(settings.isOwner) {
|
||||||
|
request.addString("name", settings.hasName ? settings.name : "false");
|
||||||
|
request.addString("members", settings.members.join(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await request.exec();
|
||||||
|
|
||||||
|
return response.code == 200;
|
||||||
|
}
|
||||||
|
|
||||||
/// Download the list of conversations from the server
|
/// Download the list of conversations from the server
|
||||||
Future<ConversationsList> downloadList() async {
|
Future<ConversationsList> downloadList() async {
|
||||||
final response =
|
final response =
|
||||||
|
@ -1,5 +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/account_utils.dart';
|
||||||
import 'package:comunic/utils/list_utils.dart';
|
import 'package:comunic/utils/list_utils.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
@ -34,6 +35,10 @@ class Conversation extends CacheModel implements Comparable {
|
|||||||
/// Check out whether a conversation has a fixed name or not
|
/// Check out whether a conversation has a fixed name or not
|
||||||
bool get hasName => this.name != null;
|
bool get hasName => this.name != null;
|
||||||
|
|
||||||
|
/// Check out whether current user of the application is the owner of it or
|
||||||
|
/// not
|
||||||
|
bool get isOwner => this.ownerID == userID();
|
||||||
|
|
||||||
Conversation.fromMap(Map<String, dynamic> map)
|
Conversation.fromMap(Map<String, dynamic> map)
|
||||||
: ownerID = map[ConversationTableContract.C_OWNER_ID],
|
: ownerID = map[ConversationTableContract.C_OWNER_ID],
|
||||||
lastActive = map[ConversationTableContract.C_LAST_ACTIVE],
|
lastActive = map[ConversationTableContract.C_LAST_ACTIVE],
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
/// Conversation settings model
|
|
||||||
///
|
|
||||||
/// Use this model to create / update a conversation
|
|
||||||
///
|
|
||||||
/// @author Pierre HUBERT
|
|
||||||
|
|
||||||
class ConversationSettings {
|
|
||||||
/// Set the ID to 0 if not required
|
|
||||||
final int id;
|
|
||||||
final String name;
|
|
||||||
final bool following;
|
|
||||||
final List<int> members;
|
|
||||||
|
|
||||||
ConversationSettings({
|
|
||||||
@required this.id,
|
|
||||||
@required this.name,
|
|
||||||
@required this.following,
|
|
||||||
@required this.members,
|
|
||||||
}) : assert(members != null && members.length > 0),
|
|
||||||
assert(following != null);
|
|
||||||
|
|
||||||
bool get hasName => name != null && name.length > 0;
|
|
||||||
|
|
||||||
bool get hasId => id != null && id > 0;
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:comunic/helpers/conversations_helper.dart';
|
import 'package:comunic/helpers/conversations_helper.dart';
|
||||||
import 'package:comunic/models/conversation.dart';
|
import 'package:comunic/models/conversation.dart';
|
||||||
|
import 'package:comunic/ui/routes/update_conversation_route.dart';
|
||||||
import 'package:comunic/ui/screens/conversation_screen.dart';
|
import 'package:comunic/ui/screens/conversation_screen.dart';
|
||||||
import 'package:comunic/utils/intl_utils.dart';
|
import 'package:comunic/utils/intl_utils.dart';
|
||||||
import 'package:comunic/utils/ui_utils.dart';
|
import 'package:comunic/utils/ui_utils.dart';
|
||||||
@ -53,6 +54,14 @@ class _ConversationRouteState extends State<ConversationRoute> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _openSettings() {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute(builder: (b) {
|
||||||
|
return UpdateConversationRoute(
|
||||||
|
conversationID: widget.conversationID,
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildRouteBody() {
|
Widget _buildRouteBody() {
|
||||||
//Handle errors
|
//Handle errors
|
||||||
if (_error != null && _error)
|
if (_error != null && _error)
|
||||||
@ -86,6 +95,12 @@ class _ConversationRouteState extends State<ConversationRoute> {
|
|||||||
title: Text(
|
title: Text(
|
||||||
_conversationName == null ? tr("Loading") : _conversationName,
|
_conversationName == null ? tr("Loading") : _conversationName,
|
||||||
),
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.settings),
|
||||||
|
onPressed: _openSettings,
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: _buildRouteBody(),
|
body: _buildRouteBody(),
|
||||||
);
|
);
|
||||||
|
91
lib/ui/routes/update_conversation_route.dart
Normal file
91
lib/ui/routes/update_conversation_route.dart
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import 'package:comunic/helpers/conversations_helper.dart';
|
||||||
|
import 'package:comunic/helpers/users_helper.dart';
|
||||||
|
import 'package:comunic/lists/users_list.dart';
|
||||||
|
import 'package:comunic/models/conversation.dart';
|
||||||
|
import 'package:comunic/ui/screens/update_conversation_screen.dart';
|
||||||
|
import 'package:comunic/utils/intl_utils.dart';
|
||||||
|
import 'package:comunic/utils/ui_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Update a conversation route
|
||||||
|
///
|
||||||
|
/// @author Pierre HUBERT
|
||||||
|
|
||||||
|
class UpdateConversationRoute extends StatefulWidget {
|
||||||
|
final int conversationID;
|
||||||
|
|
||||||
|
const UpdateConversationRoute({Key key, this.conversationID})
|
||||||
|
: assert(conversationID != null),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _UpdateConversationRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UpdateConversationRoute extends State<UpdateConversationRoute> {
|
||||||
|
Conversation _conversation;
|
||||||
|
UsersList _membersInfo;
|
||||||
|
bool _error = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
_loadConversation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setError(bool e) => setState(() {
|
||||||
|
_error = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Load information about the being updated conversation
|
||||||
|
Future<void> _loadConversation() async {
|
||||||
|
setError(false);
|
||||||
|
|
||||||
|
final conversation = await ConversationsHelper()
|
||||||
|
.getSingle(widget.conversationID, force: true);
|
||||||
|
|
||||||
|
if (conversation == null) return setError(true);
|
||||||
|
|
||||||
|
//Load information about the members of the conversation
|
||||||
|
_membersInfo = await UsersHelper().getUsersInfo(conversation.members);
|
||||||
|
|
||||||
|
if (_membersInfo == null) return setError(true);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_conversation = conversation;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the body of this widget
|
||||||
|
Widget _buildBody() {
|
||||||
|
if (_error)
|
||||||
|
return buildErrorCard(
|
||||||
|
tr("Could not load information about the conversation"),
|
||||||
|
actions: [
|
||||||
|
FlatButton(
|
||||||
|
onPressed: _loadConversation,
|
||||||
|
child: Text(
|
||||||
|
tr("Retry").toUpperCase(),
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (_conversation == null) return buildLoadingPage();
|
||||||
|
|
||||||
|
return UpdateConversationScreen(
|
||||||
|
initialUsers: _membersInfo,
|
||||||
|
initialSettings: _conversation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(tr("Update a conversation")),
|
||||||
|
),
|
||||||
|
body: _buildBody(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:comunic/helpers/conversations_helper.dart';
|
import 'package:comunic/helpers/conversations_helper.dart';
|
||||||
import 'package:comunic/lists/users_list.dart';
|
import 'package:comunic/lists/users_list.dart';
|
||||||
import 'package:comunic/models/conversation_settings.dart';
|
import 'package:comunic/models/conversation.dart';
|
||||||
import 'package:comunic/ui/routes/conversation_route.dart';
|
import 'package:comunic/ui/routes/conversation_route.dart';
|
||||||
import 'package:comunic/ui/tiles/simple_user_tile.dart';
|
import 'package:comunic/ui/tiles/simple_user_tile.dart';
|
||||||
import 'package:comunic/ui/widgets/pick_user_widget.dart';
|
import 'package:comunic/ui/widgets/pick_user_widget.dart';
|
||||||
@ -14,6 +14,15 @@ import 'package:flutter/material.dart';
|
|||||||
enum _MembersMenuChoices { REMOVE }
|
enum _MembersMenuChoices { REMOVE }
|
||||||
|
|
||||||
class UpdateConversationScreen extends StatefulWidget {
|
class UpdateConversationScreen extends StatefulWidget {
|
||||||
|
final Conversation initialSettings;
|
||||||
|
final UsersList initialUsers;
|
||||||
|
|
||||||
|
const UpdateConversationScreen({
|
||||||
|
Key key,
|
||||||
|
this.initialSettings,
|
||||||
|
this.initialUsers,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _UpdateConversationScreen();
|
State<StatefulWidget> createState() => _UpdateConversationScreen();
|
||||||
}
|
}
|
||||||
@ -23,6 +32,22 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
|
|||||||
UsersList _members = UsersList();
|
UsersList _members = UsersList();
|
||||||
bool _followConversation = true;
|
bool _followConversation = true;
|
||||||
|
|
||||||
|
get isUpdating => widget.initialSettings != null;
|
||||||
|
|
||||||
|
get isOwner => !isUpdating || widget.initialSettings.isOwner;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
// Check if we are updating an existing conversation
|
||||||
|
if (widget.initialSettings != null) {
|
||||||
|
_nameController.text = widget.initialSettings.name;
|
||||||
|
_members = widget.initialUsers;
|
||||||
|
_followConversation = widget.initialSettings.following;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -33,8 +58,10 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
|
|||||||
TextField(
|
TextField(
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: tr("Conversation name (optionnal)"),
|
labelText: tr("Conversation name (optionnal)"),
|
||||||
alignLabelWithHint: true),
|
alignLabelWithHint: true,
|
||||||
|
enabled: isOwner,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Add a member to the conversation
|
// Add a member to the conversation
|
||||||
@ -42,6 +69,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
|
|||||||
resetOnChoose: true,
|
resetOnChoose: true,
|
||||||
keepFocusOnChoose: true,
|
keepFocusOnChoose: true,
|
||||||
label: tr("Add member"),
|
label: tr("Add member"),
|
||||||
|
enabled: isOwner,
|
||||||
onSelectUser: (user) => setState(() {
|
onSelectUser: (user) => setState(() {
|
||||||
if (!_members.contains(user)) _members.add(user);
|
if (!_members.contains(user)) _members.add(user);
|
||||||
}),
|
}),
|
||||||
@ -57,17 +85,19 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
|
|||||||
itemBuilder: (b, i) {
|
itemBuilder: (b, i) {
|
||||||
return SimpleUserTile(
|
return SimpleUserTile(
|
||||||
user: _members[i],
|
user: _members[i],
|
||||||
trailing: PopupMenuButton<_MembersMenuChoices>(
|
trailing: isOwner
|
||||||
onSelected: (choice) =>
|
? PopupMenuButton<_MembersMenuChoices>(
|
||||||
_membersMenuItemSelected(i, choice),
|
onSelected: (choice) =>
|
||||||
itemBuilder: (c) =>
|
_membersMenuItemSelected(i, choice),
|
||||||
<PopupMenuEntry<_MembersMenuChoices>>[
|
itemBuilder: (c) =>
|
||||||
PopupMenuItem(
|
<PopupMenuEntry<_MembersMenuChoices>>[
|
||||||
child: Text(tr("Remove")),
|
PopupMenuItem(
|
||||||
value: _MembersMenuChoices.REMOVE,
|
child: Text(tr("Remove")),
|
||||||
)
|
value: _MembersMenuChoices.REMOVE,
|
||||||
],
|
)
|
||||||
),
|
],
|
||||||
|
)
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -90,7 +120,9 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
|
|||||||
// Submit button
|
// Submit button
|
||||||
RaisedButton(
|
RaisedButton(
|
||||||
onPressed: _members.length < 1 ? null : _submitForm,
|
onPressed: _members.length < 1 ? null : _submitForm,
|
||||||
child: Text(tr("Create the conversation")),
|
child: Text(isUpdating
|
||||||
|
? tr("Update the conversation")
|
||||||
|
: tr("Create the conversation")),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -109,24 +141,40 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
|
|||||||
|
|
||||||
/// Submit the conversation
|
/// Submit the conversation
|
||||||
Future<void> _submitForm() async {
|
Future<void> _submitForm() async {
|
||||||
final settings = ConversationSettings(
|
final settings = Conversation(
|
||||||
id: 0,
|
id: isUpdating ? widget.initialSettings.id : 0,
|
||||||
name: _nameController.text,
|
name: _nameController.text,
|
||||||
following: _followConversation,
|
following: _followConversation,
|
||||||
members: _members.usersID,
|
members: _members.usersID,
|
||||||
);
|
|
||||||
|
// Give random value to these fields as they are ignored here
|
||||||
|
lastActive: 0,
|
||||||
|
ownerID: 0,
|
||||||
|
sawLastMessage: true);
|
||||||
|
|
||||||
// Create the conversation
|
// Create the conversation
|
||||||
final conversationID = await ConversationsHelper().createConversation(settings);
|
var conversationID = settings.id;
|
||||||
|
bool error = false;
|
||||||
|
if (isUpdating)
|
||||||
|
error = !(await ConversationsHelper().updateConversation(settings));
|
||||||
|
else {
|
||||||
|
conversationID = await ConversationsHelper().createConversation(settings);
|
||||||
|
if (conversationID < 1) error = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for errors
|
// Check for errors
|
||||||
if(conversationID < 1)
|
if (error)
|
||||||
return Scaffold.of(context).showSnackBar(
|
return Scaffold.of(context).showSnackBar(SnackBar(
|
||||||
SnackBar(content: Text(tr("Could not create the conversation!")), duration: Duration(seconds: 1),));
|
content: Text(isUpdating
|
||||||
|
? tr("Could not update the conversation!")
|
||||||
|
: tr("Could not create the conversation!")),
|
||||||
|
duration: Duration(seconds: 1),
|
||||||
|
));
|
||||||
|
|
||||||
// Open the conversation
|
// Open the conversation
|
||||||
Navigator.of(context).pushReplacement(MaterialPageRoute(
|
Navigator.of(context).pushReplacement(MaterialPageRoute(
|
||||||
builder: (c) => ConversationRoute(conversationID: conversationID,)
|
builder: (c) => ConversationRoute(
|
||||||
));
|
conversationID: conversationID,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,15 @@ class PickUserWidget extends StatefulWidget {
|
|||||||
final String label;
|
final String label;
|
||||||
final bool resetOnChoose;
|
final bool resetOnChoose;
|
||||||
final bool keepFocusOnChoose;
|
final bool keepFocusOnChoose;
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
const PickUserWidget(
|
const PickUserWidget(
|
||||||
{Key key,
|
{Key key,
|
||||||
@required this.onSelectUser,
|
@required this.onSelectUser,
|
||||||
@required this.label,
|
@required this.label,
|
||||||
this.resetOnChoose = false,
|
this.resetOnChoose = false,
|
||||||
this.keepFocusOnChoose = false})
|
this.keepFocusOnChoose = false,
|
||||||
|
this.enabled = true})
|
||||||
: assert(onSelectUser != null),
|
: assert(onSelectUser != null),
|
||||||
assert(label != null),
|
assert(label != null),
|
||||||
assert(resetOnChoose != null),
|
assert(resetOnChoose != null),
|
||||||
@ -66,6 +68,7 @@ class _PickUserWidgetState extends State<PickUserWidget> {
|
|||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
onChanged: (s) => _updateSuggestions(),
|
onChanged: (s) => _updateSuggestions(),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
enabled: widget.enabled,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: widget.label,
|
labelText: widget.label,
|
||||||
alignLabelWithHint: true,
|
alignLabelWithHint: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user