diff --git a/lib/common/avatar/avatar.dart b/lib/common/avatar/avatar.dart index d77762c..681df3a 100644 --- a/lib/common/avatar/avatar.dart +++ b/lib/common/avatar/avatar.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-10-13 21:49:53 - * @LastEditTime : 2022-10-20 13:46:16 + * @LastEditTime : 2022-10-20 16:53:26 * @Description : */ @@ -82,7 +82,7 @@ class UserAvatar extends StatelessWidget { alignment: Alignment.center, child: FittedBox( fit: BoxFit.cover, - child: Image.memory(base64.decode(state.userInfo.avatarEncoded!)), + child: state.preCachedAvatar ?? Image.memory(base64.decode(state.userInfo.avatarEncoded!)), ), ), Material( diff --git a/lib/common/avatar/cubit/avatar_cubit.dart b/lib/common/avatar/cubit/avatar_cubit.dart index 755bdf2..3f38863 100644 --- a/lib/common/avatar/cubit/avatar_cubit.dart +++ b/lib/common/avatar/cubit/avatar_cubit.dart @@ -1,11 +1,14 @@ /* * @Author : Linloir * @Date : 2022-10-13 21:50:14 - * @LastEditTime : 2022-10-13 22:03:01 + * @LastEditTime : 2022-10-20 17:02:19 * @Description : */ +import 'dart:convert'; + import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; import 'package:tcp_client/common/avatar/cubit/avatar_state.dart'; import 'package:tcp_client/repositories/common_models/userinfo.dart'; import 'package:tcp_client/repositories/user_repository/user_repository.dart'; @@ -14,15 +17,25 @@ class AvatarCubit extends Cubit { AvatarCubit({ required int userid, required this.userRepository - }): super(AvatarState(userInfo: userRepository.getUserInfo(userid: userid))) { + }): super(AvatarState(userInfo: userRepository.getUserInfo(userid: userid))) + { userRepository.userInfoStreamBroadcast.listen(onFetchedUserInfo); + emit(AvatarState( + userInfo: state.userInfo, + preCachedAvatar: state.userInfo.avatarEncoded == null ? null : + Image.memory(base64.decode(state.userInfo.avatarEncoded!)) + )); } final UserRepository userRepository; void onFetchedUserInfo(UserInfo userInfo) { if(userInfo.userID == state.userInfo.userID) { - emit(AvatarState(userInfo: userInfo)); + emit(AvatarState( + userInfo: userInfo, + preCachedAvatar: userInfo.avatarEncoded == null ? null : + Image.memory(base64.decode(userInfo.avatarEncoded!)) + )); } } } \ No newline at end of file diff --git a/lib/common/avatar/cubit/avatar_state.dart b/lib/common/avatar/cubit/avatar_state.dart index 13844fd..e6998db 100644 --- a/lib/common/avatar/cubit/avatar_state.dart +++ b/lib/common/avatar/cubit/avatar_state.dart @@ -1,20 +1,23 @@ /* * @Author : Linloir * @Date : 2022-10-13 21:50:07 - * @LastEditTime : 2022-10-13 22:02:11 + * @LastEditTime : 2022-10-20 16:51:11 * @Description : */ import 'package:equatable/equatable.dart'; +import 'package:flutter/cupertino.dart'; import 'package:tcp_client/repositories/common_models/userinfo.dart'; class AvatarState extends Equatable { const AvatarState({ required this.userInfo, + this.preCachedAvatar }); final UserInfo userInfo; + final Image? preCachedAvatar; @override - List get props => [userInfo.userID, userInfo.avatarEncoded]; + List get props => [userInfo.userID, userInfo.avatarEncoded, preCachedAvatar]; } diff --git a/lib/home/view/contact_page/contact_page.dart b/lib/home/view/contact_page/contact_page.dart index 71d81c3..b67065d 100644 --- a/lib/home/view/contact_page/contact_page.dart +++ b/lib/home/view/contact_page/contact_page.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-10-12 23:36:07 - * @LastEditTime : 2022-10-18 11:25:18 + * @LastEditTime : 2022-10-20 17:04:52 * @Description : */ @@ -26,7 +26,7 @@ class ContactPage extends StatelessWidget { itemCount: indexedData.length, itemBuilder: (context, index) { return ContactTile( - userInfo: (indexedData[index] as ContactModel).userInfo, + contactInfo: (indexedData[index] as ContactModel), ); }, physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), @@ -38,7 +38,7 @@ class ContactPage extends StatelessWidget { color: Colors.grey[200], alignment: Alignment.centerLeft, child: Text( - indexedData[index].getSuspensionTag(), + indexedData[index].getSuspensionTag() == '⨂' ? 'Pending for reply' : indexedData[index].getSuspensionTag() == '⊙' ? 'Requesting' : indexedData[index].getSuspensionTag(), softWrap: false, style: TextStyle( fontSize: 14.0, diff --git a/lib/home/view/contact_page/cubit/contact_cubit.dart b/lib/home/view/contact_page/cubit/contact_cubit.dart index 6358371..a968fbe 100644 --- a/lib/home/view/contact_page/cubit/contact_cubit.dart +++ b/lib/home/view/contact_page/cubit/contact_cubit.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-10-13 14:01:45 - * @LastEditTime : 2022-10-14 23:03:02 + * @LastEditTime : 2022-10-20 16:36:05 * @Description : */ @@ -22,7 +22,7 @@ class ContactCubit extends Cubit { }): super(ContactState.empty()) { subscription = tcpRepository.responseStreamBroadcast.listen(_onResponse); updateContacts(); - timer = Timer.periodic(const Duration(seconds: 10), (timer) {updateContacts();}); + timer = Timer.periodic(const Duration(seconds: 20), (timer) {updateContacts();}); } final LocalServiceRepository localServiceRepository; diff --git a/lib/home/view/contact_page/cubit/contact_state.dart b/lib/home/view/contact_page/cubit/contact_state.dart index b909f02..4375193 100644 --- a/lib/home/view/contact_page/cubit/contact_state.dart +++ b/lib/home/view/contact_page/cubit/contact_state.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-10-13 14:01:39 - * @LastEditTime : 2022-10-17 17:28:33 + * @LastEditTime : 2022-10-20 16:09:50 * @Description : */ @@ -24,13 +24,17 @@ class ContactState extends Equatable { static ContactState empty() => const ContactState(contacts: [], pending: [], requesting: []); List get indexedData { - var indexedList = contacts.map((e) => ContactModel(userInfo: e)).toList(); + var indexedList = contacts.map((e) => ContactModel(userInfo: e, status: ContactStatus.added)).toList(); indexedList.sort((a, b) => a.getSuspensionTag().compareTo(b.getSuspensionTag())); + //Add requesting contacts + indexedList.insertAll(0, requesting.map((e) => ContactModel(userInfo: e, status: ContactStatus.requesting)).toList()); + //Add pending contacts + indexedList.insertAll(0, pending.map((e) => ContactModel(userInfo: e, status: ContactStatus.pending)).toList()); // SuspensionUtil.sortListBySuspensionTag(indexedList); SuspensionUtil.setShowSuspensionStatus(indexedList); return indexedList; } @override - List get props => contacts; + List get props => [...contacts, ...pending, ...requesting]; } diff --git a/lib/home/view/contact_page/models/contact_model.dart b/lib/home/view/contact_page/models/contact_model.dart index e88617f..e2a705d 100644 --- a/lib/home/view/contact_page/models/contact_model.dart +++ b/lib/home/view/contact_page/models/contact_model.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-10-13 15:34:08 - * @LastEditTime : 2022-10-17 17:20:47 + * @LastEditTime : 2022-10-20 16:00:22 * @Description : */ @@ -9,13 +9,22 @@ import 'package:azlistview/azlistview.dart'; import 'package:lpinyin/lpinyin.dart'; import 'package:tcp_client/repositories/common_models/userinfo.dart'; +enum ContactStatus { added, pending, requesting } + class ContactModel extends ISuspensionBean { final UserInfo userInfo; + final ContactStatus status; - ContactModel({required this.userInfo}); + ContactModel({required this.userInfo, required this.status}); @override String getSuspensionTag() { + if(status == ContactStatus.pending) { + return '⨂'; + } + else if(status == ContactStatus.requesting) { + return '⊙'; + } var pinyin = PinyinHelper.getPinyinE(userInfo.userName); var tag = pinyin.substring(0, 1).toUpperCase(); if(!RegExp('[A-Z]').hasMatch(tag)) { diff --git a/lib/home/view/contact_page/view/contact_tile.dart b/lib/home/view/contact_page/view/contact_tile.dart index 7bb638b..4ec43ee 100644 --- a/lib/home/view/contact_page/view/contact_tile.dart +++ b/lib/home/view/contact_page/view/contact_tile.dart @@ -1,30 +1,34 @@ /* * @Author : Linloir * @Date : 2022-10-13 14:02:00 - * @LastEditTime : 2022-10-18 11:25:32 + * @LastEditTime : 2022-10-20 16:26:33 * @Description : */ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:loading_indicator/loading_indicator.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:tcp_client/chat/chat_page.dart'; import 'package:tcp_client/common/avatar/avatar.dart'; import 'package:tcp_client/common/username/username.dart'; import 'package:tcp_client/home/cubit/home_cubit.dart'; import 'package:tcp_client/home/cubit/home_state.dart'; +import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart'; +import 'package:tcp_client/home/view/contact_page/models/contact_model.dart'; import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart'; -import 'package:tcp_client/repositories/common_models/userinfo.dart'; import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart'; +import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart'; import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart'; import 'package:tcp_client/repositories/user_repository/user_repository.dart'; class ContactTile extends StatelessWidget { const ContactTile({ - required this.userInfo, + required this.contactInfo, super.key }); - final UserInfo userInfo; + final ContactModel contactInfo; @override Widget build(BuildContext context) { @@ -33,16 +37,16 @@ class ContactTile extends StatelessWidget { fit: StackFit.expand, children: [ InkWell( - onTap: () { + onTap: contactInfo.status == ContactStatus.added ? () { Navigator.of(context).push(ChatPage.route( userRepository: context.read(), localServiceRepository: context.read(), tcpRepository: context.read(), - userID: userInfo.userID + userID: contactInfo.userInfo.userID )); - context.read().addEmptyMessageOf(targetUser: userInfo.userID); + context.read().addEmptyMessageOf(targetUser: contactInfo.userInfo.userID); context.read().switchPage(HomePagePosition.message); - }, + } : (){}, ), Padding( padding: const EdgeInsets.symmetric( @@ -52,7 +56,7 @@ class ContactTile extends StatelessWidget { child: Row( children: [ IgnorePointer( - child: UserAvatar(userid: userInfo.userID), + child: UserAvatar(userid: contactInfo.userInfo.userID), ), const SizedBox(width: 12,), Expanded( @@ -61,10 +65,32 @@ class ContactTile extends StatelessWidget { vertical: 12.0 ), child: IgnorePointer( - child: UserNameText(userid: userInfo.userID,) + child: UserNameText(userid: contactInfo.userInfo.userID,) ), ) ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: contactInfo.status == ContactStatus.added ? null : + contactInfo.status == ContactStatus.pending ? + SizedBox( + width: 24, + height: 24, + child: LoadingIndicator( + indicatorType: Indicator.ballPulse, + colors: [Colors.blue.withOpacity(0.5)], + ), + ) : + TextButton( + onPressed: () async { + context.read().tcpRepository.pushRequest(AddContactRequest( + userid: contactInfo.userInfo.userID, + token: (await SharedPreferences.getInstance()).getInt('token') + )); + }, + child: const Text('Confirm'), + ), + ) ], ), ), diff --git a/lib/profile/cubit/user_profile_cubit.dart b/lib/profile/cubit/user_profile_cubit.dart index 03ab6cc..74891db 100644 --- a/lib/profile/cubit/user_profile_cubit.dart +++ b/lib/profile/cubit/user_profile_cubit.dart @@ -1,7 +1,7 @@ /* * @Author : Linloir * @Date : 2022-10-14 08:54:32 - * @LastEditTime : 2022-10-20 11:30:46 + * @LastEditTime : 2022-10-20 16:45:19 * @Description : */ @@ -28,9 +28,8 @@ class UserProfileCubit extends Cubit { emit(const UserProfileState(status: ContactStatus.none)); return; } - var clonedTCPRepository = await tcpRepository.clone(); - clonedTCPRepository.pushRequest(FetchContactRequest(token: (await SharedPreferences.getInstance()).getInt('token'))); - await for(var response in clonedTCPRepository.responseStreamBroadcast) { + tcpRepository.pushRequest(FetchContactRequest(token: (await SharedPreferences.getInstance()).getInt('token'))); + await for(var response in tcpRepository.responseStreamBroadcast) { if(response.type == TCPResponseType.fetchContact) { response as FetchContactResponse; if(response.addedContacts.any((element) => element.userID == userID)) { @@ -45,7 +44,6 @@ class UserProfileCubit extends Cubit { break; } } - clonedTCPRepository.dispose(); } Future addContact() async {