mod: merge main
This commit is contained in:
33
lib/common/widgets/appbar.dart
Normal file
33
lib/common/widgets/appbar.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppBarWidget extends StatelessWidget implements PreferredSizeWidget {
|
||||
const AppBarWidget({
|
||||
required this.child,
|
||||
required this.controller,
|
||||
required this.visible,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
final PreferredSizeWidget child;
|
||||
final AnimationController controller;
|
||||
final bool visible;
|
||||
|
||||
@override
|
||||
// TODO: implement preferredSize
|
||||
Size get preferredSize => child.preferredSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
visible ? controller.reverse() : controller.forward();
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: const Offset(0, -1),
|
||||
).animate(CurvedAnimation(
|
||||
parent: controller,
|
||||
curve: Curves.easeInOutBack,
|
||||
)),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
34
lib/common/widgets/http_error.dart
Normal file
34
lib/common/widgets/http_error.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HttpError extends StatelessWidget {
|
||||
HttpError({required this.errMsg, required this.fn, super.key});
|
||||
|
||||
String errMsg = '';
|
||||
final Function()? fn;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: 150,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
errMsg,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
fn!();
|
||||
},
|
||||
child: const Text('点击重试'))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:pilipala/common/constants.dart';
|
||||
|
||||
class NetworkImgLayer extends StatelessWidget {
|
||||
final String? src;
|
||||
@ -29,11 +30,16 @@ class NetworkImgLayer extends StatelessWidget {
|
||||
// double pr = 2;
|
||||
return src != ''
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(type == 'avatar' ? 50 : 4),
|
||||
borderRadius: BorderRadius.circular(type == 'avatar'
|
||||
? 50
|
||||
: type == 'emote'
|
||||
? 0
|
||||
: StyleString.imgRadius.x),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: src!,
|
||||
width: width ?? double.infinity,
|
||||
height: height ?? double.infinity,
|
||||
alignment: Alignment.center,
|
||||
maxWidthDiskCache: ((cacheW ?? width!) * pr).toInt(),
|
||||
// maxHeightDiskCache: (cacheH ?? height!).toInt(),
|
||||
memCacheWidth: ((cacheW ?? width!) * pr).toInt(),
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pilipala/utils/utils.dart';
|
||||
|
||||
@ -11,21 +12,21 @@ class StatDanMu extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color color =
|
||||
theme == 'white' ? Colors.white : Theme.of(context).colorScheme.outline;
|
||||
return Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/dm_$theme.png',
|
||||
width: size == 'medium' ? 16 : 14,
|
||||
height: size == 'medium' ? 16 : 14,
|
||||
Icon(
|
||||
CupertinoIcons.ellipses_bubble,
|
||||
size: 14,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
const SizedBox(width: 3),
|
||||
Text(
|
||||
Utils.numFormat(danmu!),
|
||||
style: TextStyle(
|
||||
fontSize: size == 'medium' ? 12 : 11,
|
||||
color: theme == 'white'
|
||||
? Colors.white
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
color: color,
|
||||
),
|
||||
)
|
||||
],
|
||||
|
||||
24
lib/common/widgets/stat/up.dart
Normal file
24
lib/common/widgets/stat/up.dart
Normal file
@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class UpTag extends StatelessWidget {
|
||||
const UpTag({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 14,
|
||||
height: 10,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
border: Border.all(color: Theme.of(context).colorScheme.outline)),
|
||||
margin: const EdgeInsets.only(right: 4),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'UP',
|
||||
style: TextStyle(
|
||||
fontSize: 6, color: Theme.of(context).colorScheme.outline),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pilipala/utils/utils.dart';
|
||||
|
||||
@ -6,26 +7,26 @@ class StatView extends StatelessWidget {
|
||||
final int? view;
|
||||
final String? size;
|
||||
|
||||
const StatView({Key? key, this.theme, this.view, this.size}) : super(key: key);
|
||||
const StatView({Key? key, this.theme, this.view, this.size})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color color =
|
||||
theme == 'white' ? Colors.white : Theme.of(context).colorScheme.outline;
|
||||
return Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/view_$theme.png',
|
||||
width: size == 'medium' ? 16 : 14,
|
||||
height: size == 'medium' ? 16 : 14,
|
||||
Icon(
|
||||
CupertinoIcons.play_rectangle,
|
||||
size: 13,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
const SizedBox(width: 3),
|
||||
Text(
|
||||
Utils.numFormat(view!),
|
||||
// videoItem['stat']['view'].toString(),
|
||||
style: TextStyle(
|
||||
fontSize: size == 'medium' ? 12 : 11,
|
||||
color: theme == 'white'
|
||||
? Colors.white
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -7,6 +7,7 @@ import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||
|
||||
// 视频卡片 - 水平布局
|
||||
class VideoCardH extends StatelessWidget {
|
||||
// ignore: prefer_typing_uninitialized_variables
|
||||
var videoItem;
|
||||
Function()? longPress;
|
||||
Function()? longPressEnd;
|
||||
@ -20,84 +21,94 @@ class VideoCardH extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Ink(
|
||||
child: GestureDetector(
|
||||
onLongPress: () {
|
||||
longPress!();
|
||||
},
|
||||
onLongPressEnd: (details) {
|
||||
longPressEnd!();
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
int aid = videoItem.aid ?? videoItem.id;
|
||||
Get.toNamed('/video?aid=$aid',
|
||||
arguments: {'videoItem': videoItem});
|
||||
},
|
||||
child: Container(
|
||||
int aid = videoItem.aid;
|
||||
String heroTag = Utils.makeHeroTag(aid);
|
||||
return GestureDetector(
|
||||
onLongPress: () {
|
||||
longPress!();
|
||||
},
|
||||
onLongPressEnd: (details) {
|
||||
longPressEnd!();
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
Get.toNamed('/video?aid=$aid',
|
||||
arguments: {'videoItem': videoItem, 'heroTag': heroTag});
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
StyleString.cardSpace, 5, StyleString.cardSpace, 5),
|
||||
child: LayoutBuilder(builder: (context, boxConstraints) {
|
||||
double width =
|
||||
(boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2;
|
||||
return SizedBox(
|
||||
height: width / StyleString.aspectRatio,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: StyleString.aspectRatio,
|
||||
// child: ClipRRect(
|
||||
// borderRadius: StyleString.mdRadius,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
double maxWidth = boxConstraints.maxWidth;
|
||||
double maxHeight = boxConstraints.maxHeight;
|
||||
double PR = MediaQuery.of(context).devicePixelRatio;
|
||||
return Stack(
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
// src: videoItem['pic'] +
|
||||
// '@${(maxWidth * 2).toInt()}w',
|
||||
src: videoItem.pic + '@.webp',
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
),
|
||||
// Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,),
|
||||
Positioned(
|
||||
right: 4,
|
||||
bottom: 4,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 1, horizontal: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: Colors.black54.withOpacity(0.4)),
|
||||
child: Text(
|
||||
Utils.timeFormat(videoItem.duration!),
|
||||
style: const TextStyle(
|
||||
fontSize: 11, color: Colors.white),
|
||||
StyleString.cardSpace, 7, StyleString.cardSpace, 7),
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
double width =
|
||||
(boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2;
|
||||
return SizedBox(
|
||||
height: width / StyleString.aspectRatio,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: StyleString.aspectRatio,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
double maxWidth = boxConstraints.maxWidth;
|
||||
double maxHeight = boxConstraints.maxHeight;
|
||||
double PR =
|
||||
MediaQuery.of(context).devicePixelRatio;
|
||||
return Stack(
|
||||
children: [
|
||||
Hero(
|
||||
tag: heroTag,
|
||||
child: NetworkImgLayer(
|
||||
// src: videoItem['pic'] +
|
||||
// '@${(maxWidth * 2).toInt()}w',
|
||||
src: videoItem.pic + '@.webp',
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
),
|
||||
),
|
||||
// Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
Positioned(
|
||||
right: 4,
|
||||
bottom: 4,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 1, horizontal: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.circular(4),
|
||||
color:
|
||||
Colors.black54.withOpacity(0.4)),
|
||||
child: Text(
|
||||
Utils.timeFormat(videoItem.duration!),
|
||||
style: const TextStyle(
|
||||
fontSize: 11, color: Colors.white),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
// ),
|
||||
),
|
||||
VideoContent(videoItem: videoItem)
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
// height: 124,
|
||||
VideoContent(videoItem: videoItem)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
indent: 8,
|
||||
endIndent: 12,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.08),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -126,7 +137,7 @@ class VideoContent extends StatelessWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Spacer(),
|
||||
if (videoItem.rcmdReason != '' &&
|
||||
if (videoItem.rcmdReason != null &&
|
||||
videoItem.rcmdReason.content != '')
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||||
@ -145,12 +156,6 @@ class VideoContent extends StatelessWidget {
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/up_gray.png',
|
||||
width: 14,
|
||||
height: 12,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
videoItem.owner.name,
|
||||
style: TextStyle(
|
||||
|
||||
@ -22,6 +22,7 @@ class VideoCardV extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String heroTag = Utils.makeHeroTag(videoItem.id);
|
||||
return Card(
|
||||
elevation: 0.8,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
@ -40,7 +41,7 @@ class VideoCardV extends StatelessWidget {
|
||||
onTap: () async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
Get.toNamed('/video?aid=${videoItem.id}',
|
||||
arguments: {'videoItem': videoItem});
|
||||
arguments: {'videoItem': videoItem, 'heroTag': heroTag});
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
@ -57,12 +58,15 @@ class VideoCardV extends StatelessWidget {
|
||||
double PR = MediaQuery.of(context).devicePixelRatio;
|
||||
return Stack(
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
// 指定图片尺寸
|
||||
// src: videoItem.pic + '@${(maxWidth * 2).toInt()}w',
|
||||
src: videoItem.pic + '@.webp',
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
Hero(
|
||||
tag: heroTag,
|
||||
child: NetworkImgLayer(
|
||||
// 指定图片尺寸
|
||||
// src: videoItem.pic + '@${(maxWidth * 2).toInt()}w',
|
||||
src: videoItem.pic + '@.webp',
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
@ -77,7 +81,7 @@ class VideoCardV extends StatelessWidget {
|
||||
duration: videoItem.duration,
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
@ -141,6 +145,25 @@ class VideoContent extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4)
|
||||
] else if (videoItem.isFollowed == 1) ...[
|
||||
Container(
|
||||
padding: const EdgeInsets.fromLTRB(3, 1, 3, 1),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer
|
||||
.withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(3)),
|
||||
child: Text(
|
||||
'已关注',
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4)
|
||||
],
|
||||
Expanded(
|
||||
child: LayoutBuilder(builder:
|
||||
|
||||
Reference in New Issue
Block a user