mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-03 19:54:12 +00:00 
			
		
		
		
	Display the list of friends of the user
This commit is contained in:
		
							
								
								
									
										38
									
								
								lib/helpers/friends_helper.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/helpers/friends_helper.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
import 'package:comunic/lists/friends_list.dart';
 | 
			
		||||
import 'package:comunic/models/api_request.dart';
 | 
			
		||||
import 'package:comunic/models/friend.dart';
 | 
			
		||||
 | 
			
		||||
/// Friends helper
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
class FriendsHelper {
 | 
			
		||||
  /// Get the list of friends of the user
 | 
			
		||||
  ///
 | 
			
		||||
  /// Returns the list of friends in case of success, or null if an error
 | 
			
		||||
  /// occurred
 | 
			
		||||
  Future<FriendsList> downloadList() async {
 | 
			
		||||
    final response = await APIRequest(
 | 
			
		||||
      uri: "friends/getList",
 | 
			
		||||
      needLogin: true,
 | 
			
		||||
      args: {
 | 
			
		||||
        "complete": "true",
 | 
			
		||||
      },
 | 
			
		||||
    ).exec();
 | 
			
		||||
 | 
			
		||||
    if (response.code != 200) return null;
 | 
			
		||||
 | 
			
		||||
    // Parse and return the list of friends
 | 
			
		||||
    FriendsList list = FriendsList();
 | 
			
		||||
    response.getArray().forEach((f) =>
 | 
			
		||||
        list.add(Friend(
 | 
			
		||||
          id: f["ID_friend"],
 | 
			
		||||
          accepted: f["accepted"] == 1,
 | 
			
		||||
          lastActive: f["time_last_activity"],
 | 
			
		||||
          following: f["following"] == 1,
 | 
			
		||||
          canPostTexts: f["canPostTexts"],),),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return list;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								lib/lists/friends_list.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/lists/friends_list.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import 'dart:collection';
 | 
			
		||||
 | 
			
		||||
import 'package:comunic/models/friend.dart';
 | 
			
		||||
 | 
			
		||||
/// List of friends of the user
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
class FriendsList extends ListBase<Friend> {
 | 
			
		||||
  List<Friend> _list = List();
 | 
			
		||||
 | 
			
		||||
  int get length => _list.length;
 | 
			
		||||
 | 
			
		||||
  set length(int length) => _list.length = length;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Friend operator [](int index) => _list[index];
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void operator []=(int index, Friend value) => _list[index] = value;
 | 
			
		||||
 | 
			
		||||
  /// Get the ID of all the friends of the current user
 | 
			
		||||
  List<int> get usersId => map((f) => f.id).toList();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								lib/models/friend.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/models/friend.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import 'package:comunic/utils/date_utils.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
/// Single user Friend information
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
class Friend {
 | 
			
		||||
  final int id;
 | 
			
		||||
  final bool accepted;
 | 
			
		||||
  final int lastActive;
 | 
			
		||||
  final bool following;
 | 
			
		||||
  final bool canPostTexts;
 | 
			
		||||
 | 
			
		||||
  Friend({
 | 
			
		||||
    @required this.id,
 | 
			
		||||
    @required this.accepted,
 | 
			
		||||
    @required this.lastActive,
 | 
			
		||||
    @required this.following,
 | 
			
		||||
    @required this.canPostTexts,
 | 
			
		||||
  })  : assert(id != null),
 | 
			
		||||
        assert(accepted != null),
 | 
			
		||||
        assert(lastActive != null),
 | 
			
		||||
        assert(following != null),
 | 
			
		||||
        assert(canPostTexts != null);
 | 
			
		||||
 | 
			
		||||
  /// Check out whether friend is connected or not
 | 
			
		||||
  bool get isConnected => time() - 30 < lastActive;
 | 
			
		||||
}
 | 
			
		||||
@@ -31,6 +31,9 @@ class User extends CacheModel {
 | 
			
		||||
  /// Get user full name
 | 
			
		||||
  String get fullName => firstName + " " + lastName;
 | 
			
		||||
 | 
			
		||||
  /// Get user display name
 | 
			
		||||
  String get displayName => fullName; //TODO : support HTML characters (eg: É => é)
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toMap() {
 | 
			
		||||
    return {
 | 
			
		||||
      UserTableContract.C_ID: id,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
import 'package:comunic/ui/screens/conversations_list_screen.dart';
 | 
			
		||||
import 'package:comunic/ui/screens/friends_list_screen.dart';
 | 
			
		||||
import 'package:comunic/ui/screens/menus_screen.dart';
 | 
			
		||||
import 'package:comunic/ui/tiles/custom_bottom_navigation_bar_item.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
/// Main route of the application
 | 
			
		||||
@@ -52,6 +54,9 @@ class _HomeRouteState extends State<HomeRoute> {
 | 
			
		||||
        return ConversationsListScreen();
 | 
			
		||||
 | 
			
		||||
      case 1:
 | 
			
		||||
        return FriendsListScreen();
 | 
			
		||||
 | 
			
		||||
      case 2:
 | 
			
		||||
        return MenuScreen();
 | 
			
		||||
 | 
			
		||||
      default:
 | 
			
		||||
@@ -64,11 +69,15 @@ class _HomeRouteState extends State<HomeRoute> {
 | 
			
		||||
    return <BottomNavigationBarItem>[
 | 
			
		||||
      CustomNavigationBarItem(
 | 
			
		||||
        icon: Icon(Icons.chat),
 | 
			
		||||
        title: Text("Conversations"),
 | 
			
		||||
        title: Text(tr("Conversations")),
 | 
			
		||||
      ),
 | 
			
		||||
      CustomNavigationBarItem(
 | 
			
		||||
        icon: Icon(Icons.group),
 | 
			
		||||
        title: Text(tr("Friends")),
 | 
			
		||||
      ),
 | 
			
		||||
      CustomNavigationBarItem(
 | 
			
		||||
        icon: Icon(Icons.menu),
 | 
			
		||||
        title: Text("Menu"),
 | 
			
		||||
        title: Text(tr("Menu")),
 | 
			
		||||
      ),
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										122
									
								
								lib/ui/screens/friends_list_screen.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								lib/ui/screens/friends_list_screen.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
import 'package:comunic/helpers/friends_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/users_helper.dart';
 | 
			
		||||
import 'package:comunic/lists/friends_list.dart';
 | 
			
		||||
import 'package:comunic/lists/users_list.dart';
 | 
			
		||||
import 'package:comunic/ui/tiles/accepted_friend_tile.dart';
 | 
			
		||||
import 'package:comunic/ui/tiles/pending_friend_tile.dart';
 | 
			
		||||
import 'package:comunic/ui/widgets/safe_state.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/ui_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
/// Friends list screen
 | 
			
		||||
///
 | 
			
		||||
/// Display the list of friends of the current user
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
enum _ErrorsLevel { NONE, MINOR, MAJOR }
 | 
			
		||||
 | 
			
		||||
class FriendsListScreen extends StatefulWidget {
 | 
			
		||||
  @override
 | 
			
		||||
  State<StatefulWidget> createState() => _FriendsListScreenState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _FriendsListScreenState extends SafeState<FriendsListScreen> {
 | 
			
		||||
  /// Helpers
 | 
			
		||||
  final _friendsHelper = FriendsHelper();
 | 
			
		||||
  final _usersHelper = UsersHelper();
 | 
			
		||||
 | 
			
		||||
  /// Widget members
 | 
			
		||||
  _ErrorsLevel _error = _ErrorsLevel.NONE;
 | 
			
		||||
  FriendsList _friendsList;
 | 
			
		||||
  UsersList _usersInfo;
 | 
			
		||||
  bool _loading = true;
 | 
			
		||||
 | 
			
		||||
  /// Useful setters
 | 
			
		||||
  set error(_ErrorsLevel err) => setState(() => _error = err);
 | 
			
		||||
 | 
			
		||||
  set loading(bool loading) => setState(() => _loading = loading);
 | 
			
		||||
 | 
			
		||||
  void _gotError() =>
 | 
			
		||||
      error = _friendsList == null ? _ErrorsLevel.MAJOR : _ErrorsLevel.MINOR;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void didChangeDependencies() {
 | 
			
		||||
    super.didChangeDependencies();
 | 
			
		||||
    _loadList();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Load the list of friends
 | 
			
		||||
  Future<void> _loadList() async {
 | 
			
		||||
    error = _ErrorsLevel.NONE;
 | 
			
		||||
    loading = true;
 | 
			
		||||
 | 
			
		||||
    // Get the list of friends
 | 
			
		||||
    final list = await _friendsHelper.downloadList();
 | 
			
		||||
 | 
			
		||||
    // Check for errors
 | 
			
		||||
    if (list == null) return _gotError();
 | 
			
		||||
 | 
			
		||||
    // Get information about related users
 | 
			
		||||
    final users = await _usersHelper.getUsersInfo(list.usersId);
 | 
			
		||||
 | 
			
		||||
    // Check for errors
 | 
			
		||||
    if (users == null) return _gotError();
 | 
			
		||||
 | 
			
		||||
    // Apply new information
 | 
			
		||||
    setState(() {
 | 
			
		||||
      _friendsList = list;
 | 
			
		||||
      _usersInfo = users;
 | 
			
		||||
    });
 | 
			
		||||
    loading = false;
 | 
			
		||||
    error = _ErrorsLevel.NONE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Build and return loading error
 | 
			
		||||
  Widget _buildError() =>
 | 
			
		||||
      buildErrorCard(
 | 
			
		||||
        tr("Could not load your list of friends!"),
 | 
			
		||||
        actions: [
 | 
			
		||||
          FlatButton(
 | 
			
		||||
            onPressed: _loadList,
 | 
			
		||||
            child: Text(
 | 
			
		||||
              tr("Retry").toUpperCase(),
 | 
			
		||||
              style: TextStyle(color: Colors.white),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    if (_error == _ErrorsLevel.MAJOR) return _buildError();
 | 
			
		||||
    if (_friendsList == null) return buildCenteredProgressBar();
 | 
			
		||||
 | 
			
		||||
    return Column(
 | 
			
		||||
      children: <Widget>[
 | 
			
		||||
 | 
			
		||||
        // Check for errors
 | 
			
		||||
        Container(child: _error != _ErrorsLevel.NONE ? _buildError() : null),
 | 
			
		||||
 | 
			
		||||
        // Check if loading
 | 
			
		||||
        Container(child: _loading ? CircularProgressIndicator() : null),
 | 
			
		||||
 | 
			
		||||
        // List of friends
 | 
			
		||||
        Expanded(
 | 
			
		||||
          child: ListView.builder(itemCount: _friendsList.length, itemBuilder: (c, i) =>
 | 
			
		||||
          _friendsList[i].accepted ? AcceptedFriendTile(
 | 
			
		||||
            friend: _friendsList[i],
 | 
			
		||||
            user: _usersInfo.getUser(_friendsList[i].id),
 | 
			
		||||
          ) : PendingFriendTile(
 | 
			
		||||
            friend: _friendsList[i],
 | 
			
		||||
            user: _usersInfo.getUser(_friendsList[i].id),
 | 
			
		||||
            onRespond: (friend, accept){},
 | 
			
		||||
          )),
 | 
			
		||||
        ),
 | 
			
		||||
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								lib/ui/tiles/accepted_friend_tile.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lib/ui/tiles/accepted_friend_tile.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
import 'package:comunic/models/friend.dart';
 | 
			
		||||
import 'package:comunic/models/user.dart';
 | 
			
		||||
import 'package:comunic/ui/widgets/account_image_widget.dart';
 | 
			
		||||
import 'package:comunic/utils/date_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
/// Accepted friend tile
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
class AcceptedFriendTile extends StatelessWidget {
 | 
			
		||||
  final Friend friend;
 | 
			
		||||
  final User user;
 | 
			
		||||
 | 
			
		||||
  const AcceptedFriendTile(
 | 
			
		||||
      {Key key, @required this.friend, @required this.user})
 | 
			
		||||
      : assert(friend != null),
 | 
			
		||||
        assert(user != null),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return ListTile(
 | 
			
		||||
      leading: AccountImageWidget(user: user),
 | 
			
		||||
      title: Text(user.displayName),
 | 
			
		||||
      subtitle: friend.isConnected
 | 
			
		||||
          ? Text(
 | 
			
		||||
              tr(
 | 
			
		||||
                "Online",
 | 
			
		||||
              ),
 | 
			
		||||
              style: TextStyle(color: Colors.green),
 | 
			
		||||
            )
 | 
			
		||||
          : Text(
 | 
			
		||||
        diffTimeFromNowToStr(friend.lastActive),
 | 
			
		||||
            ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								lib/ui/tiles/pending_friend_tile.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								lib/ui/tiles/pending_friend_tile.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
import 'package:comunic/models/friend.dart';
 | 
			
		||||
import 'package:comunic/models/user.dart';
 | 
			
		||||
import 'package:comunic/ui/widgets/account_image_widget.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
/// Pending friend tile
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
typedef RespondFriendshipRequestCallback = void Function(Friend, bool);
 | 
			
		||||
 | 
			
		||||
class PendingFriendTile extends StatelessWidget {
 | 
			
		||||
  final Friend friend;
 | 
			
		||||
  final User user;
 | 
			
		||||
  final RespondFriendshipRequestCallback onRespond;
 | 
			
		||||
 | 
			
		||||
  const PendingFriendTile(
 | 
			
		||||
      {Key key,
 | 
			
		||||
      @required this.friend,
 | 
			
		||||
      @required this.user,
 | 
			
		||||
      @required this.onRespond})
 | 
			
		||||
      : assert(friend != null),
 | 
			
		||||
        assert(user != null),
 | 
			
		||||
        assert(onRespond != null),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return ListTile(
 | 
			
		||||
      leading: AccountImageWidget(
 | 
			
		||||
        user: user,
 | 
			
		||||
      ),
 | 
			
		||||
      isThreeLine: true,
 | 
			
		||||
      title: Text(user.fullName),
 | 
			
		||||
      subtitle: Container(
 | 
			
		||||
        height: 30.0,
 | 
			
		||||
        margin: EdgeInsets.only(top: 8.0),
 | 
			
		||||
        child: Row(
 | 
			
		||||
          mainAxisAlignment: MainAxisAlignment.end,
 | 
			
		||||
          children: <Widget>[
 | 
			
		||||
            FlatButton(
 | 
			
		||||
              child: Text(
 | 
			
		||||
                tr("Accept").toUpperCase(),
 | 
			
		||||
                style: TextStyle(color: Colors.white),
 | 
			
		||||
              ),
 | 
			
		||||
              color: Colors.green,
 | 
			
		||||
              onPressed: () => onRespond(friend, true),
 | 
			
		||||
            ),
 | 
			
		||||
            Container(width: 8.0,),
 | 
			
		||||
            FlatButton(
 | 
			
		||||
              child: Text(
 | 
			
		||||
                tr("Reject").toUpperCase(),
 | 
			
		||||
                style: TextStyle(color: Colors.white),
 | 
			
		||||
              ),
 | 
			
		||||
              color: Colors.red,
 | 
			
		||||
              onPressed: () => onRespond(friend, false),
 | 
			
		||||
            )
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								lib/ui/widgets/safe_state.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/ui/widgets/safe_state.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
/// Little State hack to avoid issues
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
abstract class SafeState<T extends StatefulWidget> extends State<T> {
 | 
			
		||||
  @override
 | 
			
		||||
  void setState(fn) {
 | 
			
		||||
    if(mounted)
 | 
			
		||||
      super.setState(fn);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user