mirror of
https://github.com/Linloir/Simple-TCP-Client.git
synced 2025-12-18 09:18:11 +08:00
More Codes
- Contacts page (untested)
This commit is contained in:
parent
0f714c2633
commit
43cb79f6ab
@ -1,6 +1,35 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:03:16
|
* @Date : 2022-10-13 14:03:16
|
||||||
* @LastEditTime : 2022-10-13 14:03:16
|
* @LastEditTime : 2022-10-13 16:29:57
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tcp_client/repositories/common_models/userinfo.dart';
|
||||||
|
|
||||||
|
class ChatPage extends StatelessWidget {
|
||||||
|
const ChatPage({
|
||||||
|
required this.userInfo,
|
||||||
|
super.key
|
||||||
|
});
|
||||||
|
|
||||||
|
final UserInfo userInfo;
|
||||||
|
|
||||||
|
static Route<void> route({required UserInfo userInfo}) => MaterialPageRoute<void>(builder: (context) => ChatPage(userInfo: userInfo,));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(
|
||||||
|
userInfo.userName,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:02:28
|
* @Date : 2022-10-13 14:02:28
|
||||||
* @LastEditTime : 2022-10-13 14:02:28
|
* @LastEditTime : 2022-10-13 16:43:49
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:tcp_client/home/cubit/home_state.dart';
|
||||||
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
|
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||||
|
|
||||||
|
class HomeCubit extends Cubit<HomeState> {
|
||||||
|
HomeCubit({
|
||||||
|
required this.localServiceRepository,
|
||||||
|
required this.tcpRepository,
|
||||||
|
}): super(const HomeState(page: HomePagePosition.message));
|
||||||
|
|
||||||
|
final LocalServiceRepository localServiceRepository;
|
||||||
|
final TCPRepository tcpRepository;
|
||||||
|
|
||||||
|
void switchPage(HomePagePosition newPage) {
|
||||||
|
emit(state.copyWith(page: newPage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,38 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:02:24
|
* @Date : 2022-10-13 14:02:24
|
||||||
* @LastEditTime : 2022-10-13 14:02:24
|
* @LastEditTime : 2022-10-13 16:55:05
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
enum HomePagePosition {
|
||||||
|
message(0),
|
||||||
|
contact(1),
|
||||||
|
profile(2);
|
||||||
|
|
||||||
|
const HomePagePosition(int value): _value = value;
|
||||||
|
final int _value;
|
||||||
|
final List<String> _literals = const ['Messages', 'Contacts', 'Me'];
|
||||||
|
int get value => _value;
|
||||||
|
String get literal => _literals[value];
|
||||||
|
|
||||||
|
//Construct the enum type by value
|
||||||
|
factory HomePagePosition.fromValue(int value) {
|
||||||
|
return HomePagePosition.values.firstWhere((element) => element._value == value, orElse: () => HomePagePosition.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HomeState extends Equatable {
|
||||||
|
final HomePagePosition page;
|
||||||
|
|
||||||
|
const HomeState({required this.page});
|
||||||
|
|
||||||
|
HomeState copyWith({HomePagePosition? page}) {
|
||||||
|
return HomeState(page: page ?? this.page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [page];
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,84 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-11 11:05:08
|
* @Date : 2022-10-11 11:05:08
|
||||||
* @LastEditTime : 2022-10-12 11:03:13
|
* @LastEditTime : 2022-10-13 16:55:48
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.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/contact_page.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart';
|
||||||
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart';
|
||||||
|
import 'package:tcp_client/home/view/message_page/mesage_page.dart';
|
||||||
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
|
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||||
|
|
||||||
class HomePage extends StatelessWidget {
|
class HomePage extends StatelessWidget {
|
||||||
const HomePage({super.key});
|
HomePage({
|
||||||
|
required this.localServiceRepository,
|
||||||
|
required this.tcpRepository,
|
||||||
|
super.key
|
||||||
|
});
|
||||||
|
|
||||||
static Route<void> route() => MaterialPageRoute<void>(builder: (context) => const HomePage());
|
final LocalServiceRepository localServiceRepository;
|
||||||
|
final TCPRepository tcpRepository;
|
||||||
|
|
||||||
|
final PageController _controller = PageController();
|
||||||
|
|
||||||
|
static Route<void> route({
|
||||||
|
required LocalServiceRepository localServiceRepository,
|
||||||
|
required TCPRepository tcpRepository
|
||||||
|
}) => MaterialPageRoute<void>(builder: (context) => HomePage(
|
||||||
|
localServiceRepository: localServiceRepository,
|
||||||
|
tcpRepository: tcpRepository,
|
||||||
|
));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Scaffold();
|
return MultiBlocProvider(
|
||||||
|
providers: [
|
||||||
|
BlocProvider<MessageListCubit>(
|
||||||
|
create: (context) => MessageListCubit(
|
||||||
|
localServiceRepository: localServiceRepository,
|
||||||
|
tcpRepository: tcpRepository
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BlocProvider<ContactCubit>(
|
||||||
|
create: (context) => ContactCubit(
|
||||||
|
localServiceRepository: localServiceRepository,
|
||||||
|
tcpRepository: tcpRepository
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BlocProvider<HomeCubit>(
|
||||||
|
create: (context) => HomeCubit(
|
||||||
|
localServiceRepository: localServiceRepository,
|
||||||
|
tcpRepository: tcpRepository
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
child: BlocListener<HomeCubit, HomeState>(
|
||||||
|
listenWhen:(previous, current) => current.page != previous.page,
|
||||||
|
listener: (context, state) {
|
||||||
|
_controller.animateToPage(
|
||||||
|
state.page.value,
|
||||||
|
duration: const Duration(milliseconds: 375),
|
||||||
|
curve: Curves.easeInOutCubicEmphasized
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
body: PageView(
|
||||||
|
controller: _controller,
|
||||||
|
children: const [
|
||||||
|
MessagePage(),
|
||||||
|
ContactPage()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
lib/home/view/bottom_bar.dart
Normal file
6
lib/home/view/bottom_bar.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 16:37:30
|
||||||
|
* @LastEditTime : 2022-10-13 16:37:30
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
@ -1,6 +1,53 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-12 23:36:07
|
* @Date : 2022-10-12 23:36:07
|
||||||
* @LastEditTime : 2022-10-12 23:36:08
|
* @LastEditTime : 2022-10-13 16:10:57
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:azlistview/azlistview.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/cubit/contact_state.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/models/contact_model.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/view/contact_tile.dart';
|
||||||
|
|
||||||
|
class ContactPage extends StatelessWidget {
|
||||||
|
const ContactPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<ContactCubit, ContactState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return AzListView(
|
||||||
|
data: state.indexedData,
|
||||||
|
itemCount: state.contacts.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return ContactTile(
|
||||||
|
userInfo: state.contacts[index],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
susItemBuilder: (context, index) {
|
||||||
|
return Container(
|
||||||
|
height: 40,
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
padding: const EdgeInsets.only(left: 16.0),
|
||||||
|
color: Colors.grey[200],
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
ContactModel(userInfo: state.contacts[index]).getSuspensionTag(),
|
||||||
|
softWrap: false,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.0,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:01:45
|
* @Date : 2022-10-13 14:01:45
|
||||||
* @LastEditTime : 2022-10-13 14:01:46
|
* @LastEditTime : 2022-10-13 14:50:34
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/cubit/contact_state.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/models/tcp_response.dart';
|
||||||
|
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||||
|
|
||||||
|
class ContactCubit extends Cubit<ContactState> {
|
||||||
|
ContactCubit({
|
||||||
|
required this.localServiceRepository,
|
||||||
|
required this.tcpRepository
|
||||||
|
}): super(ContactState.empty()) {
|
||||||
|
tcpRepository.responseStreamBroadcast.listen(_onResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServiceRepository localServiceRepository;
|
||||||
|
TCPRepository tcpRepository;
|
||||||
|
|
||||||
|
void _onResponse(TCPResponse response) {
|
||||||
|
switch(response.type) {
|
||||||
|
case TCPResponseType.fetchContact: {
|
||||||
|
response as FetchContactResponse;
|
||||||
|
emit(ContactState(
|
||||||
|
contacts: response.addedContacts,
|
||||||
|
pending: response.pendingContacts,
|
||||||
|
requesting: response.requestingContacts
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateContacts() async {
|
||||||
|
tcpRepository.pushRequest(FetchContactRequest(token: (await SharedPreferences.getInstance()).getInt('token')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,35 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:01:39
|
* @Date : 2022-10-13 14:01:39
|
||||||
* @LastEditTime : 2022-10-13 14:01:40
|
* @LastEditTime : 2022-10-13 15:51:23
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:azlistview/azlistview.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:tcp_client/home/view/contact_page/models/contact_model.dart';
|
||||||
|
import 'package:tcp_client/repositories/common_models/userinfo.dart';
|
||||||
|
|
||||||
|
class ContactState extends Equatable {
|
||||||
|
final List<UserInfo> contacts;
|
||||||
|
final List<UserInfo> pending;
|
||||||
|
final List<UserInfo> requesting;
|
||||||
|
|
||||||
|
const ContactState({
|
||||||
|
required this.contacts,
|
||||||
|
required this.pending,
|
||||||
|
required this.requesting
|
||||||
|
});
|
||||||
|
|
||||||
|
static ContactState empty() => const ContactState(contacts: [], pending: [], requesting: []);
|
||||||
|
|
||||||
|
List<ISuspensionBean> get indexedData {
|
||||||
|
var indexedList = contacts.map((e) => ContactModel(userInfo: e)).toList();
|
||||||
|
SuspensionUtil.sortListBySuspensionTag(indexedList);
|
||||||
|
SuspensionUtil.setShowSuspensionStatus(indexedList);
|
||||||
|
return indexedList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => contacts;
|
||||||
|
}
|
||||||
|
|||||||
26
lib/home/view/contact_page/models/contact_model.dart
Normal file
26
lib/home/view/contact_page/models/contact_model.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 15:34:08
|
||||||
|
* @LastEditTime : 2022-10-13 15:41:24
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'package:azlistview/azlistview.dart';
|
||||||
|
import 'package:lpinyin/lpinyin.dart';
|
||||||
|
import 'package:tcp_client/repositories/common_models/userinfo.dart';
|
||||||
|
|
||||||
|
class ContactModel extends ISuspensionBean {
|
||||||
|
final UserInfo userInfo;
|
||||||
|
|
||||||
|
ContactModel({required this.userInfo});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getSuspensionTag() {
|
||||||
|
var pinyin = PinyinHelper.getPinyinE(userInfo.userName);
|
||||||
|
var tag = pinyin.substring(0, 1);
|
||||||
|
if(!RegExp('[A-Z]').hasMatch(tag)) {
|
||||||
|
tag = '#';
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,92 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:02:00
|
* @Date : 2022-10-13 14:02:00
|
||||||
* @LastEditTime : 2022-10-13 14:02:00
|
* @LastEditTime : 2022-10-13 16:44:03
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:tcp_client/chat/chat_page.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/message_page/cubit/msg_list_cubit.dart';
|
||||||
|
import 'package:tcp_client/repositories/common_models/userinfo.dart';
|
||||||
|
|
||||||
|
class ContactTile extends StatelessWidget {
|
||||||
|
const ContactTile({
|
||||||
|
required this.userInfo,
|
||||||
|
super.key
|
||||||
|
});
|
||||||
|
|
||||||
|
final UserInfo userInfo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return IntrinsicHeight(
|
||||||
|
child: Stack(
|
||||||
|
fit: StackFit.expand,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(ChatPage.route(userInfo: userInfo));
|
||||||
|
context.read<MessageListCubit>().addEmptyMessageOf(user: userInfo);
|
||||||
|
context.read<HomeCubit>().switchPage(HomePagePosition.message);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
if(userInfo.avatarEncoded != null && userInfo.avatarEncoded!.isEmpty)
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.grey[700]!,
|
||||||
|
width: 1.0
|
||||||
|
)
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
child: OverflowBox(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: FittedBox(
|
||||||
|
fit: BoxFit.fitWidth,
|
||||||
|
child: Image.memory(base64Decode(userInfo.avatarEncoded!)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(userInfo.avatarEncoded == null || userInfo.avatarEncoded!.isEmpty)
|
||||||
|
Container(
|
||||||
|
color: Colors.grey,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.grey[700]!,
|
||||||
|
width: 1.0
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12,),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 12.0
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
userInfo.userName,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18.0
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-12 23:38:31
|
* @Date : 2022-10-12 23:38:31
|
||||||
* @LastEditTime : 2022-10-13 11:14:54
|
* @LastEditTime : 2022-10-13 16:12:53
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -19,13 +19,21 @@ class MessageListCubit extends Cubit<MessageListState> {
|
|||||||
required this.localServiceRepository,
|
required this.localServiceRepository,
|
||||||
required this.tcpRepository
|
required this.tcpRepository
|
||||||
}): super(MessageListState.empty()) {
|
}): super(MessageListState.empty()) {
|
||||||
tcpRepository.responseStreamBroadcast.listen(onResponse);
|
tcpRepository.responseStreamBroadcast.listen(_onResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocalServiceRepository localServiceRepository;
|
final LocalServiceRepository localServiceRepository;
|
||||||
final TCPRepository tcpRepository;
|
final TCPRepository tcpRepository;
|
||||||
|
|
||||||
Future<void> onResponse(TCPResponse response) async {
|
void addEmptyMessageOf({required UserInfo user}) {
|
||||||
|
if(state.messageList.any((element) => element.userInfo.userID == user.userID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var newList = [MessageInfo(userInfo: user)];
|
||||||
|
emit(MessageListState(messageList: newList..addAll(state.messageList)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onResponse(TCPResponse response) async {
|
||||||
switch(response.type) {
|
switch(response.type) {
|
||||||
case TCPResponseType.fetchMessage: {
|
case TCPResponseType.fetchMessage: {
|
||||||
response as FetchMessageResponse;
|
response as FetchMessageResponse;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-11 11:05:18
|
* @Date : 2022-10-11 11:05:18
|
||||||
* @LastEditTime : 2022-10-13 13:58:43
|
* @LastEditTime : 2022-10-13 16:11:24
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -10,39 +10,29 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_state.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list_state.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/view/message_tile.dart';
|
import 'package:tcp_client/home/view/message_page/view/message_tile.dart';
|
||||||
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
|
||||||
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
|
||||||
|
|
||||||
class MessagePage extends StatelessWidget {
|
class MessagePage extends StatelessWidget {
|
||||||
const MessagePage({super.key});
|
const MessagePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider<MessageListCubit>(
|
return BlocBuilder<MessageListCubit, MessageListState>(
|
||||||
create: (context) {
|
builder: (context, state) {
|
||||||
return MessageListCubit(
|
return ListView.separated(
|
||||||
localServiceRepository: context.read<LocalServiceRepository>(),
|
itemBuilder: (context, index) {
|
||||||
tcpRepository: context.read<TCPRepository>()
|
return MessageTile(
|
||||||
|
userInfo: state.messageList[index].userInfo,
|
||||||
|
message: state.messageList[index].message,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) {
|
||||||
|
return const Divider(
|
||||||
|
height: 0.5,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: state.messageList.length
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
child: BlocBuilder<MessageListCubit, MessageListState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return ListView.separated(
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return MessageTile(
|
|
||||||
userInfo: state.messageList[index].userInfo,
|
|
||||||
message: state.messageList[index].message,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (context, index) {
|
|
||||||
return const Divider(
|
|
||||||
height: 0.5,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: state.messageList.length
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 13:17:52
|
* @Date : 2022-10-13 13:17:52
|
||||||
* @LastEditTime : 2022-10-13 14:00:12
|
* @LastEditTime : 2022-10-13 14:57:14
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -64,6 +64,7 @@ class MessageTile extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 12,),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-12 15:06:30
|
* @Date : 2022-10-12 15:06:30
|
||||||
* @LastEditTime : 2022-10-12 23:37:04
|
* @LastEditTime : 2022-10-13 16:46:06
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -54,7 +54,10 @@ class LoginPage extends StatelessWidget {
|
|||||||
const SnackBar(content: Text('Login Successed'))
|
const SnackBar(content: Text('Login Successed'))
|
||||||
);
|
);
|
||||||
Future.delayed(const Duration(seconds: 1)).then((_) {
|
Future.delayed(const Duration(seconds: 1)).then((_) {
|
||||||
Navigator.of(context).pushReplacement(HomePage.route());
|
Navigator.of(context).pushReplacement(HomePage.route(
|
||||||
|
localServiceRepository: localServiceRepository,
|
||||||
|
tcpRepository: tcpRepository
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-10 08:04:53
|
* @Date : 2022-10-10 08:04:53
|
||||||
* @LastEditTime : 2022-10-12 17:55:07
|
* @LastEditTime : 2022-10-13 16:46:33
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -52,7 +52,10 @@ class SplashPage extends StatelessWidget {
|
|||||||
if(state.isDone) {
|
if(state.isDone) {
|
||||||
Future.delayed(const Duration(seconds: 1)).then((_) async {
|
Future.delayed(const Duration(seconds: 1)).then((_) async {
|
||||||
if((await SharedPreferences.getInstance()).getInt('userid') != null) {
|
if((await SharedPreferences.getInstance()).getInt('userid') != null) {
|
||||||
Navigator.of(context).pushReplacement(HomePage.route());
|
Navigator.of(context).pushReplacement(HomePage.route(
|
||||||
|
localServiceRepository: state.localServiceRepository!,
|
||||||
|
tcpRepository: state.tcpRepository!
|
||||||
|
));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Navigator.of(context).pushReplacement(LoginPage.route(
|
Navigator.of(context).pushReplacement(LoginPage.route(
|
||||||
|
|||||||
6
lib/profile/user_profile_page.dart
Normal file
6
lib/profile/user_profile_page.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 17:04:44
|
||||||
|
* @LastEditTime : 2022-10-13 17:04:44
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-12 17:36:38
|
* @Date : 2022-10-12 17:36:38
|
||||||
* @LastEditTime : 2022-10-12 17:50:42
|
* @LastEditTime : 2022-10-13 16:45:44
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
@ -64,7 +64,10 @@ class RegisterPage extends StatelessWidget {
|
|||||||
const SnackBar(content: Text('Register Successed'))
|
const SnackBar(content: Text('Register Successed'))
|
||||||
);
|
);
|
||||||
Future.delayed(const Duration(seconds: 1)).then((_) {
|
Future.delayed(const Duration(seconds: 1)).then((_) {
|
||||||
Navigator.of(context).pushReplacement(HomePage.route());
|
Navigator.of(context).pushReplacement(HomePage.route(
|
||||||
|
localServiceRepository: localServiceRepository,
|
||||||
|
tcpRepository: tcpRepository
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-11 14:30:10
|
* @Date : 2022-10-11 14:30:10
|
||||||
* @LastEditTime : 2022-10-11 15:39:13
|
* @LastEditTime : 2022-10-13 15:38:18
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:tcp_client/repositories/common_models/json_encodable.dart';
|
import 'package:tcp_client/repositories/common_models/json_encodable.dart';
|
||||||
|
|
||||||
class UserInfo extends JSONEncodable {
|
class UserInfo extends JSONEncodable {
|
||||||
@ -25,7 +27,7 @@ class UserInfo extends JSONEncodable {
|
|||||||
required Map<String, Object?> jsonObject
|
required Map<String, Object?> jsonObject
|
||||||
}):
|
}):
|
||||||
_userid = jsonObject['userid'] as int,
|
_userid = jsonObject['userid'] as int,
|
||||||
_username = jsonObject['username'] as String,
|
_username = utf8.decode(base64.decode(jsonObject['username'] as String)),
|
||||||
_avatar = jsonObject['avatar'] as String?;
|
_avatar = jsonObject['avatar'] as String?;
|
||||||
|
|
||||||
int get userID => _userid;
|
int get userID => _userid;
|
||||||
@ -35,7 +37,7 @@ class UserInfo extends JSONEncodable {
|
|||||||
@override
|
@override
|
||||||
Map<String, Object?> get jsonObject => {
|
Map<String, Object?> get jsonObject => {
|
||||||
'userid': _userid,
|
'userid': _userid,
|
||||||
'username': _username,
|
'username': base64.encode(utf8.encode(_username)),
|
||||||
'avatar': _avatar
|
'avatar': _avatar
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
6
lib/search/cubit/search_cubit.dart
Normal file
6
lib/search/cubit/search_cubit.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 17:09:25
|
||||||
|
* @LastEditTime : 2022-10-13 17:09:26
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
6
lib/search/cubit/search_state.dart
Normal file
6
lib/search/cubit/search_state.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 17:08:56
|
||||||
|
* @LastEditTime : 2022-10-13 17:08:57
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
6
lib/search/model/search_key.dart
Normal file
6
lib/search/model/search_key.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 17:09:46
|
||||||
|
* @LastEditTime : 2022-10-13 17:09:46
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
22
lib/search/search_page.dart
Normal file
22
lib/search/search_page.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 17:04:12
|
||||||
|
* @LastEditTime : 2022-10-13 17:08:13
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tcp_client/search/view/search_bar.dart';
|
||||||
|
|
||||||
|
class SearchPage extends StatelessWidget {
|
||||||
|
const SearchPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const SearchBar(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
lib/search/view/search_bar.dart
Normal file
17
lib/search/view/search_bar.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-13 17:06:52
|
||||||
|
* @LastEditTime : 2022-10-13 17:06:53
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SearchBar extends StatelessWidget {
|
||||||
|
const SearchBar({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
35
pubspec.lock
35
pubspec.lock
@ -8,6 +8,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.9.0"
|
version: "2.9.0"
|
||||||
|
azlistview:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: azlistview
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -125,6 +132,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.7"
|
version: "2.0.7"
|
||||||
|
flutter_slidable:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_slidable
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -163,6 +177,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
lpinyin:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: lpinyin
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -284,6 +305,20 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.3"
|
version: "6.0.3"
|
||||||
|
pull_to_refresh:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: pull_to_refresh
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
scrollable_positioned_list:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: scrollable_positioned_list
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -49,6 +49,10 @@ dependencies:
|
|||||||
loading_indicator: ^3.1.0
|
loading_indicator: ^3.1.0
|
||||||
async: ^2.9.0
|
async: ^2.9.0
|
||||||
stream_transform: ^2.0.1
|
stream_transform: ^2.0.1
|
||||||
|
flutter_slidable: ^2.0.0
|
||||||
|
pull_to_refresh: ^2.0.0
|
||||||
|
azlistview: ^2.0.0
|
||||||
|
lpinyin: ^2.0.3
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user