reason

显示我的作品

......@@ -3,21 +3,33 @@ import 'package:Parlando/routers/i_router.dart';
import 'page/account_edit_page.dart';
import 'page/account_page.dart';
import 'page/work_player.dart';
class AccountRouter implements IRouterProvider{
class AccountRouter implements IRouterProvider {
static String accountPage = '/account';
static String accountEditPage = '/account/edit';
static String workPlayer = '/account/work/player';
@override
void initRouter(FluroRouter router) {
router.define(accountPage, handler: Handler(handlerFunc: (_, __) {
return const AccountPage(isSelfPage: true,);
return const AccountPage(
isSelfPage: true,
);
}));
router.define(accountEditPage, handler: Handler(handlerFunc: (_, __) {
return AccountEditPage();
}));
router.define(
workPlayer,
handler: Handler(
handlerFunc: (_, Map<String, List<String>> params) {
String? id = params['id']?.first;
return WorkPlayer(
id: int.parse(id!),
);
},
),
);
}
}
......
import 'dart:convert';
import 'package:Parlando/generated/json/base/json_field.dart';
import 'package:Parlando/generated/json/video_entity.g.dart';
@JsonSerializable()
class VideoEntity {
String? status;
int? code;
String? message;
VideoData? data;
VideoError? error;
VideoEntity();
factory VideoEntity.fromJson(Map<String, dynamic> json) =>
$VideoEntityFromJson(json);
Map<String, dynamic> toJson() => $VideoEntityToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
@JsonSerializable()
class VideoData {
int? id;
@JSONField(name: "user_id")
int? userId;
String? title;
String? content;
String? url;
int? type;
String? duration;
String? size;
@JSONField(name: "poem_id")
int? poemId;
@JSONField(name: "temp_id")
int? tempId;
String? thumbnail;
dynamic bgm;
String? praise;
String? view;
String? collect;
String? share;
String? comment;
String? state;
@JSONField(name: "is_publish")
String? isPublish;
@JSONField(name: "is_check")
String? isCheck;
@JSONField(name: "created_at")
String? createdAt;
@JSONField(name: "updated_at")
String? updatedAt;
VideoData();
factory VideoData.fromJson(Map<String, dynamic> json) =>
$VideoDataFromJson(json);
Map<String, dynamic> toJson() => $VideoDataToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
@JsonSerializable()
class VideoError {
VideoError();
factory VideoError.fromJson(Map<String, dynamic> json) =>
$VideoErrorFromJson(json);
Map<String, dynamic> toJson() => $VideoErrorToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
......@@ -64,7 +64,10 @@ class AccountPageState extends State<AccountPage> {
params: [],
onSuccess: (data) {
for (MyVideosData each in data!.data!) {
videos.add(_SmallVideo());
videos.add(_SmallVideo(
url: each.thumbnail!,
id: each.id!,
));
}
isLoadMyVideos = false;
setState(() {});
......@@ -255,11 +258,14 @@ class AccountPageState extends State<AccountPage> {
child: isLoadMyVideos
? const GFLoader()
: GridView(
padding: EdgeInsets.all(15.px),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //横轴三个子widget
childAspectRatio: 1.0 //宽高比为1时,子widget
),
crossAxisCount: 3, //横轴三个子widget
childAspectRatio: 1.0, //宽高比为1时,子widget
mainAxisSpacing: 5,
crossAxisSpacing: 5,
),
children: videos,
),
),
......@@ -390,62 +396,14 @@ class _UserTag extends StatelessWidget {
}
}
class _UserVideoTable extends StatelessWidget {
const _UserVideoTable({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
color: ColorPlate.white,
padding: EdgeInsets.symmetric(
vertical: 12.px,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_PointSelectTextButton(
true,
ParlandoLocalizations.of(context)
.onePoemBottomNavigationBarItemTitle,
),
_PointSelectTextButton(
false,
ParlandoLocalizations.of(context)
.timelineBottomNavigationBarItemTitle),
_PointSelectTextButton(
false,
ParlandoLocalizations.of(context)
.categoryBottomNavigationBarItemTitle),
],
),
),
Row(
children: const [
_SmallVideo(),
_SmallVideo(),
_SmallVideo(),
],
),
Row(
children: const [
_SmallVideo(),
_SmallVideo(),
_SmallVideo(),
],
),
],
);
}
}
class _SmallVideo extends StatelessWidget {
final String url;
final int id;
const _SmallVideo({
Key? key,
required this.url,
required this.id,
}) : super(key: key);
@override
......@@ -455,27 +413,16 @@ class _SmallVideo extends StatelessWidget {
onTap: () {
NavigatorUtils.push(
context,
'${PoemRouter.poemDetailPage}?id=100',
'${AccountRouter.workPlayer}?id=$id',
);
},
child: AspectRatio(
aspectRatio: 3.px / 4.0,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/poem/poem_background.png"),
fit: BoxFit.fill,
),
),
alignment: Alignment.center,
child: Text(
'一言',
style: TextStyle(
color: Colors.black54,
fontSize: 18.px,
fontWeight: FontWeight.w900,
),
),
child: CachedNetworkImage(
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(),
errorWidget: (context, url, error) => const Icon(Icons.error),
imageUrl: url,
),
),
),
......@@ -483,55 +430,16 @@ class _SmallVideo extends StatelessWidget {
}
}
class _PointSelectTextButton extends StatelessWidget {
final bool isSelect;
final String title;
final Function? onTap;
const _PointSelectTextButton(this.isSelect,
this.title, {
Key? key,
this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
isSelect
? Container(
width: 6.px,
height: 6.px,
decoration: BoxDecoration(
color: ColorPlate.orange,
borderRadius: BorderRadius.circular(3),
),
)
: Container(),
Container(
padding: const EdgeInsets.only(left: 2),
child: Text(
title,
style: isSelect ? StandardTextStyle.big : StandardTextStyle.small,
),
)
],
),
);
}
}
class TextGroup extends StatelessWidget {
final String title, tag;
final Color? color;
const TextGroup(this.title,
this.tag, {
Key? key,
this.color,
}) : super(key: key);
const TextGroup(
this.title,
this.tag, {
Key? key,
this.color,
}) : super(key: key);
@override
Widget build(BuildContext context) {
......
import 'package:Parlando/account/models/video_entity.dart';
import 'package:Parlando/net/dio_utils.dart';
import 'package:Parlando/net/http_api.dart';
import 'package:Parlando/util/toast_utils.dart';
import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';
import 'package:Parlando/widgets/my_app_bar.dart';
class WorkPlayer extends StatefulWidget {
final int id;
const WorkPlayer({
Key? key,
required this.id,
}) : super(key: key);
@override
WorkPlayerState createState() => WorkPlayerState();
}
class WorkPlayerState extends State<WorkPlayer> {
final FijkPlayer player = FijkPlayer();
bool isLoading = false;
@override
void initState() {
super.initState();
isLoading = true;
DioUtils.instance.asyncRequestNetwork<VideoEntity>(
Method.get,
'${HttpApi.myVideos}/${widget.id}',
params: [],
onSuccess: (data) {
isLoading = false;
player.setDataSource(
data!.data!.url!,
autoPlay: true,
);
player.setLoop(0);
},
onError: (code, msg) {
isLoading = false;
Toast.show("获取数据失败,请稍后再试...");
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(
homeMenuHeader: Container(
alignment: Alignment.center,
child: const Text(
"我的临境",
style: TextStyle(
color: Colors.white,
),
),
),
),
body: Stack(
children: [
FijkView(
height: MediaQuery.of(context).size.height,
player: player,
fit: FijkFit.fill,
),
],
));
}
@override
void dispose() {
player.release();
super.dispose();
}
}
......@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:Parlando/account/models/my_videos_entity.dart';
import 'package:Parlando/account/models/upload_avatar_entity.dart';
import 'package:Parlando/account/models/user_entity.dart';
import 'package:Parlando/account/models/video_entity.dart';
import 'package:Parlando/category/models/category_entity.dart';
import 'package:Parlando/category/models/category_item_entity.dart';
import 'package:Parlando/home/models/home_entity.dart';
......@@ -31,6 +32,9 @@ class JsonConvert {
(UserEntity).toString(): UserEntity.fromJson,
(UserData).toString(): UserData.fromJson,
(UserError).toString(): UserError.fromJson,
(VideoEntity).toString(): VideoEntity.fromJson,
(VideoData).toString(): VideoData.fromJson,
(VideoError).toString(): VideoError.fromJson,
(CategoryEntity).toString(): CategoryEntity.fromJson,
(CategoryData).toString(): CategoryData.fromJson,
(CategoryDataData).toString(): CategoryDataData.fromJson,
......@@ -186,6 +190,21 @@ class JsonConvert {
.map<UserError>((Map<String, dynamic> e) => UserError.fromJson(e))
.toList() as M;
}
if (<VideoEntity>[] is M) {
return data
.map<VideoEntity>((Map<String, dynamic> e) => VideoEntity.fromJson(e))
.toList() as M;
}
if (<VideoData>[] is M) {
return data
.map<VideoData>((Map<String, dynamic> e) => VideoData.fromJson(e))
.toList() as M;
}
if (<VideoError>[] is M) {
return data
.map<VideoError>((Map<String, dynamic> e) => VideoError.fromJson(e))
.toList() as M;
}
if (<CategoryEntity>[] is M) {
return data
.map<CategoryEntity>(
......
......@@ -166,4 +166,4 @@ MyVideosError $MyVideosErrorFromJson(Map<String, dynamic> json) {
Map<String, dynamic> $MyVideosErrorToJson(MyVideosError entity) {
final Map<String, dynamic> data = <String, dynamic>{};
return data;
}
}
\ No newline at end of file
......
import 'package:Parlando/generated/json/base/json_convert_content.dart';
import 'package:Parlando/account/models/video_entity.dart';
VideoEntity $VideoEntityFromJson(Map<String, dynamic> json) {
final VideoEntity videoEntity = VideoEntity();
final String? status = jsonConvert.convert<String>(json['status']);
if (status != null) {
videoEntity.status = status;
}
final int? code = jsonConvert.convert<int>(json['code']);
if (code != null) {
videoEntity.code = code;
}
final String? message = jsonConvert.convert<String>(json['message']);
if (message != null) {
videoEntity.message = message;
}
final VideoData? data = jsonConvert.convert<VideoData>(json['data']);
if (data != null) {
videoEntity.data = data;
}
final VideoError? error = jsonConvert.convert<VideoError>(json['error']);
if (error != null) {
videoEntity.error = error;
}
return videoEntity;
}
Map<String, dynamic> $VideoEntityToJson(VideoEntity entity) {
final Map<String, dynamic> data = <String, dynamic>{};
data['status'] = entity.status;
data['code'] = entity.code;
data['message'] = entity.message;
data['data'] = entity.data?.toJson();
data['error'] = entity.error?.toJson();
return data;
}
VideoData $VideoDataFromJson(Map<String, dynamic> json) {
final VideoData videoData = VideoData();
final int? id = jsonConvert.convert<int>(json['id']);
if (id != null) {
videoData.id = id;
}
final int? userId = jsonConvert.convert<int>(json['user_id']);
if (userId != null) {
videoData.userId = userId;
}
final String? title = jsonConvert.convert<String>(json['title']);
if (title != null) {
videoData.title = title;
}
final String? content = jsonConvert.convert<String>(json['content']);
if (content != null) {
videoData.content = content;
}
final String? url = jsonConvert.convert<String>(json['url']);
if (url != null) {
videoData.url = url;
}
final int? type = jsonConvert.convert<int>(json['type']);
if (type != null) {
videoData.type = type;
}
final String? duration = jsonConvert.convert<String>(json['duration']);
if (duration != null) {
videoData.duration = duration;
}
final String? size = jsonConvert.convert<String>(json['size']);
if (size != null) {
videoData.size = size;
}
final int? poemId = jsonConvert.convert<int>(json['poem_id']);
if (poemId != null) {
videoData.poemId = poemId;
}
final int? tempId = jsonConvert.convert<int>(json['temp_id']);
if (tempId != null) {
videoData.tempId = tempId;
}
final String? thumbnail = jsonConvert.convert<String>(json['thumbnail']);
if (thumbnail != null) {
videoData.thumbnail = thumbnail;
}
final dynamic? bgm = jsonConvert.convert<dynamic>(json['bgm']);
if (bgm != null) {
videoData.bgm = bgm;
}
final String? praise = jsonConvert.convert<String>(json['praise']);
if (praise != null) {
videoData.praise = praise;
}
final String? view = jsonConvert.convert<String>(json['view']);
if (view != null) {
videoData.view = view;
}
final String? collect = jsonConvert.convert<String>(json['collect']);
if (collect != null) {
videoData.collect = collect;
}
final String? share = jsonConvert.convert<String>(json['share']);
if (share != null) {
videoData.share = share;
}
final String? comment = jsonConvert.convert<String>(json['comment']);
if (comment != null) {
videoData.comment = comment;
}
final String? state = jsonConvert.convert<String>(json['state']);
if (state != null) {
videoData.state = state;
}
final String? isPublish = jsonConvert.convert<String>(json['is_publish']);
if (isPublish != null) {
videoData.isPublish = isPublish;
}
final String? isCheck = jsonConvert.convert<String>(json['is_check']);
if (isCheck != null) {
videoData.isCheck = isCheck;
}
final String? createdAt = jsonConvert.convert<String>(json['created_at']);
if (createdAt != null) {
videoData.createdAt = createdAt;
}
final String? updatedAt = jsonConvert.convert<String>(json['updated_at']);
if (updatedAt != null) {
videoData.updatedAt = updatedAt;
}
return videoData;
}
Map<String, dynamic> $VideoDataToJson(VideoData entity) {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = entity.id;
data['user_id'] = entity.userId;
data['title'] = entity.title;
data['content'] = entity.content;
data['url'] = entity.url;
data['type'] = entity.type;
data['duration'] = entity.duration;
data['size'] = entity.size;
data['poem_id'] = entity.poemId;
data['temp_id'] = entity.tempId;
data['thumbnail'] = entity.thumbnail;
data['bgm'] = entity.bgm;
data['praise'] = entity.praise;
data['view'] = entity.view;
data['collect'] = entity.collect;
data['share'] = entity.share;
data['comment'] = entity.comment;
data['state'] = entity.state;
data['is_publish'] = entity.isPublish;
data['is_check'] = entity.isCheck;
data['created_at'] = entity.createdAt;
data['updated_at'] = entity.updatedAt;
return data;
}
VideoError $VideoErrorFromJson(Map<String, dynamic> json) {
final VideoError videoError = VideoError();
return videoError;
}
Map<String, dynamic> $VideoErrorToJson(VideoError entity) {
final Map<String, dynamic> data = <String, dynamic>{};
return data;
}
......@@ -11,6 +11,9 @@ class HttpApi {
static const String user = 'user';
static const String home = 'home';
static const String myVideos = '/my/videos';
static const String praise = '/praise';
static const String addView = '/addview';
static const String collect = '/collect';
static const String search = 'search/repositories';
static const String subscriptions = 'users/simplezhli/subscriptions';
static const String upload = 'uuc/upload-inco';
......
......@@ -51,6 +51,9 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
String currentPoemId = '';
String currentPoemType = '';
bool isFav = false;
bool isPraise = false;
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
if (state != AppLifecycleState.resumed) {
......@@ -81,11 +84,14 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
for (HomeData data in data!.data!) {
videoDataList.add(
UserVideo(
id: data.id!,
image: '',
url: data.url!,
desc: data.content,
poemId: '${data.poemId}',
poemType: '${data.type}',
isPraise: data.praise == '1' ? true : false,
isCollect: data.collect == '1' ? true : false,
),
);
}
......@@ -202,6 +208,17 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
_videoListController.currentPlayer.videoInfo!.poemId;
currentPoemType =
_videoListController.currentPlayer.videoInfo!.poemType;
String url =
'${HttpApi.addView}/${_videoListController.currentPlayer.videoInfo!.id}';
// 统计观看数
DioUtils.instance.asyncRequestNetwork(
Method.get,
url,
params: [],
onSuccess: (data) {},
onError: (code, msg) {},
);
},
key: const Key('home'),
physics: const QuickerScrollPhysics(),
......@@ -214,11 +231,35 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
var data = player.videoInfo!;
// 右侧按钮列
Widget buttons = TikTokButtonColumn(
isFavorite: false,
isPraise: _videoListController
.currentPlayer.videoInfo!.isPraise,
isCollect: _videoListController
.currentPlayer.videoInfo!.isCollect,
onAvatar: () {
tkController.animateToPage(TikTokPagePosition.right);
},
onFavorite: () {},
onPraise: () {
String url =
'${HttpApi.praise}/${_videoListController.currentPlayer.videoInfo!.id}';
DioUtils.instance.asyncRequestNetwork(
Method.post,
url,
params: [],
onSuccess: (data) {},
onError: (code, msg) {},
);
},
onCollect: () {
String url =
'${HttpApi.collect}/${_videoListController.currentPlayer.videoInfo!.id}';
DioUtils.instance.asyncRequestNetwork(
Method.post,
url,
params: [],
onSuccess: (data) {},
onError: (code, msg) {},
);
},
onShare: () {},
);
Widget poem = TikTokVidePoem(
......@@ -276,7 +317,6 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
onPress: () {
String url =
'${PoemRouter.poemRecordVideoPage}?id=$currentPoemId&type=$currentPoemType';
print("===========================" + url);
eventBus.fire(TransEvent());
NavigatorUtils.push(
context,
......
......@@ -8,18 +8,24 @@ var videoList = [
];
class UserVideo {
final int id;
final String url;
final String image;
final String? desc;
final String poemId;
final String poemType;
final bool isPraise;
final bool isCollect;
UserVideo({
required this.id,
required this.url,
required this.image,
this.desc,
required this.poemId,
required this.poemType,
required this.isPraise,
required this.isCollect,
});
@override
......
......@@ -6,18 +6,21 @@ import 'package:Parlando/extension/int_extension.dart';
class TikTokButtonColumn extends StatelessWidget {
final double? bottomPadding;
final bool isFavorite;
final Function? onFavorite;
final Function? onComment;
final bool isPraise;
final bool isCollect;
final Function? onPraise;
final Function? onCollect;
final Function? onShare;
final Function? onAvatar;
const TikTokButtonColumn({
Key? key,
this.bottomPadding,
this.onFavorite,
this.onComment,
this.onPraise,
this.onCollect,
this.onShare,
this.isFavorite = false,
this.isPraise = false,
this.isCollect = false,
this.onAvatar,
}) : super(key: key);
......@@ -34,13 +37,12 @@ class TikTokButtonColumn extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FavoriteIcon(
onFavorite: onFavorite,
isFavorite: isFavorite,
onFavorite: onPraise,
isFavorite: isPraise,
),
_IconButton(
icon: IconToText(Icons.star_border, size: 20.px),
text: '收藏',
onTap: onComment,
CollectIcon(
onCollect: onCollect,
isCollect: isCollect,
),
_IconButton(
icon: IconToText(Icons.share, size: 20.px),
......@@ -70,12 +72,35 @@ class FavoriteIcon extends StatelessWidget {
size: 20,
color: isFavorite! ? ColorPlate.red : null,
),
text: '喜爱',
text: '点赞',
onTap: onFavorite,
);
}
}
class CollectIcon extends StatelessWidget {
const CollectIcon({
Key? key,
required this.onCollect,
this.isCollect,
}) : super(key: key);
final bool? isCollect;
final Function? onCollect;
@override
Widget build(BuildContext context) {
return _IconButton(
icon: IconToText(
Icons.star_border_outlined,
size: 20,
color: isCollect! ? ColorPlate.red : null,
),
text: '收藏',
onTap: onCollect,
);
}
}
/// 把IconData转换为文字,使其可以使用文字样式
class IconToText extends StatelessWidget {
final IconData? icon;
......@@ -90,6 +115,7 @@ class IconToText extends StatelessWidget {
this.size,
this.color,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
......@@ -109,6 +135,7 @@ class _IconButton extends StatelessWidget {
final Widget? icon;
final String? text;
final Function? onTap;
const _IconButton({
Key? key,
this.icon,
......@@ -130,8 +157,8 @@ class _IconButton extends StatelessWidget {
Widget body = Column(
children: <Widget>[
Tapped(
child: icon ?? Container(),
onTap: onTap,
child: icon ?? Container(),
),
Container(height: 2.px),
Text(
......@@ -146,8 +173,8 @@ class _IconButton extends StatelessWidget {
return Container(
padding: EdgeInsets.symmetric(vertical: 10.px),
child: DefaultTextStyle(
child: body,
style: shadowStyle,
child: body,
),
);
}
......