From 23a5e381452ed6a91088281938d7fd2c9ccecde3 Mon Sep 17 00:00:00 2001 From: Tovi Jaeschke-Rogers Date: Wed, 16 Nov 2022 03:00:15 +1030 Subject: [PATCH] Add pull to refresh on conversations and friends lists --- Backend/Api/Friends/Friends.go | 31 +++++++++++++------ Backend/Database/ConversationDetails.go | 4 +-- Backend/Database/FriendRequests.go | 20 +++++++++--- mobile/lib/database/models/conversations.dart | 8 +++++ .../conversations_repository.dart | 22 +++++++++++++ .../repositories/friends_repository.dart | 14 +++++++++ .../lib/services/conversations_service.dart | 4 +++ mobile/lib/services/friends_service.dart | 13 ++++++-- mobile/lib/utils/storage/database.dart | 4 ++- mobile/lib/views/main/conversation/list.dart | 14 +++++---- mobile/lib/views/main/friend/list.dart | 15 +++++---- 11 files changed, 118 insertions(+), 31 deletions(-) diff --git a/Backend/Api/Friends/Friends.go b/Backend/Api/Friends/Friends.go index 7321902..efd0736 100644 --- a/Backend/Api/Friends/Friends.go +++ b/Backend/Api/Friends/Friends.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" "strconv" + "time" "git.tovijaeschke.xyz/tovi/Envelope/Backend/Api/Auth" "git.tovijaeschke.xyz/tovi/Envelope/Backend/Database" @@ -13,24 +14,36 @@ import ( // FriendRequestList gets friend request list func FriendRequestList(w http.ResponseWriter, r *http.Request) { var ( - userSession Database.Session - friends Database.FriendRequestList - values url.Values - returnJSON []byte - page int - err error + userSession Database.Session + friends Database.FriendRequestList + query url.Values + acceptedAtString []string + acceptedAt time.Time + page int + ok bool + returnJSON []byte + err error ) - values = r.URL.Query() + query = r.URL.Query() - page, err = strconv.Atoi(values.Get("page")) + page, err = strconv.Atoi(query.Get("page")) if err != nil { page = 0 } + acceptedAtString, ok = query["updated_at"] + if ok { + acceptedAt, err = time.Parse(time.RFC3339, acceptedAtString[0]) + if err != nil { + http.Error(w, "Invalid Data", http.StatusBadGateway) + return + } + } + userSession, _ = Auth.CheckCookie(r) - friends, err = Database.GetFriendRequestsByUserID(userSession.UserID.String(), page) + friends, err = Database.GetFriendRequestsByUserID(userSession.UserID.String(), page, acceptedAt) if err != nil { http.Error(w, "Error", http.StatusInternalServerError) return diff --git a/Backend/Database/ConversationDetails.go b/Backend/Database/ConversationDetails.go index 70cd6d6..71886da 100644 --- a/Backend/Database/ConversationDetails.go +++ b/Backend/Database/ConversationDetails.go @@ -22,8 +22,8 @@ type ConversationDetail struct { AdminAddMembers string ` json:"admin_add_members"` // Stored encrypted AdminEditInfo string ` json:"admin_edit_info"` // Stored encrypted AdminSendMessages string ` json:"admin_send_messages"` // Stored encrypted - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + CreatedAt time.Time ` json:"created_at"` + UpdatedAt time.Time ` json:"updated_at"` } // GetConversationDetailByID gets by id diff --git a/Backend/Database/FriendRequests.go b/Backend/Database/FriendRequests.go index 3d9edb0..3726204 100644 --- a/Backend/Database/FriendRequests.go +++ b/Backend/Database/FriendRequests.go @@ -42,8 +42,9 @@ func GetFriendRequestByID(id string) (FriendRequest, error) { } // GetFriendRequestsByUserID gets friend request by user id -func GetFriendRequestsByUserID(userID string, page int) ([]FriendRequest, error) { +func GetFriendRequestsByUserID(userID string, page int, acceptedAt time.Time) ([]FriendRequest, error) { var ( + query *gorm.DB friends []FriendRequest offset int err error @@ -51,11 +52,20 @@ func GetFriendRequestsByUserID(userID string, page int) ([]FriendRequest, error) offset = page * PageSize - err = DB.Model(FriendRequest{}). + query = DB.Model(FriendRequest{}). Preload("FriendRequestDeviceTokens.DeviceToken"). - Where("user_id = ?", userID). - Offset(offset). - Limit(PageSize). + Where("user_id = ?", userID) + + if !acceptedAt.IsZero() { + query = query.Where("accepted_at > ?", acceptedAt). + Or("created_at > ?", acceptedAt) + } else { + query = query. + Offset(offset). + Limit(PageSize) + } + + err = query. Order("created_at DESC"). Find(&friends). Error diff --git a/mobile/lib/database/models/conversations.dart b/mobile/lib/database/models/conversations.dart index f069ad5..9843951 100644 --- a/mobile/lib/database/models/conversations.dart +++ b/mobile/lib/database/models/conversations.dart @@ -37,6 +37,8 @@ class Conversation { bool adminAddMembers = true; bool adminEditInfo = true; bool adminSendMessages = false; + DateTime createdAt; + DateTime updatedAt; File? icon; Conversation({ @@ -52,6 +54,8 @@ class Conversation { required this.adminAddMembers, required this.adminEditInfo, required this.adminSendMessages, + required this.createdAt, + required this.updatedAt, this.icon, }); @@ -85,6 +89,8 @@ class Conversation { adminAddMembers: true, adminEditInfo: true, adminSendMessages: false, + createdAt: DateTime.now(), + updatedAt: DateTime.now(), ); } @@ -175,6 +181,8 @@ class Conversation { 'admin_add_members': adminAddMembers ? 1 : 0, 'admin_edit_info': adminEditInfo ? 1 : 0, 'admin_send_messages': adminSendMessages ? 1 : 0, + 'created_at': createdAt.toIso8601String(), + 'updated_at': updatedAt.toIso8601String(), }; } diff --git a/mobile/lib/database/repositories/conversations_repository.dart b/mobile/lib/database/repositories/conversations_repository.dart index 93a3587..79251d9 100644 --- a/mobile/lib/database/repositories/conversations_repository.dart +++ b/mobile/lib/database/repositories/conversations_repository.dart @@ -38,6 +38,8 @@ class ConversationsRepository { adminAddMembers: true, adminEditInfo: true, adminSendMessages: false, + createdAt: DateTime.now(), + updatedAt: DateTime.now(), ); await db.insert( @@ -131,6 +133,8 @@ class ConversationsRepository { adminAddMembers: maps[0]['admin_add_members'] == 1, adminEditInfo: maps[0]['admin_edit_info'] == 1, adminSendMessages: maps[0]['admin_send_messages'] == 1, + createdAt: DateTime.parse(maps[0]['created_at']), + updatedAt: DateTime.parse(maps[0]['updated_at']), ); } @@ -163,6 +167,8 @@ class ConversationsRepository { adminAddMembers: maps[i]['admin_add_members'] == 1, adminEditInfo: maps[i]['admin_edit_info'] == 1, adminSendMessages: maps[i]['admin_send_messages'] == 1, + createdAt: DateTime.parse(maps[i]['created_at']), + updatedAt: DateTime.parse(maps[i]['updated_at']), ); }); } @@ -200,7 +206,23 @@ class ConversationsRepository { adminAddMembers: maps[0]['admin_add_members'] == 1, adminEditInfo: maps[0]['admin_edit_info'] == 1, adminSendMessages: maps[0]['admin_send_messages'] == 1, + createdAt: DateTime.parse(maps[0]['created_at']), + updatedAt: DateTime.parse(maps[0]['updated_at']), ); } + + static Future getLatestUpdatedAt() async { + final db = await getDatabaseConnection(); + + final List> maps = await db.rawQuery( + ''' + SELECT conversations.updated_at FROM conversations + ORDER BY updated_at DESC + LIMIT 1; + ''' + ); + + return maps.isNotEmpty ? DateTime.parse(maps[0]['updated_at']) : null; + } } diff --git a/mobile/lib/database/repositories/friends_repository.dart b/mobile/lib/database/repositories/friends_repository.dart index 64bf442..d10f914 100644 --- a/mobile/lib/database/repositories/friends_repository.dart +++ b/mobile/lib/database/repositories/friends_repository.dart @@ -60,4 +60,18 @@ class FriendsRepository { ); }); } + + static Future getLatestAcceptedAt() async { + final db = await getDatabaseConnection(); + + final List> maps = await db.rawQuery( + ''' + SELECT friends.accepted_at FROM friends + ORDER BY accepted_at DESC + LIMIT 1; + ''' + ); + + return maps.isNotEmpty ? DateTime.parse(maps[0]['accepted_at']) : null; + } } diff --git a/mobile/lib/services/conversations_service.dart b/mobile/lib/services/conversations_service.dart index d5cf1e0..32ed2fc 100644 --- a/mobile/lib/services/conversations_service.dart +++ b/mobile/lib/services/conversations_service.dart @@ -160,6 +160,10 @@ class ConversationsService { static Future _storeConversations(Database db, Conversation conversation, Map detailsJson) async { + + conversation.createdAt = DateTime.parse(detailsJson['created_at']); + conversation.updatedAt = DateTime.parse(detailsJson['updated_at']); + conversation.messageExpiryDefault = detailsJson['message_expiry']; conversation.twoUser = AesHelper.aesDecrypt( diff --git a/mobile/lib/services/friends_service.dart b/mobile/lib/services/friends_service.dart index d1a96d6..facb5ad 100644 --- a/mobile/lib/services/friends_service.dart +++ b/mobile/lib/services/friends_service.dart @@ -11,11 +11,20 @@ import '/utils/storage/database.dart'; import '/utils/storage/session_cookie.dart'; class FriendsService { - static Future updateFriends() async { + static Future updateFriends({DateTime? acceptedAt}) async { RSAPrivateKey privKey = await MyProfile.getPrivateKey(); + Map params = {}; + + if (acceptedAt != null) { + params['updated_at'] = acceptedAt.toIso8601String(); + } + + var uri = await MyProfile.getServerUrl('api/v1/auth/friend_requests'); + uri = uri.replace(queryParameters: params); + var resp = await http.get( - await MyProfile.getServerUrl('api/v1/auth/friend_requests'), + uri, headers: { 'cookie': await getSessionCookie(), } diff --git a/mobile/lib/utils/storage/database.dart b/mobile/lib/utils/storage/database.dart index 5bed118..de6d020 100644 --- a/mobile/lib/utils/storage/database.dart +++ b/mobile/lib/utils/storage/database.dart @@ -44,7 +44,9 @@ Future getDatabaseConnection() async { message_expiry TEXT, admin_add_members INTEGER, admin_edit_info INTEGER, - admin_send_messages INTEGER + admin_send_messages INTEGER, + created_at TEXT, + updated_at TEXT ); '''); diff --git a/mobile/lib/views/main/conversation/list.dart b/mobile/lib/views/main/conversation/list.dart index 1836724..64725a5 100644 --- a/mobile/lib/views/main/conversation/list.dart +++ b/mobile/lib/views/main/conversation/list.dart @@ -174,12 +174,14 @@ class _ConversationListState extends State { } Future _refresh() async { - Future.delayed( - const Duration(seconds: 1), - () { - print('Doing thing'); - } - ); + DateTime? updatedAt = await ConversationsRepository.getLatestUpdatedAt(); + if (updatedAt == null) { + return; + } + + ConversationsService.updateConversations(updatedAt: updatedAt); + conversations = await ConversationsRepository.getConversations(); + setState(() {}); } onGoBack(dynamic value) async { diff --git a/mobile/lib/views/main/friend/list.dart b/mobile/lib/views/main/friend/list.dart index 93d21a4..dcd3385 100644 --- a/mobile/lib/views/main/friend/list.dart +++ b/mobile/lib/views/main/friend/list.dart @@ -1,4 +1,5 @@ import 'package:Envelope/database/repositories/friends_repository.dart'; +import 'package:Envelope/services/friends_service.dart'; import 'package:flutter/material.dart'; import '/components/custom_title_bar.dart'; @@ -194,11 +195,13 @@ class _FriendListState extends State { } Future _refresh() async { - Future.delayed( - const Duration(seconds: 1), - () { - print('Doing thing'); - } - ); + DateTime? acceptedAt = await FriendsRepository.getLatestAcceptedAt(); + if (acceptedAt == null) { + return; + } + + FriendsService.updateFriends(acceptedAt: acceptedAt); + friends = await FriendsRepository.getFriends(); + setState(() {}); } }