mod: 样式
This commit is contained in:
BIN
assets/fonts/ArchivoNarrow-BoldItalic.ttf
Normal file
BIN
assets/fonts/ArchivoNarrow-BoldItalic.ttf
Normal file
Binary file not shown.
@ -59,7 +59,7 @@ class _VideoCardHSkeletonState extends State<VideoCardHSkeleton> {
|
||||
.colorScheme
|
||||
.onInverseSurface,
|
||||
width: 200,
|
||||
height: 13,
|
||||
height: 11,
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
),
|
||||
Container(
|
||||
|
@ -25,12 +25,6 @@ class VideoCardVSkeleton extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline
|
||||
.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -23,8 +23,8 @@ class VideoReplySkeleton extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Container(
|
||||
width: 120,
|
||||
height: 16,
|
||||
width: 80,
|
||||
height: 13,
|
||||
color: bgColor,
|
||||
)
|
||||
],
|
||||
@ -40,28 +40,28 @@ class VideoReplySkeleton extends StatelessWidget {
|
||||
children: [
|
||||
Container(
|
||||
width: 300,
|
||||
height: 16,
|
||||
height: 14,
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
color: bgColor,
|
||||
),
|
||||
Container(
|
||||
width: 180,
|
||||
height: 16,
|
||||
margin: const EdgeInsets.only(bottom: 6),
|
||||
height: 14,
|
||||
margin: const EdgeInsets.only(bottom: 10),
|
||||
color: bgColor,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 16,
|
||||
width: 40,
|
||||
height: 14,
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
color: bgColor,
|
||||
),
|
||||
const Spacer(),
|
||||
Container(
|
||||
width: 60,
|
||||
height: 16,
|
||||
width: 40,
|
||||
height: 14,
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
color: bgColor,
|
||||
),
|
||||
|
@ -27,7 +27,11 @@ class MyApp extends StatelessWidget {
|
||||
ColorScheme.fromSeed(
|
||||
seedColor: Colors.green, brightness: Brightness.light),
|
||||
useMaterial3: true),
|
||||
darkTheme: ThemeData(colorScheme: darkDynamic, useMaterial3: true),
|
||||
darkTheme: ThemeData(
|
||||
colorScheme: darkDynamic ??
|
||||
ColorScheme.fromSeed(
|
||||
seedColor: Colors.green, brightness: Brightness.dark),
|
||||
useMaterial3: true),
|
||||
getPages: Routes.getPages,
|
||||
home: const MainApp(),
|
||||
// home: const Scaffold(),
|
||||
|
@ -6,6 +6,7 @@ class ReplyContent {
|
||||
this.emote, // 表情包 如果有的话 null
|
||||
this.jumpUrl, // {}
|
||||
this.pictures, // {}
|
||||
this.vote,
|
||||
});
|
||||
|
||||
String? message;
|
||||
@ -14,6 +15,7 @@ class ReplyContent {
|
||||
Map? emote;
|
||||
Map? jumpUrl;
|
||||
List? pictures;
|
||||
Map? vote;
|
||||
|
||||
ReplyContent.fromJson(Map<String, dynamic> json) {
|
||||
message = json['message'];
|
||||
@ -22,5 +24,6 @@ class ReplyContent {
|
||||
emote = json['emote'] ?? {};
|
||||
jumpUrl = json['jump_url'] ?? {};
|
||||
pictures = json['pictures'] ?? [];
|
||||
vote = json['vote'] ?? {};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
class HomeAppBar extends StatelessWidget {
|
||||
const HomeAppBar({super.key});
|
||||
@ -29,19 +30,26 @@ class HomeAppBar extends StatelessWidget {
|
||||
title: const Text(
|
||||
'PiLiPaLa',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontSize: 19,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1,
|
||||
fontFamily: 'ArchivoNarrow',
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.notifications_none_rounded),
|
||||
icon: const FaIcon(
|
||||
FontAwesomeIcons.magnifyingGlass,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.search_rounded),
|
||||
icon: const FaIcon(
|
||||
FontAwesomeIcons.envelope,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10)
|
||||
],
|
||||
|
@ -19,7 +19,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
||||
late AnimationController? _animationController;
|
||||
late Animation<double>? _fadeAnimation;
|
||||
late Animation<double>? _slideAnimation;
|
||||
int selectedIndex = 0;
|
||||
int selectedIndex = 2;
|
||||
int? _lastSelectTime; //上次点击时间
|
||||
|
||||
@override
|
||||
|
@ -1,4 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:pilipala/common/constants.dart';
|
||||
|
||||
class MinePage extends StatefulWidget {
|
||||
const MinePage({super.key});
|
||||
@ -12,7 +14,187 @@ class _MinePageState extends State<MinePage> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('我的'),
|
||||
title: null,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.light_mode_rounded),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const FaIcon(
|
||||
FontAwesomeIcons.sliders,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(left: 12, right: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(width: 20),
|
||||
ClipOval(
|
||||
child: Container(
|
||||
width: 75,
|
||||
height: 75,
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
child: Center(
|
||||
child: Image.asset('assets/images/loading.png'),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Text(
|
||||
'点击登录',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
TextStyle style = TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.titleMedium!.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: FontWeight.bold);
|
||||
return SizedBox(
|
||||
height: constraints.maxWidth / 3 * 0.6,
|
||||
child: GridView.count(
|
||||
primary: false,
|
||||
padding: const EdgeInsets.all(0),
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.67,
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('-', style: style),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'动态',
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'50',
|
||||
style: style,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'关注',
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'-',
|
||||
style: style,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'粉丝',
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SizedBox(
|
||||
height: constraints.maxWidth / 4 * 0.8,
|
||||
child: GridView.count(
|
||||
primary: false,
|
||||
padding: const EdgeInsets.all(0),
|
||||
crossAxisCount: 4,
|
||||
childAspectRatio: 1.25,
|
||||
children: <Widget>[
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.download),
|
||||
onTap: () => {},
|
||||
text: '离线缓存',
|
||||
),
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.clockRotateLeft),
|
||||
onTap: () => {},
|
||||
text: '历史记录',
|
||||
),
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.star),
|
||||
onTap: () => {},
|
||||
text: '我的收藏',
|
||||
),
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.film),
|
||||
onTap: () => {},
|
||||
text: '稍后再看',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ActionItem extends StatelessWidget {
|
||||
Icon? icon;
|
||||
Function? onTap;
|
||||
String? text;
|
||||
|
||||
ActionItem({
|
||||
Key? key,
|
||||
this.icon,
|
||||
this.onTap,
|
||||
this.text,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon!.icon!),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
text!,
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pilipala/common/constants.dart';
|
||||
@ -114,116 +115,29 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 12, right: 12, top: 25),
|
||||
padding: const EdgeInsets.only(left: 12, right: 12, top: 20),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: !widget.loadingStatus || videoItem.isNotEmpty
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
type: 'avatar',
|
||||
src: !widget.loadingStatus
|
||||
? widget.videoDetail!.owner!.face
|
||||
: videoItem['owner'].face,
|
||||
width: 38,
|
||||
height: 38,
|
||||
fadeInDuration: Duration.zero,
|
||||
fadeOutDuration: Duration.zero,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(!widget.loadingStatus
|
||||
? widget.videoDetail!.owner!.name
|
||||
: videoItem['owner'].name),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
widget.loadingStatus
|
||||
? '- 粉丝'
|
||||
: '${Utils.numFormat(widget.videoIntroController!.userStat['follower'])}粉丝',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.outline),
|
||||
)
|
||||
]),
|
||||
const Spacer(),
|
||||
AnimatedOpacity(
|
||||
opacity: widget.loadingStatus ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: SizedBox(
|
||||
height: 35,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {}, child: const Text('+ 关注')),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
SelectableRegion(
|
||||
magnifierConfiguration: const TextMagnifierConfiguration(),
|
||||
focusNode: FocusNode(),
|
||||
selectionControls: MaterialTextSelectionControls(),
|
||||
child: Text(
|
||||
!widget.loadingStatus
|
||||
? widget.videoDetail!.title
|
||||
: videoItem['title'],
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 13),
|
||||
// 标题 超过两行收起
|
||||
// Container(
|
||||
// color: Colors.blue[50],
|
||||
// child: SizedOverflowBox(
|
||||
// size: const Size(50.0, 50.0),
|
||||
// alignment: AlignmentDirectional.bottomStart,
|
||||
// child: Container(height: 150.0, width: 150.0, color: Colors.blue,),
|
||||
// ),
|
||||
// ),
|
||||
// Row(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: ExpandedSection(
|
||||
// expand: false,
|
||||
// begin: 1,
|
||||
// end: 1,
|
||||
// child: Text(
|
||||
// !widget.loadingStatus
|
||||
// ? widget.videoDetail!.title
|
||||
// : videoItem['title'],
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// maxLines: 1,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 10),
|
||||
// RotationTransition(
|
||||
// turns: _manualAnimation!,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// /// 获取动画当前的值
|
||||
// var value = _manualController!.value;
|
||||
|
||||
// /// 0.5代表 180弧度
|
||||
// if (value == 0) {
|
||||
// _manualController!.animateTo(0.5);
|
||||
// } else {
|
||||
// _manualController!.animateTo(0);
|
||||
// }
|
||||
// setState(() {
|
||||
// isExpand = !isExpand;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(Icons.expand_less)),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
|
||||
Text(
|
||||
!widget.loadingStatus
|
||||
? widget.videoDetail!.title
|
||||
: videoItem['title'],
|
||||
),
|
||||
// const SizedBox(height: 5),
|
||||
// 播放量、评论、日期
|
||||
|
||||
InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
onTap: () {
|
||||
_manualController!.animateTo(isExpand ? 0 : 0.5);
|
||||
setState(() {
|
||||
@ -276,8 +190,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.expand_less,
|
||||
size: 22,
|
||||
FontAwesomeIcons.angleUp,
|
||||
size: 15,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
@ -287,8 +201,65 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// const SizedBox(height: 5),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
type: 'avatar',
|
||||
src: !widget.loadingStatus
|
||||
? widget.videoDetail!.owner!.face
|
||||
: videoItem['owner'].face,
|
||||
width: 38,
|
||||
height: 38,
|
||||
fadeInDuration: Duration.zero,
|
||||
fadeOutDuration: Duration.zero,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(!widget.loadingStatus
|
||||
? widget.videoDetail!.owner!.name
|
||||
: videoItem['owner'].name),
|
||||
// const SizedBox(width: 10),
|
||||
Text(
|
||||
widget.loadingStatus
|
||||
? '- 粉丝'
|
||||
: '${Utils.numFormat(widget.videoIntroController!.userStat['follower'])}粉丝',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.outline),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
AnimatedOpacity(
|
||||
opacity: widget.loadingStatus ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: SizedBox(
|
||||
height: 36,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: const [
|
||||
Icon(
|
||||
FontAwesomeIcons.lemon,
|
||||
size: 17,
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Text('关注'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// 简介 默认收起
|
||||
if (!widget.loadingStatus)
|
||||
ExpandedSection(
|
||||
@ -320,8 +291,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
_actionGrid(context),
|
||||
// const SizedBox(height: 5),
|
||||
],
|
||||
)
|
||||
: const Center(child: CircularProgressIndicator()),
|
||||
@ -333,14 +304,15 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
Widget _actionGrid(BuildContext context) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return SizedBox(
|
||||
height: constraints.maxWidth / 5,
|
||||
height: constraints.maxWidth / 5 * 0.8,
|
||||
child: GridView.count(
|
||||
primary: false,
|
||||
padding: const EdgeInsets.all(0),
|
||||
crossAxisCount: 5,
|
||||
childAspectRatio: 1.25,
|
||||
children: <Widget>[
|
||||
ActionItem(
|
||||
icon: const Icon(Icons.thumb_up),
|
||||
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
||||
onTap: () => {},
|
||||
selectStatus: false,
|
||||
loadingStatus: widget.loadingStatus,
|
||||
@ -348,13 +320,13 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
? widget.videoDetail!.stat!.like!.toString()
|
||||
: '-'),
|
||||
ActionItem(
|
||||
icon: const Icon(Icons.thumb_down),
|
||||
icon: const Icon(FontAwesomeIcons.thumbsDown),
|
||||
onTap: () => {},
|
||||
selectStatus: false,
|
||||
loadingStatus: widget.loadingStatus,
|
||||
text: '不喜欢'),
|
||||
ActionItem(
|
||||
icon: const Icon(Icons.generating_tokens),
|
||||
icon: const Icon(FontAwesomeIcons.b),
|
||||
onTap: () => {},
|
||||
selectStatus: false,
|
||||
loadingStatus: widget.loadingStatus,
|
||||
@ -362,7 +334,10 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
? widget.videoDetail!.stat!.coin!.toString()
|
||||
: '-'),
|
||||
ActionItem(
|
||||
icon: const Icon(Icons.star),
|
||||
icon: const Icon(
|
||||
FontAwesomeIcons.heart,
|
||||
size: 17,
|
||||
),
|
||||
onTap: () => {},
|
||||
selectStatus: false,
|
||||
loadingStatus: widget.loadingStatus,
|
||||
@ -370,7 +345,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
||||
? widget.videoDetail!.stat!.favorite!.toString()
|
||||
: '-'),
|
||||
ActionItem(
|
||||
icon: const Icon(Icons.share),
|
||||
icon: const Icon(FontAwesomeIcons.shareFromSquare),
|
||||
onTap: () => {},
|
||||
selectStatus: false,
|
||||
loadingStatus: widget.loadingStatus,
|
||||
@ -403,33 +378,35 @@ class ActionItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Ink(
|
||||
child: InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon!.icon!,
|
||||
color: selectStatus
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).colorScheme.outline),
|
||||
const SizedBox(height: 2),
|
||||
AnimatedOpacity(
|
||||
opacity: loadingStatus! ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Text(
|
||||
text!,
|
||||
style: TextStyle(
|
||||
color: selectStatus
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
fontSize: Theme.of(context).textTheme.labelSmall?.fontSize),
|
||||
child: Ink(
|
||||
child: InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon!.icon!,
|
||||
color: selectStatus
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).colorScheme.outline),
|
||||
const SizedBox(height: 2),
|
||||
AnimatedOpacity(
|
||||
opacity: loadingStatus! ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Text(
|
||||
text!,
|
||||
style: TextStyle(
|
||||
color: selectStatus
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelSmall?.fontSize),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pilipala/common/skeleton/video_card_h.dart';
|
||||
import 'package:pilipala/common/widgets/video_card_h.dart';
|
||||
import 'package:pilipala/common/widgets/video_card_v.dart';
|
||||
import './controller.dart';
|
||||
|
||||
class RelatedVideoPanel extends StatefulWidget {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||
import 'package:pilipala/models/video/reply/item.dart';
|
||||
@ -289,45 +290,46 @@ class ReplyItemRow extends StatelessWidget {
|
||||
);
|
||||
} else {
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
8,
|
||||
index == 0 && (extraRow == 1 || replies!.length > 1)
|
||||
? 8
|
||||
: 5,
|
||||
8,
|
||||
5),
|
||||
child: Text.rich(
|
||||
overflow: extraRow == 1
|
||||
? TextOverflow.ellipsis
|
||||
: TextOverflow.visible,
|
||||
maxLines: extraRow == 1 ? 2 : null,
|
||||
TextSpan(
|
||||
children: [
|
||||
if (replies![index].isUp)
|
||||
WidgetSpan(
|
||||
child: UpTag(),
|
||||
),
|
||||
TextSpan(
|
||||
text: replies![index].member.uname + ' ',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => {
|
||||
print('跳转至用户主页'),
|
||||
},
|
||||
onTap: () {},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
8,
|
||||
index == 0 && (extraRow == 1 || replies!.length > 1)
|
||||
? 8
|
||||
: 5,
|
||||
8,
|
||||
5),
|
||||
child: Text.rich(
|
||||
overflow: extraRow == 1
|
||||
? TextOverflow.ellipsis
|
||||
: TextOverflow.visible,
|
||||
maxLines: extraRow == 1 ? 2 : null,
|
||||
TextSpan(
|
||||
children: [
|
||||
if (replies![index].isUp)
|
||||
WidgetSpan(
|
||||
child: UpTag(),
|
||||
),
|
||||
buildContent(context, replies![index].content),
|
||||
],
|
||||
),
|
||||
TextSpan(
|
||||
text: replies![index].member.uname + ' ',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => {
|
||||
print('跳转至用户主页'),
|
||||
},
|
||||
),
|
||||
buildContent(context, replies![index].content),
|
||||
],
|
||||
),
|
||||
));
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -382,6 +384,7 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
if (content.emote.isEmpty &&
|
||||
content.atNameToMid.isEmpty &&
|
||||
content.jumpUrl.isEmpty &&
|
||||
content.vote.isEmpty &&
|
||||
content.pictures.isEmpty) {
|
||||
return TextSpan(text: content.message);
|
||||
}
|
||||
@ -416,7 +419,7 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
String matchMember = str;
|
||||
if (content.atNameToMid.isNotEmpty) {
|
||||
matchMember = str.splitMapJoin(
|
||||
RegExp(r"@.*:"),
|
||||
RegExp(r"@.*( |:)"),
|
||||
onMatch: (Match match) {
|
||||
if (match[0] != null) {
|
||||
content.atNameToMid.forEach((key, value) {
|
||||
@ -455,7 +458,6 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
RegExp("(?:${urlKeys.join("|")})"),
|
||||
onMatch: (Match match) {
|
||||
String matchStr = match[0]!;
|
||||
// spanChilds.add(TextSpan(text: matchStr));
|
||||
spanChilds.add(
|
||||
TextSpan(
|
||||
text: content.jumpUrl[matchStr]['title'],
|
||||
@ -468,6 +470,16 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
},
|
||||
),
|
||||
);
|
||||
spanChilds.add(
|
||||
WidgetSpan(
|
||||
child: Icon(
|
||||
FontAwesomeIcons.magnifyingGlass,
|
||||
size: 9,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
alignment: PlaceholderAlignment.top,
|
||||
),
|
||||
);
|
||||
return '';
|
||||
},
|
||||
onNonMatch: (String str) {
|
||||
@ -477,6 +489,29 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
);
|
||||
}
|
||||
|
||||
str = matchUrl.splitMapJoin(
|
||||
RegExp(r"\d{1,2}:\d{1,2}"),
|
||||
onMatch: (Match match) {
|
||||
String matchStr = match[0]!;
|
||||
spanChilds.add(
|
||||
TextSpan(
|
||||
text: ' $matchStr ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => {
|
||||
print('time 点击'),
|
||||
},
|
||||
),
|
||||
);
|
||||
return '';
|
||||
},
|
||||
onNonMatch: (str) {
|
||||
return str;
|
||||
},
|
||||
);
|
||||
|
||||
if (content.atNameToMid.isEmpty && content.jumpUrl.isEmpty) {
|
||||
spanChilds.add(TextSpan(text: str));
|
||||
}
|
||||
@ -486,66 +521,98 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
|
||||
// 图片渲染
|
||||
if (content.pictures.isNotEmpty) {
|
||||
List<Widget> list = [];
|
||||
List picList = [];
|
||||
int len = content.pictures.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
picList.add(content.pictures[i]['img_src']);
|
||||
list.add(
|
||||
LayoutBuilder(
|
||||
builder: (context, BoxConstraints box) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Get.toNamed('/preview',
|
||||
arguments: {'initialPage': i, 'imgList': picList});
|
||||
},
|
||||
child: NetworkImgLayer(
|
||||
src: content.pictures[i]['img_src'],
|
||||
width: box.maxWidth,
|
||||
height: box.maxWidth,
|
||||
),
|
||||
);
|
||||
},
|
||||
if (len == 1) {
|
||||
Map pictureItem = content.pictures.first;
|
||||
picList.add(pictureItem['img_src']);
|
||||
spanChilds.add(const TextSpan(text: '\n'));
|
||||
spanChilds.add(
|
||||
WidgetSpan(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, BoxConstraints box) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Get.toNamed('/preview',
|
||||
arguments: {'initialPage': 0, 'imgList': picList});
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 4),
|
||||
child: NetworkImgLayer(
|
||||
src: pictureItem['img_src'],
|
||||
width: box.maxWidth / 2,
|
||||
height: box.maxWidth *
|
||||
0.5 *
|
||||
pictureItem['img_height'] /
|
||||
pictureItem['img_width'],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
spanChilds.add(
|
||||
WidgetSpan(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, BoxConstraints box) {
|
||||
double maxWidth = box.maxWidth;
|
||||
double crossCount = len < 3 ? 2 : 3;
|
||||
double height = maxWidth /
|
||||
crossCount *
|
||||
(len % crossCount == 0
|
||||
? len ~/ crossCount
|
||||
: len ~/ crossCount + 1) +
|
||||
6;
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(top: 6),
|
||||
height: height,
|
||||
child: GridView(
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
// 子Item排列规则
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
//横轴元素个数
|
||||
crossAxisCount: crossCount.toInt(),
|
||||
//纵轴间距
|
||||
mainAxisSpacing: 4.0,
|
||||
//横轴间距
|
||||
crossAxisSpacing: 4.0,
|
||||
//子组件宽高长度比例
|
||||
// childAspectRatio: 1,
|
||||
if (len > 1) {
|
||||
List<Widget> list = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
picList.add(content.pictures[i]['img_src']);
|
||||
list.add(
|
||||
LayoutBuilder(
|
||||
builder: (context, BoxConstraints box) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Get.toNamed('/preview',
|
||||
arguments: {'initialPage': i, 'imgList': picList});
|
||||
},
|
||||
child: NetworkImgLayer(
|
||||
src: content.pictures[i]['img_src'],
|
||||
width: box.maxWidth,
|
||||
height: box.maxWidth,
|
||||
),
|
||||
//GridView中使用的子Widegt
|
||||
children: list,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
spanChilds.add(
|
||||
WidgetSpan(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, BoxConstraints box) {
|
||||
double maxWidth = box.maxWidth;
|
||||
double crossCount = len < 3 ? 2 : 3;
|
||||
double height = maxWidth /
|
||||
crossCount *
|
||||
(len % crossCount == 0
|
||||
? len ~/ crossCount
|
||||
: len ~/ crossCount + 1) +
|
||||
6;
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(top: 6),
|
||||
height: height,
|
||||
child: GridView(
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
// 子Item排列规则
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
//横轴元素个数
|
||||
crossAxisCount: crossCount.toInt(),
|
||||
//纵轴间距
|
||||
mainAxisSpacing: 4.0,
|
||||
//横轴间距
|
||||
crossAxisSpacing: 4.0,
|
||||
//子组件宽高长度比例
|
||||
// childAspectRatio: 1,
|
||||
),
|
||||
//GridView中使用的子Widegt
|
||||
children: list,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
// spanChilds.add(TextSpan(text: matchMember));
|
||||
return TextSpan(children: spanChilds);
|
||||
@ -554,24 +621,25 @@ InlineSpan buildContent(BuildContext context, content) {
|
||||
class UpTag extends StatelessWidget {
|
||||
String? tagText;
|
||||
UpTag({super.key, this.tagText = 'UP'});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color primary = Theme.of(context).colorScheme.primary;
|
||||
return Container(
|
||||
width: tagText == 'UP' ? 28 : 38,
|
||||
height: tagText == 'UP' ? 17 : 19,
|
||||
width: tagText == 'UP' ? 25 : 32,
|
||||
height: tagText == 'UP' ? 16 : 18,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
// color: Theme.of(context).colorScheme.primary,
|
||||
border: Border.all(color: Theme.of(context).colorScheme.primary)),
|
||||
color: tagText == 'UP' ? primary : null,
|
||||
border: Border.all(color: primary)),
|
||||
margin: const EdgeInsets.only(right: 4),
|
||||
// padding: const EdgeInsets.symmetric(vertical: 0.5, horizontal: 4),
|
||||
child: Center(
|
||||
child: Text(
|
||||
tagText!,
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontSize: 10,
|
||||
color: tagText == 'UP'
|
||||
? Theme.of(context).colorScheme.onPrimary
|
||||
: primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -272,6 +272,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
font_awesome_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: font_awesome_flutter
|
||||
sha256: "959ef4add147753f990b4a7c6cccb746d5792dbdc81b1cde99e62e7edb31b206"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.4.0"
|
||||
get:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -65,6 +65,7 @@ dependencies:
|
||||
flutter_inappwebview: 5.4.4
|
||||
|
||||
extended_nested_scroll_view: ^6.0.0
|
||||
font_awesome_flutter: ^10.4.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -106,6 +107,9 @@ flutter:
|
||||
- family: fansCard
|
||||
fonts:
|
||||
- asset: assets/fonts/fansCard.ttf
|
||||
- family: ArchivoNarrow
|
||||
fonts:
|
||||
- asset: assets/fonts/ArchivoNarrow-BoldItalic.ttf
|
||||
|
||||
|
||||
# For details regarding fonts from package dependencies,
|
||||
|
Reference in New Issue
Block a user