diff --git a/lib/views/social.dart b/lib/views/social.dart index 19070af..f5cddff 100644 --- a/lib/views/social.dart +++ b/lib/views/social.dart @@ -1,4 +1,6 @@ +import 'package:environmental_protection/common/user_information.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; class SocialPage extends StatefulWidget { const SocialPage({super.key}); @@ -8,49 +10,34 @@ class SocialPage extends StatefulWidget { } class _SocialPageState extends State { - final List> posts = [ - { - "user": "邻居A", - "likes": 360, - }, - { - "user": "邻居B", - "likes": 280, - }, - { - "user": "邻居C", - "likes": 420, - }, - { - "user": "邻居D", - "likes": 150, - }, - { - "user": "邻居D", - "likes": 150, - }, - { - "user": "邻居D", - "likes": 150, - }, - { - "user": "邻居D", - "likes": 150, - }, - { - "user": "邻居D", - "likes": 150, - }, - { - "user": "邻居D", - "likes": 150, - }, + List> posts = []; - ]; + @override + void initState() { + super.initState(); + _fetchPosts(); + } + + Future _fetchPosts() async { + var global = GlobalInformation.getInstance(); + final response = await global.requester.get(resolve('api/post/list')); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + setState(() { + posts = List>.from(data['rows']); + }); + } else { + throw Exception('Failed to load posts'); + } + } @override Widget build(BuildContext context) { return Scaffold( + appBar: AppBar( + title: const Text("友邻社交"), + ), body: GridView.builder( padding: const EdgeInsets.all(10.0), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( @@ -67,7 +54,7 @@ class _SocialPageState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => PostDetailPage(post: post), + builder: (context) => PostDetailPage(postId: post['id']), ), ); }, @@ -75,33 +62,26 @@ class _SocialPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Placeholder( - fallbackHeight: 150, - color: Colors.grey, + Image.network( + resolve(post['cover']).toString(), + fit: BoxFit.cover, + height: 150, + width: double.infinity, + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text(post['nickName'] ?? "未知用户", style: const TextStyle(fontSize: 16)), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + children: [ + const Icon(Icons.favorite, color: Colors.red, size: 16), + const SizedBox(width: 5), + Text(post['likeNum'].toString()), + ], + ), ), - Row( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Text(post['user'], style: const TextStyle(fontSize: 16)), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - const Icon(Icons.favorite, color: Colors.grey, size: 10,), - const SizedBox(width: 5), - Text(post['likes'].toString()), - ], - ), - ], - ), - ), - ], - ) ], ), ), @@ -109,117 +89,204 @@ class _SocialPageState extends State { }, ), floatingActionButton: FloatingActionButton( - onPressed: () {}, + heroTag: 'uniqueTag', + onPressed: () { + // 添加发布帖子的功能 + }, child: const Icon(Icons.add), ), ); } } -// 社交帖详情页面 -class PostDetailPage extends StatelessWidget { - final Map post; +class PostDetailPage extends StatefulWidget { + final int postId; - PostDetailPage({super.key, required this.post}); + const PostDetailPage({super.key, required this.postId}); - // 假数据,用户评论 - final List> comments = [ - { - "username": "用户1", - "date": "2024-08-24", - "content": "这是一个很有趣的帖子!", - "likes": 120, - }, - { - "username": "用户2", - "date": "2024-08-23", - "content": "我很喜欢这个内容。", - "likes": 89, - }, - { - "username": "用户3", - "date": "2024-08-22", - "content": "赞同楼上的看法。", - "likes": 45, - }, - ]; + @override + State createState() => _PostDetailPageState(); +} + +class _PostDetailPageState extends State { + Map? post; + List> comments = []; + int pageNum = 1; + final int pageSize = 10; + bool isLoading = false; + bool hasMore = true; + final TextEditingController _commentController = TextEditingController(); + + @override + void initState() { + super.initState(); + _fetchPostDetail(); + _fetchComments(); + } + + Future _fetchPostDetail() async { + final url = resolve('api/post/${widget.postId}'); + final response = await GlobalInformation.getInstance().requester.get(url); + + if (response.statusCode == 200) { + setState(() { + post = Map.from(jsonDecode(response.body)['data']); + }); + } else { + throw Exception('Failed to load post detail'); + } + } + + Future _fetchComments() async { + if (isLoading || !hasMore) return; + + setState(() { + isLoading = true; + }); + + var url = resolve('api/post/comment/list'); + url = url.replace(queryParameters: { + 'postId': widget.postId.toString(), + 'pageNum': pageNum.toString(), + 'pageSize': pageSize.toString(), + }); + final response = await GlobalInformation.getInstance().requester.get( + url, + ); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + setState(() { + comments.addAll(List>.from(data['rows'])); + hasMore = data['rows'].length == pageSize; + if (hasMore) { + pageNum++; + } + }); + } else { + throw Exception('Failed to load comments'); + } + + setState(() { + isLoading = false; + }); + } @override Widget build(BuildContext context) { return Scaffold( - body: Column( - children: [ - Container( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon(Icons.keyboard_arrow_left), + ), + title: const Text("帖子详情"), + centerTitle: true, + ), + body: post == null + ? const Center(child: CircularProgressIndicator()) + : ListView( children: [ - Text(post['user'], style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), - const SizedBox(height: 10), - const Text("发布时间: 2024-08-24"), - const SizedBox(height: 20), - const Text("这是社交帖的内容。这是一段假数据。", style: TextStyle(fontSize: 16)), - ], - ), - ), - const Divider(), - Expanded( - child: ListView.builder( - itemCount: comments.length, - itemBuilder: (context, index) { - final comment = comments[index]; - return ListTile( - leading: const CircleAvatar( - child: Placeholder(), - ), - title: Text(comment['username']), - subtitle: Column( + Container( + padding: const EdgeInsets.all(16.0), + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(comment['content']), - const SizedBox(height: 5), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(comment['date'], style: const TextStyle(fontSize: 12, color: Colors.grey)), - Row( - children: [ - const Icon(Icons.favorite, color: Colors.red, size: 16), - const SizedBox(width: 4), - Text(comment['likes'].toString()), - ], + Text(post!['nickName'] ?? "未知用户", style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), + const SizedBox(height: 10), + Text("发布时间: ${post!['createTime']}"), + const SizedBox(height: 20), + Text(post!['content'] ?? "无内容", style: const TextStyle(fontSize: 16)), + const SizedBox(height: 10), + Image.network(resolve(post!['cover']).toString()), + ], + ), + ), + const Divider(), + Expanded( + child: NotificationListener( + onNotification: (ScrollNotification scrollInfo) { + if (!isLoading && + scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { + _fetchComments(); + } + return false; + }, + child: SizedBox( + height: 600, + child: ListView.builder( + itemCount: comments.length + 1, + itemBuilder: (context, index) { + if (index == comments.length) { + return hasMore + ? const Center(child: CircularProgressIndicator()) + : const Padding( + padding: EdgeInsets.all(8.0), + child: Center(child: Text("没有更多评论了")), + ); + } + final comment = comments[index]; + return ListTile( + leading: comment['avatar'] != null && comment['avatar'] != '' ? CircleAvatar( + backgroundImage: NetworkImage(resolve(comment['avatar']).toString()), + ) : const SizedBox(width: 40, height: 40, child: Placeholder()), + title: Text(comment['nickName'] ?? "未知用户"), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(comment['content'] ?? ""), + const SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(comment['createTime'] ?? "未知", style: const TextStyle(fontSize: 12, color: Colors.grey)), + Row( + children: [ + const Icon(Icons.favorite, color: Colors.red, size: 16), + const SizedBox(width: 4), + Text(comment['likeNum'].toString()), + ], + ), + ], + ), + ], + ), + ); + }, + ), + ) + ), + ), + const Divider(), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + decoration: const InputDecoration( + hintText: '发表评论...', + border: OutlineInputBorder(), ), - ], + controller: _commentController, + ), + ), + const SizedBox(width: 10), + ElevatedButton( + onPressed: () { + var global = GlobalInformation.getInstance(); + global.requester.post(resolve('api/post/comment'), body: jsonEncode({"postId": widget.postId.toString(), "content": _commentController.text, "likeNum": "0", "parentId": 0})); + _commentController.clear(); + }, + child: const Text("发布"), ), ], ), - ); - }, - ), - ), - const Divider(), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - const Expanded( - child: TextField( - decoration: InputDecoration( - hintText: '发表评论...', - border: OutlineInputBorder(), - ), - ), - ), - const SizedBox(width: 10), - ElevatedButton( - onPressed: () {}, - child: const Text("发布"), ), ], - ), - ), - ], - ), + ) ); } } \ No newline at end of file