1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 12:59:21 +00:00

Get and show the list of conversations

This commit is contained in:
Pierre HUBERT 2019-04-23 14:35:41 +02:00
parent d10df9dd7a
commit 7666af0975
10 changed files with 246 additions and 11 deletions

View File

@ -0,0 +1,5 @@
/// Load error level
///
/// @author Pierre HUBERT
enum LoadErrorLevel {MINOR, MAJOR, NONE}

View File

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:comunic/helpers/account_credentials_helper.dart';
import 'package:comunic/models/api_request.dart'; 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/config.dart'; import 'package:comunic/models/config.dart';
@ -23,7 +24,12 @@ class APIHelper {
request.addString("serviceToken", config().serviceToken); request.addString("serviceToken", config().serviceToken);
//Add user tokens (if required) //Add user tokens (if required)
if (request.needLogin) throw "Can add user tokens right now !"; if (request.needLogin) {
final tokens = await AccountCredentialsHelper().get();
assert(tokens != null);
request.addString("userToken1", tokens.tokenOne);
request.addString("userToken2", tokens.tokenTwo);
}
// Prepare request body // Prepare request body
String requestBody = ""; String requestBody = "";

View File

@ -0,0 +1,36 @@
import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/conversation.dart';
/// Conversation helper
///
/// @author Pierre HUBERT
class ConversationsHelper {
/// Download the list of conversations from the server
Future<List<Conversation>> downloadList() async {
final response =
await APIRequest(uri: "conversations/getList", needLogin: true).exec();
if (response.code != 200) return null;
try {
List<Conversation> list = List();
response.getArray().forEach((f) =>
list.add(Conversation(
id: f["ID"],
ownerID: f["ID_owner"],
lastActive: f["last_active"],
name: f["name"] == false ? null : f["name"],
following: f["following"] == 1,
sawLastMessage: f["saw_last_message"] == 1,
members: f["members"].map<int>((f) => int.parse(f)).toList(),
)));
return list;
} on Exception catch(e){
print(e.toString());
return null;
}
}
}

View File

@ -1,3 +1,5 @@
import 'package:comunic/helpers/api_helper.dart';
import 'package:comunic/models/api_response.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
/// API Request model /// API Request model
@ -11,12 +13,11 @@ class APIRequest {
final bool needLogin; final bool needLogin;
Map<String, String> args; Map<String, String> args;
APIRequest({ APIRequest({@required this.uri, this.needLogin = false, this.args})
@required this.uri, : assert(uri != null),
this.needLogin = false, assert(needLogin != null) {
}) : assert(uri != null), if (this.args == null) this.args = Map();
assert(needLogin != null), }
args = Map();
void addString(String name, String value) => args[name] = value; void addString(String name, String value) => args[name] = value;
@ -24,4 +25,7 @@ class APIRequest {
void addBool(String name, bool value) => void addBool(String name, bool value) =>
args[name] = value ? "true" : "false"; args[name] = value ? "true" : "false";
/// Execute the request
Future<APIResponse> exec() async => APIHelper().exec(this);
} }

View File

@ -0,0 +1,30 @@
import 'package:meta/meta.dart';
/// Conversation model
///
/// @author Pierre HUBERT
class Conversation {
final int id;
final int ownerID;
final int lastActive;
final String name;
final bool following;
final bool sawLastMessage;
final List<int> members;
const Conversation({
@required this.id,
@required this.ownerID,
@required this.lastActive,
@required this.name,
@required this.following,
@required this.sawLastMessage,
@required this.members,
}) : assert(id != null),
assert(ownerID != null),
assert(lastActive != null),
assert(following != null),
assert(sawLastMessage != null),
assert(members != null);
}

View File

@ -1,3 +1,4 @@
import 'package:comunic/ui/screens/conversations_screen.dart';
import 'package:comunic/ui/screens/menus_screen.dart'; import 'package:comunic/ui/screens/menus_screen.dart';
import 'package:comunic/ui/tiles/CustomBottomNavigationBarItem.dart'; import 'package:comunic/ui/tiles/CustomBottomNavigationBarItem.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -48,7 +49,7 @@ class _HomeRouteState extends State<HomeRoute> {
Widget _buildBody(BuildContext context) { Widget _buildBody(BuildContext context) {
switch (_currTab) { switch (_currTab) {
case 0: case 0:
return Text("Conversations"); return ConversationsScreen();
case 1: case 1:
return MenuScreen(); return MenuScreen();

View File

@ -0,0 +1,87 @@
import 'package:comunic/enums/load_error_level.dart';
import 'package:comunic/helpers/conversations_helper.dart';
import 'package:comunic/models/conversation.dart';
import 'package:comunic/ui/tiles/conversation_tile.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';
/// Conversations screen
///
/// @author Pierre HUBERT
class ConversationsScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ConversationScreenState();
}
class _ConversationScreenState extends State<ConversationsScreen> {
final ConversationsHelper _conversationsHelper = ConversationsHelper();
List<Conversation> _list;
LoadErrorLevel _error = LoadErrorLevel.NONE;
bool _loading = true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_loadConversations();
}
void setError(LoadErrorLevel err) => setState(() => _error = err);
void setLoading(bool loading) => setState(() => _loading = loading);
void gotLoadingError() {
setLoading(false);
setError(_list == null ? LoadErrorLevel.MAJOR : LoadErrorLevel.MINOR);
}
/// Load the list of conversations
Future<void> _loadConversations() async {
setError(LoadErrorLevel.NONE);
setLoading(true);
final list = await _conversationsHelper.downloadList();
if (list == null) return gotLoadingError();
//Save list
_list = list;
setLoading(false);
}
/// Build an error card
Widget _buildErrorCard() {
return buildErrorCard(
tr("Could not retrieve the list of conversations!"),
actions: <Widget>[
FlatButton(
onPressed: _loadConversations,
child: Text(
tr("Retry").toUpperCase(),
style: TextStyle(
color: Colors.white,
),
),
)
],
);
}
@override
Widget build(BuildContext context) {
if (_error == LoadErrorLevel.MAJOR) return _buildErrorCard();
if (_list == null) return buildCenteredProgressBar();
// Show the list of conversations
return ListView.builder(
itemBuilder: (context, index) {
return ConversationTile(
conversation: _list.elementAt(index),
);
},
itemCount: _list.length,
);
}
}

View File

@ -0,0 +1,55 @@
import 'package:comunic/models/conversation.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:flutter/material.dart';
/// Single conversation tile
///
/// @author Pierre HUBERT
class ConversationTile extends StatelessWidget {
final Conversation conversation;
const ConversationTile({Key key, this.conversation}) : super(key: key);
_buildSubInformation(IconData icon, String content) {
return Row(
children: <Widget>[
Icon(
icon,
size: 15.0,
color: Colors.grey,
),
Text(" " + content),
],
);
}
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(conversation.name == null ? "Unknown" : conversation.name),
leading: Icon(
conversation.sawLastMessage ? Icons.check_circle : Icons.lens,
color: conversation.sawLastMessage ? null : Colors.blue,
),
isThreeLine: true,
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildSubInformation(Icons.access_time, "time"), //TODO : improve the way the time is shown
_buildSubInformation(
Icons.group,
conversation.members.length == 1
? tr("1 member")
: tr(
"%num% members",
args: {
"num": conversation.members.length.toString(),
},
),
),
],
),
);
}
}

View File

@ -5,7 +5,15 @@
/// Translate a string /// Translate a string
/// ///
/// Translate a given [string] into the current language, if available /// Translate a given [string] into the current language, if available
String tr(String string) { ///
/// Then apply the list of [args] to the string, each argument name is
/// surrounded by '%'
String tr(String string, {Map<String, String> args}) {
//TODO : create translation system //TODO : create translation system
//Apply arguments
if(args != null)
args.forEach((key, value) => string = string.replaceAll("%$key%", value));
return string; return string;
} }

View File

@ -18,7 +18,7 @@ Widget buildLoadingPage() {
} }
/// Build and return an error card /// Build and return an error card
Widget buildErrorCard(String message) { Widget buildErrorCard(String message, {List<Widget> actions}) {
return Card( return Card(
elevation: 2.0, elevation: 2.0,
color: Colors.red, color: Colors.red,
@ -39,6 +39,9 @@ Widget buildErrorCard(String message) {
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
maxLines: null, maxLines: null,
), ),
),
Row(
children: actions == null ? <Widget>[] : actions,
) )
], ],
), ),