DIgitalLife/lib/views/social.dart
2024-09-02 19:49:30 +08:00

364 lines
11 KiB
Dart

import 'package:environmental_protection/common/user_information.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
class PostCard extends StatefulWidget {
final Map<String, dynamic> post;
const PostCard({super.key, required this.post});
@override
State<PostCard> createState() => _PostCardState();
}
class _PostCardState extends State<PostCard> {
bool _isLike = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PostDetailPage(postId: widget.post['id']),
),
);
},
child: Flex(
direction: Axis.vertical,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
resolve(widget.post['cover']).toString(),
fit: BoxFit.cover,
height: 150,
width: double.infinity,
),
Padding(
padding: const EdgeInsetsDirectional.only(top: 10),
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.post['nickName'] ?? "未知用户", style: const TextStyle(fontSize: 16)),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: TextButton(
onPressed: (){
setState(() {
_isLike = !_isLike;
});
},
child: Row(
children: [
Icon(Icons.favorite, color: _isLike ? Colors.red : Colors.grey, size: 16),
const SizedBox(width: 5),
Text((_isLike ? widget.post['likeNum'] + 1 : widget.post['likeNum']).toString()),
],
)
)
),
],
),
)
],
),
);
}
}
class SocialPage extends StatefulWidget {
const SocialPage({super.key});
@override
State<SocialPage> createState() => _SocialPageState();
}
class _SocialPageState extends State<SocialPage> {
List<Map<String, dynamic>> posts = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_fetchPosts();
}
Future<void> _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<Map<String, dynamic>>.from(data['rows']);
_isLoading = false;
});
} else {
throw Exception('Failed to load posts');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("友邻社交"),
),
body: _isLoading ? const Center(child: CircularProgressIndicator()) : GridView.builder(
padding: const EdgeInsets.all(10.0),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
crossAxisSpacing: 10.0,
),
itemCount: posts.length,
itemBuilder: (context, index) {
return PostCard(post: posts[index]);
},
),
/* floatingActionButton: FloatingActionButton(
heroTag: 'uniqueTag',
onPressed: () {
// 添加发布帖子的功能
},
child: const Icon(Icons.add),
),*/
);
}
}
class Comment extends StatefulWidget {
final Map<String, dynamic> comment;
const Comment({super.key, required this.comment});
@override
State<Comment> createState() => _CommentState();
}
class _CommentState extends State<Comment> {
bool _isLike = false;
@override
Widget build(BuildContext context) {
final comment = widget.comment;
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)),
TextButton(
onPressed: (){
setState(() {
_isLike = !_isLike;
});
},
child: Row(
children: [
Icon(Icons.favorite, color: _isLike ? Colors.red : Colors.grey, size: 16),
const SizedBox(width: 5),
Text((_isLike ? comment['likeNum'] + 1 : comment['likeNum']).toString()),
],
),
)
],
),
],
),
);
}
}
class PostDetailPage extends StatefulWidget {
final int postId;
const PostDetailPage({super.key, required this.postId});
@override
State<PostDetailPage> createState() => _PostDetailPageState();
}
class _PostDetailPageState extends State<PostDetailPage> {
Map<String, dynamic>? post;
List<Map<String, dynamic>> 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<void> _fetchPostDetail() async {
final url = resolve('api/post/${widget.postId}');
final response = await GlobalInformation.getInstance().requester.get(url);
if (response.statusCode == 200) {
setState(() {
post = Map<String, dynamic>.from(jsonDecode(response.body)['data']);
});
} else {
throw Exception('Failed to load post detail');
}
}
Future<void> _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<Map<String, dynamic>>.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(
appBar: AppBar(
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.keyboard_arrow_left),
),
title: const Text("帖子详情"),
centerTitle: true,
),
body: Stack(
children: [
Positioned.fill(child: post == null
? const Center(child: CircularProgressIndicator())
: ListView(
children: [
Container(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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<ScrollNotification>(
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("没有更多评论了")),
);
}
return Comment(comment: comments[index]);
},
),
)
),
),
],
)),
Positioned.fill(
bottom: 0,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
decoration: const BoxDecoration(
color: Colors.white
),
child: 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("发布"),
),
],
),
),
)
],
)
)
],
)
);
}
}