mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 04:57:23 +00:00
comments
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/material.dart' show Icons;
|
||||
import 'package:pixes/components/animated_image.dart';
|
||||
import 'package:pixes/components/loading.dart';
|
||||
import 'package:pixes/components/message.dart';
|
||||
import 'package:pixes/components/page_route.dart';
|
||||
import 'package:pixes/foundation/app.dart';
|
||||
import 'package:pixes/foundation/image_provider.dart';
|
||||
import 'package:pixes/network/download.dart';
|
||||
@@ -15,10 +18,12 @@ import '../components/md.dart';
|
||||
const _kBottomBarHeight = 64.0;
|
||||
|
||||
class IllustPage extends StatefulWidget {
|
||||
const IllustPage(this.illust, {super.key});
|
||||
const IllustPage(this.illust, {this.favoriteCallback, super.key});
|
||||
|
||||
final Illust illust;
|
||||
|
||||
final void Function(bool)? favoriteCallback;
|
||||
|
||||
@override
|
||||
State<IllustPage> createState() => _IllustPageState();
|
||||
}
|
||||
@@ -41,7 +46,12 @@ class _IllustPageState extends State<IllustPage> {
|
||||
top: 0,
|
||||
child: buildBody(constrains.maxWidth, constrains.maxHeight),
|
||||
),
|
||||
_BottomBar(widget.illust, constrains.maxHeight, constrains.maxWidth),
|
||||
_BottomBar(
|
||||
widget.illust,
|
||||
constrains.maxHeight,
|
||||
constrains.maxWidth,
|
||||
favoriteCallback: widget.favoriteCallback,
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
@@ -105,7 +115,9 @@ class _IllustPageState extends State<IllustPage> {
|
||||
}
|
||||
|
||||
class _BottomBar extends StatefulWidget {
|
||||
const _BottomBar(this.illust, this.height, this.width);
|
||||
const _BottomBar(this.illust, this.height, this.width, {this.favoriteCallback});
|
||||
|
||||
final void Function(bool)? favoriteCallback;
|
||||
|
||||
final Illust illust;
|
||||
|
||||
@@ -335,6 +347,7 @@ class _BottomBarState extends State<_BottomBar> {
|
||||
}
|
||||
} else {
|
||||
widget.illust.isBookmarked = !widget.illust.isBookmarked;
|
||||
widget.favoriteCallback?.call(widget.illust.isBookmarked);
|
||||
}
|
||||
setState(() {
|
||||
isBookmarking = false;
|
||||
@@ -406,7 +419,7 @@ class _BottomBarState extends State<_BottomBar> {
|
||||
yield const SizedBox(width: 8,);
|
||||
|
||||
yield Button(
|
||||
onPressed: favorite,
|
||||
onPressed: () => _CommentsPage.show(context, widget.illust.id.toString()),
|
||||
child: SizedBox(
|
||||
height: 28,
|
||||
child: Row(
|
||||
@@ -502,3 +515,162 @@ class _BottomBarState extends State<_BottomBar> {
|
||||
).paddingVertical(8).paddingHorizontal(2);
|
||||
}
|
||||
}
|
||||
|
||||
class _CommentsPage extends StatefulWidget {
|
||||
const _CommentsPage(this.id);
|
||||
|
||||
final String id;
|
||||
|
||||
static void show(BuildContext context, String id) {
|
||||
Navigator.of(context).push(SideBarRoute(_CommentsPage(id)));
|
||||
}
|
||||
|
||||
@override
|
||||
State<_CommentsPage> createState() => _CommentsPageState();
|
||||
}
|
||||
|
||||
class _CommentsPageState extends MultiPageLoadingState<_CommentsPage, Comment> {
|
||||
bool isCommenting = false;
|
||||
|
||||
@override
|
||||
Widget buildContent(BuildContext context, List<Comment> data) {
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(child: buildBody(context, data)),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: buildBottom(context),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBody(BuildContext context, List<Comment> data) {
|
||||
return ListView.builder(
|
||||
itemCount: data.length + 2,
|
||||
itemBuilder: (context, index) {
|
||||
if(index == 0) {
|
||||
return Text("Comments".tl, style: const TextStyle(fontSize: 20)).paddingVertical(8).paddingHorizontal(12);
|
||||
} else if(index == data.length + 1) {
|
||||
return const SizedBox(height: 64,);
|
||||
}
|
||||
index--;
|
||||
var date = data[index].date;
|
||||
var dateText = "${date.year}/${date.month}/${date.day}";
|
||||
return Card(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
|
||||
margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 38,
|
||||
width: 38,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(38),
|
||||
child: ColoredBox(
|
||||
color: ColorScheme.of(context).secondaryContainer,
|
||||
child: GestureDetector(
|
||||
onTap: () => context.to(() => UserInfoPage(data[index].id.toString())),
|
||||
child: AnimatedImage(
|
||||
image: CachedImageProvider(data[index].avatar),
|
||||
width: 38,
|
||||
height: 38,
|
||||
fit: BoxFit.cover,
|
||||
filterQuality: FilterQuality.medium,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8,),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(data[index].name, style: const TextStyle(fontSize: 14),),
|
||||
Text(dateText, style: TextStyle(fontSize: 12, color: ColorScheme.of(context).outline),)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8,),
|
||||
if(data[index].comment.isNotEmpty)
|
||||
Text(data[index].comment, style: const TextStyle(fontSize: 16),),
|
||||
if(data[index].stampUrl != null)
|
||||
SizedBox(
|
||||
height: 64,
|
||||
width: 64,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: AnimatedImage(
|
||||
image: CachedImageProvider(data[index].stampUrl!),
|
||||
width: 64,
|
||||
height: 64,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBottom(BuildContext context) {
|
||||
return Card(
|
||||
padding: EdgeInsets.zero,
|
||||
backgroundColor: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.96),
|
||||
child: SizedBox(
|
||||
height: 52,
|
||||
child: TextBox(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
placeholder: "Comment".tl,
|
||||
foregroundDecoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.transparent),
|
||||
),
|
||||
onSubmitted: (s) {
|
||||
showToast(context, message: "Sending".tl);
|
||||
if(isCommenting) return;
|
||||
setState(() {
|
||||
isCommenting = true;
|
||||
});
|
||||
Network().comment(widget.id, s).then((value) {
|
||||
if(value.error) {
|
||||
context.showToast(message: "Network Error");
|
||||
setState(() {
|
||||
isCommenting = false;
|
||||
});
|
||||
} else {
|
||||
isCommenting = false;
|
||||
nextUrl = null;
|
||||
reset();
|
||||
}
|
||||
});
|
||||
},
|
||||
).paddingVertical(8).paddingHorizontal(12),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String? nextUrl;
|
||||
|
||||
@override
|
||||
Future<Res<List<Comment>>> loadData(int page) async{
|
||||
if(nextUrl == "end") {
|
||||
return Res.error("No more data");
|
||||
}
|
||||
var res = await Network().getComments(widget.id, nextUrl);
|
||||
if(!res.error) {
|
||||
nextUrl = res.subData;
|
||||
nextUrl ??= "end";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user