- Show pending contacts and requesting contacts in contact list
This commit is contained in:
Linloir 2022-10-20 17:14:16 +08:00
parent f9907c16fe
commit 5aa69d80f6
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
9 changed files with 85 additions and 32 deletions

View File

@ -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(

View File

@ -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<AvatarState> {
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!))
));
}
}
}

View File

@ -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<Object?> get props => [userInfo.userID, userInfo.avatarEncoded];
List<Object?> get props => [userInfo.userID, userInfo.avatarEncoded, preCachedAvatar];
}

View File

@ -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,

View File

@ -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<ContactState> {
}): 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;

View File

@ -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<ISuspensionBean> 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<Object> get props => contacts;
List<Object> get props => [...contacts, ...pending, ...requesting];
}

View File

@ -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)) {

View File

@ -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<UserRepository>(),
localServiceRepository: context.read<LocalServiceRepository>(),
tcpRepository: context.read<TCPRepository>(),
userID: userInfo.userID
userID: contactInfo.userInfo.userID
));
context.read<MessageListCubit>().addEmptyMessageOf(targetUser: userInfo.userID);
context.read<MessageListCubit>().addEmptyMessageOf(targetUser: contactInfo.userInfo.userID);
context.read<HomeCubit>().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<ContactCubit>().tcpRepository.pushRequest(AddContactRequest(
userid: contactInfo.userInfo.userID,
token: (await SharedPreferences.getInstance()).getInt('token')
));
},
child: const Text('Confirm'),
),
)
],
),
),

View File

@ -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<UserProfileState> {
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<UserProfileState> {
break;
}
}
clonedTCPRepository.dispose();
}
Future<void> addContact() async {