聊天列表优化,适配.

This commit is contained in:
18631081161 2024-07-18 14:57:16 +08:00
parent 0a226a06c8
commit e4bb070d08
11 changed files with 756 additions and 649 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -4,6 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:expandable_text/expandable_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import '../../beans/character_info_bean.dart';
import '../../beans/chat_info_bean.dart';
@ -52,12 +53,15 @@ class _ChatPageState extends State<ChatPage> {
int delIndex = 0;
///
void _scrollToBottom() {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
Future.delayed(Duration(milliseconds: 300), () {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
});
}
@override
@ -77,9 +81,7 @@ class _ChatPageState extends State<ChatPage> {
chatList.addAll(newData['data']);
EasyLoading.dismiss();
setState(() {});
Future.delayed(Duration(milliseconds: 100), () {
_scrollToBottom();
});
_scrollToBottom();
break;
case "sendMessage":
sendMessageBean = newData['data'];
@ -122,6 +124,21 @@ class _ChatPageState extends State<ChatPage> {
}
});
//
final keyboardVisibilityController = KeyboardVisibilityController();
//
keyboardVisibilityController.onChange.listen((bool visible) {
//
if (visible) {
//
print('Keyboard is visible');
_scrollToBottom();
} else {
//
print('Keyboard is hidden');
}
});
loadData();
}
@ -155,7 +172,9 @@ class _ChatPageState extends State<ChatPage> {
children: [
characterInfoBean != null && characterInfoBean?.bgUrl != null
? CachedNetworkImage(
fit: BoxFit.fitHeight,
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
imageUrl: "${characterInfoBean?.bgUrl}",
errorWidget: (context, url, error) => const Icon(Icons.error),
)

View File

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import '../../beans/category_info_list_bean.dart';
import '../chat/chat_page.dart';
import 'find_model.dart';
class MultiplexPage extends StatefulWidget {
@ -51,6 +52,16 @@ class _MultiplexPageState extends State<MultiplexPage> {
super.dispose();
}
goChatPage(String id) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatPage(
characterId: id,
)),
);
}
@override
Widget build(BuildContext context) {
return Container(
@ -64,69 +75,75 @@ class _MultiplexPageState extends State<MultiplexPage> {
}
_item(index, CategoryInfoListBean data) {
return Container(
height: 130,
width: 50,
margin: EdgeInsets.only(bottom: 23),
decoration: BoxDecoration(
color: Color(0xFF202021),
borderRadius: BorderRadius.all(Radius.circular(7)),
border: Border.all(color: Color(0xFF7E7E7E), width: 0.3),
),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 7,
child: CachedNetworkImage(
width: 83,
height: 115,
imageUrl: data.iconImage!,
errorWidget: (context, url, error) => const Icon(Icons.error),
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
goChatPage(data.id.toString());
},
child: Container(
height: 130,
width: 50,
margin: EdgeInsets.only(bottom: 23),
decoration: BoxDecoration(
color: Color(0xFF202021),
borderRadius: BorderRadius.all(Radius.circular(7)),
border: Border.all(color: Color(0xFF7E7E7E), width: 0.3),
),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 7,
child: CachedNetworkImage(
width: 83,
height: 115,
imageUrl: data.iconImage!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
),
Positioned(
left: 101,
top: 19,
child: Text(
'${data.name}',
style: TextStyle(color: Colors.white, fontSize: 14),
)),
Positioned(
left: 101,
top: 45,
child: SizedBox(
width: 200,
height: 16,
child: ListView.builder(
itemCount: data.label?.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 11),
margin: EdgeInsets.only(right: 5),
decoration: BoxDecoration(border: Border.all(color: Color(0xFFFF9000)), borderRadius: BorderRadius.all(Radius.circular(7))),
child: Text(
'${data.label?[index].name}',
style: TextStyle(fontSize: 10, color: Color(0xFFFF9000)),
),
);
}),
)),
Positioned(
left: 102,
top: 70,
child: Container(
width: 200,
Positioned(
left: 101,
top: 19,
child: Text(
maxLines: 3,
'${data.biography}',
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.white, fontSize: 10),
),
))
],
'${data.name}',
style: TextStyle(color: Colors.white, fontSize: 14),
)),
Positioned(
left: 101,
top: 45,
child: SizedBox(
width: 200,
height: 16,
child: ListView.builder(
itemCount: data.label?.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 11),
margin: EdgeInsets.only(right: 5),
decoration: BoxDecoration(border: Border.all(color: Color(0xFFFF9000)), borderRadius: BorderRadius.all(Radius.circular(7))),
child: Text(
'${data.label?[index].name}',
style: TextStyle(fontSize: 10, color: Color(0xFFFF9000)),
),
);
}),
)),
Positioned(
left: 102,
top: 70,
child: Container(
width: 200,
child: Text(
maxLines: 3,
'${data.biography}',
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.white, fontSize: 10),
),
))
],
),
),
);
}

View File

@ -8,6 +8,7 @@ import 'package:flutter_easyloading/flutter_easyloading.dart';
import '../../beans/find_banner_bean.dart';
import '../../beans/recommend_bean.dart';
import '../../custom/custom_swiper_pagination.dart';
import '../chat/chat_page.dart';
import 'find_model.dart';
///
@ -18,7 +19,7 @@ class RecommendPage extends StatefulWidget {
State<RecommendPage> createState() => _RecommendPageState();
}
class _RecommendPageState extends State<RecommendPage> {
class _RecommendPageState extends State<RecommendPage> with AutomaticKeepAliveClientMixin {
late StreamSubscription subscription;
final FindModel _viewmodel = FindModel();
@ -74,6 +75,16 @@ class _RecommendPageState extends State<RecommendPage> {
super.dispose();
}
goChatPage(String id) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatPage(
characterId: id,
)),
);
}
@override
Widget build(BuildContext context) {
return Stack(
@ -92,10 +103,15 @@ class _RecommendPageState extends State<RecommendPage> {
return Container(
key: ValueKey<int>(index),
padding: EdgeInsets.only(bottom: 30),
child: CachedNetworkImage(
fit: BoxFit.fill,
imageUrl: bannerList[index].imageUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
child: GestureDetector(
onTap: () {
goChatPage(bannerList[index].actionId.toString());
},
child: CachedNetworkImage(
fit: BoxFit.fill,
imageUrl: bannerList[index].imageUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
);
},
@ -115,19 +131,35 @@ class _RecommendPageState extends State<RecommendPage> {
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
Container(
margin: EdgeInsets.only(top: 21),
height: 360,
child: ListView.builder(
itemCount: recommendList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return _item(index, recommendList[index]);
}),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
// width: 500,
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(top: 21),
padding: EdgeInsets.only(left: 16),
height: 330,
child: GridView.count(
shrinkWrap: true,
//Widget之间间距
crossAxisSpacing: 12.0,
//Widget之间间距
mainAxisSpacing: 9.0,
//GridView内边距
padding: EdgeInsets.zero,
//Widget数量
crossAxisCount: 2,
//Widget宽高比例
childAspectRatio: 1.4,
//Widget列表
children: _item(recommendList),
physics: NeverScrollableScrollPhysics(),
// cellForRow
scrollDirection: Axis.horizontal)),
),
Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 16),
margin: EdgeInsets.only(left: 16, top: 34),
child: Text(
'热门小说角色',
style: TextStyle(color: Colors.white, fontSize: 16),
@ -150,48 +182,17 @@ class _RecommendPageState extends State<RecommendPage> {
],
);
}
}
_item(int index, RecommendBean data) {
return Container(
margin: EdgeInsets.only(right: 9, left: index == 0 ? 16 : 0),
child: Column(
children: [
Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: CachedNetworkImage(
width: 113,
height: 159,
fit: BoxFit.fill,
imageUrl: data.imageUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
Positioned(
left: 7,
bottom: 21,
child: Text(
'${data.name}',
style: TextStyle(color: Colors.white, fontSize: 12),
)),
Positioned(
left: 7,
bottom: 9,
child: Container(
width: 105,
child: Text(
'${data.biography}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Color(0xFFC2C2C2), fontSize: 9),
),
)),
],
),
Container(
margin: EdgeInsets.only(top: 12),
_item(List<RecommendBean> list) {
return list.map((res) {
int index = recommendList.indexOf(res);
return GestureDetector(
onTap: () {
goChatPage(res.id.toString());
},
child: Container(
alignment: Alignment.center,
// margin: EdgeInsets.only(right: 9, left: 16),
child: Stack(
children: [
ClipRRect(
@ -200,7 +201,7 @@ _item(int index, RecommendBean data) {
width: 113,
height: 159,
fit: BoxFit.fill,
imageUrl: data.imageUrl!,
imageUrl: res.imageUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
@ -208,7 +209,7 @@ _item(int index, RecommendBean data) {
left: 7,
bottom: 21,
child: Text(
'${data.name}',
'${res.name}',
style: TextStyle(color: Colors.white, fontSize: 12),
)),
Positioned(
@ -217,7 +218,7 @@ _item(int index, RecommendBean data) {
child: Container(
width: 105,
child: Text(
'${data.biography}',
'${res.biography}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Color(0xFFC2C2C2), fontSize: 9),
@ -225,80 +226,90 @@ _item(int index, RecommendBean data) {
)),
],
),
)
],
),
);
}
_item2(index, RecommendBean data) {
return Container(
height: 130,
width: 50,
margin: EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
color: Color(0xFF202021),
borderRadius: BorderRadius.all(Radius.circular(7)),
border: Border.all(color: Color(0xFF7E7E7E), width: 0.3),
),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 7,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: CachedNetworkImage(
width: 83,
height: 115,
fit: BoxFit.fill,
imageUrl: data.imageUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
),
Positioned(
left: 101,
top: 19,
child: Text(
'${data.name}',
style: TextStyle(color: Colors.white, fontSize: 14),
)),
Positioned(
left: 101,
top: 45,
child: SizedBox(
width: 200,
height: 16,
child: ListView.builder(
itemCount: data.label?.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 11),
margin: EdgeInsets.only(right: 5),
decoration: BoxDecoration(border: Border.all(color: Color(0xFFFF9000)), borderRadius: BorderRadius.all(Radius.circular(7))),
child: Text(
'${data.label?[index].name}',
style: TextStyle(fontSize: 10, color: Color(0xFFFF9000)),
),
);
}),
)),
Positioned(
left: 102,
top: 70,
child: Container(
width: 200,
child: Text(
maxLines: 3,
'${data.biography}',
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.white, fontSize: 10),
);
}).toList();
}
_item2(index, RecommendBean data) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
goChatPage(data.id.toString());
},
child: Container(
height: 130,
width: 50,
margin: EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
color: Color(0xFF202021),
borderRadius: BorderRadius.all(Radius.circular(7)),
border: Border.all(color: Color(0xFF7E7E7E), width: 0.3),
),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 7,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: CachedNetworkImage(
width: 83,
height: 115,
fit: BoxFit.fill,
imageUrl: data.imageUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
))
],
),
);
),
Positioned(
left: 101,
top: 19,
child: Text(
'${data.name}',
style: TextStyle(color: Colors.white, fontSize: 14),
)),
Positioned(
left: 101,
top: 45,
child: SizedBox(
width: 200,
height: 16,
child: ListView.builder(
itemCount: data.label?.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 11),
margin: EdgeInsets.only(right: 5),
decoration: BoxDecoration(border: Border.all(color: Color(0xFFFF9000)), borderRadius: BorderRadius.all(Radius.circular(7))),
child: Text(
'${data.label?[index].name}',
style: TextStyle(fontSize: 10, color: Color(0xFFFF9000)),
),
);
}),
)),
Positioned(
left: 102,
top: 70,
child: Container(
width: 200,
child: Text(
maxLines: 3,
'${data.biography}',
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.white, fontSize: 10),
),
))
],
),
),
);
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

View File

@ -4,10 +4,12 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:expandable_text/expandable_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import '../../beans/character_info_bean.dart';
import '../../beans/chat_info_bean.dart';
import '../../beans/send_message_bean.dart';
import '../../network/NetworkConfig.dart';
import '../chat/chat_info_page.dart';
import '../chat/chat_model.dart';
@ -20,7 +22,7 @@ class HomeChatPage extends StatefulWidget {
State<HomeChatPage> createState() => _HomeChatPageState();
}
class _HomeChatPageState extends State<HomeChatPage> with AutomaticKeepAliveClientMixin {
class _HomeChatPageState extends State<HomeChatPage> with AutomaticKeepAliveClientMixin, WidgetsBindingObserver {
final ScrollController _scrollController = ScrollController();
final TextEditingController _chatController = TextEditingController();
@ -69,9 +71,7 @@ class _HomeChatPageState extends State<HomeChatPage> with AutomaticKeepAliveClie
case "getChatInfo":
chatList.addAll(newData['data']);
setState(() {});
Future.delayed(Duration(milliseconds: 100), () {
_scrollToBottom();
});
_scrollToBottom();
EasyLoading.dismiss();
break;
case "sendMessage":
@ -115,6 +115,21 @@ class _HomeChatPageState extends State<HomeChatPage> with AutomaticKeepAliveClie
}
});
//
final keyboardVisibilityController = KeyboardVisibilityController();
//
keyboardVisibilityController.onChange.listen((bool visible) {
//
if (visible) {
//
print('Keyboard is visible');
_scrollToBottom();
} else {
//
print('Keyboard is hidden');
}
});
loadData();
}
@ -131,12 +146,15 @@ class _HomeChatPageState extends State<HomeChatPage> with AutomaticKeepAliveClie
_viewmodel.delChatByIds(ids, widget.characterId);
}
///
void _scrollToBottom() {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
Future.delayed(Duration(milliseconds: 300), () {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
});
}
@override
@ -151,339 +169,364 @@ class _HomeChatPageState extends State<HomeChatPage> with AutomaticKeepAliveClie
@override
Widget build(BuildContext context) {
super.build(context);
return Stack(
children: [
CachedNetworkImage(
fit: BoxFit.fitHeight,
imageUrl: characterInfoBean.bgUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
Positioned(
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
height: 311.67,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0x00000000), Color(0xFF0C0909)], //
begin: Alignment.topCenter, //
end: Alignment.bottomCenter, //
return Scaffold(
backgroundColor: Color(0xFF121213),
body: Stack(
children: [
CachedNetworkImage(
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
imageUrl: characterInfoBean.bgUrl!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
Positioned(
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
height: 311.67,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0x00000000), Color(0xFF0C0909)], //
begin: Alignment.topCenter, //
end: Alignment.bottomCenter, //
),
),
),
)),
Container(
child: Column(
children: [
///title
Container(
width: double.infinity,
height: 30,
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 9, left: 16, right: 16),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
top: 0,
left: 105,
child: Text(
"+1",
style: TextStyle(color: Color(0xFFF14476), fontSize: 10),
)),
Positioned(
left: 0,
child: Container(
width: 101,
height: 30,
decoration: BoxDecoration(color: Color(0x33000000), borderRadius: BorderRadius.all(Radius.circular(14))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
///AI头像
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatInfoPage(
data: characterInfoBean,
)),
);
},
child: Container(
margin: EdgeInsets.only(left: 2),
child: CachedNetworkImage(
width: 23,
imageUrl: characterInfoBean.icon!,
errorWidget: (context, url, error) => const Icon(Icons.error),
)),
Container(
child: Column(
children: [
///title
Container(
width: double.infinity,
height: 30,
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 9, left: 16, right: 16),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
top: 0,
left: 105,
child: Text(
"+1",
style: TextStyle(color: Color(0xFFF14476), fontSize: 10),
)),
Positioned(
left: 0,
child: Container(
width: 101,
height: 30,
decoration: BoxDecoration(color: Color(0x33000000), borderRadius: BorderRadius.all(Radius.circular(14))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
///AI头像
GestureDetector(
onTap: () {
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatInfoPage(
data: characterInfoBean,
)),
);
},
child: Container(
margin: EdgeInsets.only(left: 2),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: CachedNetworkImage(
width: 23,
height: 23,
imageUrl: characterInfoBean.icon!,
errorWidget: (context, url, error) => const Icon(Icons.error),
),
),
),
),
),
///AI名
Container(
margin: EdgeInsets.only(left: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 35,
child: Text(
characterInfoBean.characterName!,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 10, color: Colors.white),
),
),
Text(
'${characterInfoBean.lookCount} 聊过',
style: TextStyle(fontSize: 7, color: Colors.white),
),
],
),
),
///
Container(
margin: EdgeInsets.only(left: 6, right: 6),
child: GestureDetector(
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => ChatPage(
// characterId: characterInfoBean.characterId.toString(),
// )),
// );
},
child: Stack(
alignment: Alignment.center,
///AI名
Container(
margin: EdgeInsets.only(left: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Image(
width: 24,
height: 21,
image: AssetImage('assets/images/ic_beckoning.png'),
SizedBox(
width: 35,
child: Text(
characterInfoBean.characterName!,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 10, color: Colors.white),
),
),
Text(
characterInfoBean.intimacy.toString(),
style: TextStyle(fontSize: 8, color: Colors.white),
)
'${characterInfoBean.lookCount} 聊过',
style: TextStyle(fontSize: 7, color: Colors.white),
),
],
),
),
),
],
),
),
),
///
Positioned(
right: 0,
child: GestureDetector(
onTap: () {
isHalf = !isHalf;
setState(() {});
},
child: Container(
width: 50,
height: 24,
alignment: Alignment.center,
decoration: BoxDecoration(color: Color(0x33000000), borderRadius: BorderRadius.all(Radius.circular(12))),
child: Text(
'+ 关注',
style: TextStyle(fontSize: 12, color: Colors.white),
///
Container(
margin: EdgeInsets.only(left: 6, right: 6),
child: GestureDetector(
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => ChatPage(
// characterId: characterInfoBean.characterId.toString(),
// )),
// );
},
child: Stack(
alignment: Alignment.center,
children: [
Image(
width: 24,
height: 21,
image: AssetImage('assets/images/ic_beckoning.png'),
),
Text(
characterInfoBean.intimacy.toString(),
style: TextStyle(fontSize: 8, color: Colors.white),
)
],
),
),
),
],
),
),
),
),
],
),
),
isHalf
? Container(
height: MediaQuery.of(context).size.height / 3.5,
)
: Container(),
///
Expanded(
child: ListView.builder(
controller: _scrollController,
itemCount: chatList.length,
itemBuilder: (BuildContext context, int index) {
return _item(index);
})),
Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 16, bottom: 3),
child: Image(width: 63, height: 18, image: AssetImage('assets/images/ic_memory.png')),
),
///
Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.only(left: 16, right: 16, bottom: !isMore ? 60 : 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
///
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 5),
decoration: const BoxDecoration(
color: Color(0x33FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(20)),
///
Positioned(
right: 0,
child: GestureDetector(
onTap: () {
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
isHalf = !isHalf;
setState(() {});
},
child: Container(
width: 50,
height: 24,
alignment: Alignment.center,
decoration: BoxDecoration(color: Color(0x33000000), borderRadius: BorderRadius.all(Radius.circular(12))),
child: Text(
'+ 关注',
style: TextStyle(fontSize: 12, color: Colors.white),
),
),
),
),
child: Row(
children: [
Expanded(
child: Container(
padding: const EdgeInsets.only(left: 15),
child: TextField(
controller: _chatController,
onChanged: _textFieldChanged,
maxLines: null,
cursorColor: const Color(0xFFFF9000),
decoration: const InputDecoration(
border: InputBorder.none,
//
enabledBorder: InputBorder.none,
//
focusedBorder: InputBorder.none,
isCollapsed: true,
//
hintText: "打个招呼吧...",
hintStyle: TextStyle(color: Color(0xFFB6B6B6), fontSize: 13),
],
),
),
isHalf
? Container(
height: MediaQuery.of(context).size.height / 3.5,
)
: Container(),
///
Expanded(
child: ListView.builder(
controller: _scrollController,
itemCount: chatList.length,
itemBuilder: (BuildContext context, int index) {
return _item(index);
})),
Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 16, bottom: 3),
child: Image(width: 63, height: 18, image: AssetImage('assets/images/ic_memory.png')),
),
///
Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.only(left: 16, right: 16, bottom: !isMore ? 60 : 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
///
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 5),
decoration: const BoxDecoration(
color: Color(0x33FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Row(
children: [
Expanded(
child: Container(
padding: const EdgeInsets.only(left: 15),
child: TextField(
controller: _chatController,
onChanged: _textFieldChanged,
maxLines: null,
cursorColor: const Color(0xFFFF9000),
decoration: const InputDecoration(
border: InputBorder.none,
//
enabledBorder: InputBorder.none,
//
focusedBorder: InputBorder.none,
isCollapsed: true,
//
hintText: "打个招呼吧...",
hintStyle: TextStyle(color: Color(0xFFB6B6B6), fontSize: 13),
),
style: const TextStyle(color: Colors.white),
),
style: const TextStyle(color: Colors.white),
),
),
),
///
Container(
margin: const EdgeInsets.only(right: 7),
child: text == ""
? const Image(
width: 27,
image: AssetImage('assets/images/ic_send_n.png'),
)
: GestureDetector(
onTap: () {
EasyLoading.show(status: 'loading...');
chatList.add(ChatInfoBean(0, "user", text, "timestamp", "claudeType", 0, "userIcon"));
_viewmodel.sendMessage(widget.characterId, text);
_chatController.clear();
text = "";
Future.delayed(Duration(milliseconds: 200), () {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
setState(() {});
},
child: Image(
///
Container(
margin: const EdgeInsets.only(right: 7),
child: text == ""
? const Image(
width: 27,
image: AssetImage('assets/images/ic_send.png'),
image: AssetImage('assets/images/ic_send_n.png'),
)
: GestureDetector(
onTap: () {
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
EasyLoading.show(status: 'loading...');
chatList.add(ChatInfoBean(0, "user", text, "timestamp", "claudeType", 0, "userIcon"));
_viewmodel.sendMessage(widget.characterId, text);
_chatController.clear();
text = "";
Future.delayed(Duration(milliseconds: 200), () {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
setState(() {});
},
child: Image(
width: 27,
image: AssetImage('assets/images/ic_send.png'),
),
),
),
)
],
),
)),
)
],
),
)),
///
Container(
margin: const EdgeInsets.only(left: 14, right: 14),
child: GestureDetector(
///
Container(
margin: const EdgeInsets.only(left: 14, right: 14),
child: GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/LoginPage');
},
child: Image(
width: 27,
image: AssetImage('assets/images/ic_smart_chat.png'),
),
),
),
///
GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/LoginPage');
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
isMore = !isMore;
setState(() {});
},
child: Image(
width: 27,
image: AssetImage('assets/images/ic_smart_chat.png'),
image: AssetImage('assets/images/ic_more.png'),
),
),
),
///
GestureDetector(
onTap: () {
isMore = !isMore;
setState(() {});
},
child: Image(
width: 27,
image: AssetImage('assets/images/ic_more.png'),
),
),
],
],
),
),
),
isMore
? Container(
height: 70,
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 16, right: 16, bottom: 60),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(left: 23),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image(width: 26, image: AssetImage('assets/images/ic_album.png')),
Container(
margin: EdgeInsets.only(top: 9),
child: Text(
'角色相册',
style: TextStyle(fontSize: 10, color: Color(0xFFA2A2A2)),
),
),
],
),
),
Container(
margin: EdgeInsets.only(left: 23),
child: GestureDetector(
onTap: () {
EasyLoading.show(status: 'loading...');
_viewmodel.delChat(widget.characterId);
},
isMore
? Container(
height: 70,
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 16, right: 16, bottom: 60),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(left: 23),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image(width: 26, height: 26, image: AssetImage('assets/images/ic_restart.png')),
Image(width: 26, image: AssetImage('assets/images/ic_album.png')),
Container(
margin: EdgeInsets.only(top: 9),
child: Text(
'重启对话',
'角色相册',
style: TextStyle(fontSize: 10, color: Color(0xFFA2A2A2)),
),
),
],
),
),
),
],
),
)
: Container(),
],
Container(
margin: EdgeInsets.only(left: 23),
child: GestureDetector(
onTap: () {
EasyLoading.show(status: 'loading...');
_viewmodel.delChat(widget.characterId);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image(width: 26, height: 26, image: AssetImage('assets/images/ic_restart.png')),
Container(
margin: EdgeInsets.only(top: 9),
child: Text(
'重启对话',
style: TextStyle(fontSize: 10, color: Color(0xFFA2A2A2)),
),
),
],
),
),
),
],
),
)
: Container(),
],
),
),
),
///
Positioned(
top: 65,
left: 16,
child: Image(
width: 47,
height: 12,
image: AssetImage('assets/images/ic_memory_p.png'),
)),
],
///
Positioned(
top: (MediaQuery.of(context).padding.top) * 2 + 10,
left: 16,
child: Image(
width: 47,
height: 12,
image: AssetImage('assets/images/ic_memory_p.png'),
)),
],
),
);
}

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:talk/network/NetworkConfig.dart';
import 'package:talk/tools/home/my_home_page.dart';
import 'package:talk/tools/me/me_page.dart';
import 'package:talk/tools/message/message_page.dart';
@ -74,6 +75,11 @@ class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin
),
GestureDetector(
onTap: () {
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
currentIndex = 1;
_tabController.animateTo(1);
setState(() {});
@ -89,6 +95,10 @@ class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin
),
GestureDetector(
onTap: () {
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
currentIndex = 2;
_tabController.animateTo(2);
setState(() {});
@ -100,6 +110,10 @@ class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin
),
GestureDetector(
onTap: () {
if (NetworkConfig.userId == "") {
Navigator.of(context).pushNamed('/LoginPage');
return;
}
currentIndex = 3;
_tabController.animateTo(3);
setState(() {});

View File

@ -105,168 +105,169 @@ class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
Image(fit: BoxFit.fill, image: AssetImage('assets/images/login_bj.png')),
Positioned(
left: 22,
top: 28,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Image(
height: 23,
image: AssetImage('assets/images/ic_left_arrow.png'),
),
)),
Positioned(
left: 36,
top: 76,
child: Text(
'妙语',
style: TextStyle(color: Colors.white, fontSize: 33),
)),
Positioned(
left: 36,
top: 115,
child: Text(
'登陆 / 注册',
style: TextStyle(color: Color(0xFFD5D5D5), fontSize: 18),
)),
Positioned(
bottom: 35,
child: Container(
width: MediaQuery.of(context).size.width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
isCheck = !isCheck;
setState(() {});
},
child: Image(width: 16, image: isCheck ? AssetImage('assets/images/ic_ck_s.png') : AssetImage('assets/images/ic_ck.png')),
),
Container(
margin: EdgeInsets.only(left: 10),
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(text: '我已阅读并同意', style: TextStyle(fontSize: 12, color: Color(0xFF5F5F5F))),
TextSpan(text: '用户协议', style: TextStyle(fontSize: 12, color: Color(0xFFFF9000))),
TextSpan(text: '', style: TextStyle(fontSize: 12, color: Color(0xFF5F5F5F))),
TextSpan(text: '隐私协议', style: TextStyle(fontSize: 12, color: Color(0xFFFF9000))),
]),
body: SingleChildScrollView(
child: Stack(
alignment: Alignment.center,
children: [
Image(fit: BoxFit.cover, height: MediaQuery.of(context).size.height, image: AssetImage('assets/images/login_bj.png')),
Positioned(
left: 22,
top: MediaQuery.of(context).padding.top + 9,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Image(
height: 23,
image: AssetImage('assets/images/ic_left_arrow.png'),
),
)),
Positioned(
left: 36,
top: 76,
child: Text(
'妙语',
style: TextStyle(color: Colors.white, fontSize: 33),
)),
Positioned(
left: 36,
top: 115,
child: Text(
'登陆 / 注册',
style: TextStyle(color: Color(0xFFD5D5D5), fontSize: 18),
)),
Positioned(
bottom: 35,
child: Container(
width: MediaQuery.of(context).size.width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
isCheck = !isCheck;
setState(() {});
},
child: Image(width: 16, image: isCheck ? AssetImage('assets/images/ic_ck_s.png') : AssetImage('assets/images/ic_ck.png')),
),
)
],
),
)),
Positioned(
bottom: 70,
child: GestureDetector(
onTap: () {
if (phoneText != "" && codeText != "") {
if (isCheck) {
EasyLoading.showToast("登录");
_viewmodel.login(phoneText, codeText, 0,
"eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJOaWNrTmFtZSI6IuaWsOeUqOaItyIsIlVzZXJJZCI6IjMiLCJleHAiOjE3MjEyMjQzNjksImlzcyI6Ikh1YW5NZW5nIiwiYXVkIjoiSHVhbk1lbmdBcHAifQ.gxf2y47qWuNtEf2xvGSG6ATEgaXOrTWbJpi_Bp6eU2k");
} else {
EasyLoading.showToast("请选中协议");
Container(
margin: EdgeInsets.only(left: 10),
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(text: '我已阅读并同意', style: TextStyle(fontSize: 12, color: Color(0xFF5F5F5F))),
TextSpan(text: '用户协议', style: TextStyle(fontSize: 12, color: Color(0xFFFF9000))),
TextSpan(text: '', style: TextStyle(fontSize: 12, color: Color(0xFF5F5F5F))),
TextSpan(text: '隐私协议', style: TextStyle(fontSize: 12, color: Color(0xFFFF9000))),
]),
),
)
],
),
)),
Positioned(
bottom: 70,
child: GestureDetector(
onTap: () {
if (phoneText != "" && codeText != "") {
if (isCheck) {
EasyLoading.showToast("登录");
_viewmodel.login(phoneText, codeText, 1, "");
} else {
EasyLoading.showToast("请选中协议");
}
}
}
},
},
child: Container(
height: 43,
width: 288,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(phoneText != "" && codeText != "" ? 0xFFFF9000 : 0xFFAC6D1C),
borderRadius: BorderRadius.all(Radius.circular(7)),
),
child: Text(
'登录',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
),
),
)),
Positioned(
bottom: 125,
child: Container(
height: 43,
width: 288,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(phoneText != "" && codeText != "" ? 0xFFFF9000 : 0xFFAC6D1C),
color: Color(0x33FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(7)),
),
child: Text(
'登录',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
),
),
)),
Positioned(
bottom: 125,
child: Container(
height: 43,
width: 288,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(0x33FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(7)),
),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 17, bottom: 6),
child: TextField(
controller: _codeController,
onChanged: _codeChanged,
cursorColor: Color(0xFFFF9000),
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hintText: "请输入验证码",
hintStyle: TextStyle(color: Color(0xFFB5B5B5), fontSize: 15),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 17, bottom: 6),
child: TextField(
controller: _codeController,
onChanged: _codeChanged,
cursorColor: Color(0xFFFF9000),
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hintText: "请输入验证码",
hintStyle: TextStyle(color: Color(0xFFB5B5B5), fontSize: 15),
),
style: TextStyle(color: Colors.white),
),
style: TextStyle(color: Colors.white),
),
),
),
GestureDetector(
onTap: () {
if (!_isCountingDown) {
getCode();
}
},
child: Container(
margin: EdgeInsets.only(right: 14),
child: Text(
!_isCountingDown ? "获取验证码" : "$_timeLeft后重新获取",
style: TextStyle(fontSize: 15, color: Color(0xFFB5B5B5)),
GestureDetector(
onTap: () {
if (!_isCountingDown) {
getCode();
}
},
child: Container(
margin: EdgeInsets.only(right: 14),
child: Text(
!_isCountingDown ? "获取验证码" : "$_timeLeft后重新获取",
style: TextStyle(fontSize: 15, color: Color(0xFFB5B5B5)),
),
),
),
),
],
),
)),
Positioned(
bottom: 178,
child: Container(
height: 43,
width: 288,
alignment: Alignment.center,
padding: EdgeInsets.only(left: 17, bottom: 6),
decoration: BoxDecoration(
color: Color(0x33FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(7)),
),
child: TextField(
controller: _phoneController,
onChanged: _phoneChanged,
cursorColor: Color(0xFFFF9000),
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hintText: "请输入手机号",
hintStyle: TextStyle(color: Color(0xFFB5B5B5), fontSize: 15),
],
),
style: TextStyle(color: Colors.white),
),
)),
],
)),
Positioned(
bottom: 178,
child: Container(
height: 43,
width: 288,
alignment: Alignment.center,
padding: EdgeInsets.only(left: 17, bottom: 6),
decoration: BoxDecoration(
color: Color(0x33FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(7)),
),
child: TextField(
controller: _phoneController,
onChanged: _phoneChanged,
cursorColor: Color(0xFFFF9000),
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hintText: "请输入手机号",
hintStyle: TextStyle(color: Color(0xFFB5B5B5), fontSize: 15),
),
style: TextStyle(color: Colors.white),
),
)),
],
),
),
);
}

View File

@ -61,9 +61,10 @@ class _StartPageState extends State<StartPage> {
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
fit: BoxFit.cover,
image: AssetImage('assets/images/img_start.png'),
),
);

View File

@ -46,6 +46,7 @@ dependencies:
expandable_text: ^2.3.0
card_swiper: ^3.0.1
flutter_slidable: ^3.1.0
flutter_keyboard_visibility: ^6.0.0
dev_dependencies:
flutter_test: