Showing
11 changed files
with
489 additions
and
143 deletions
| ... | @@ -3,21 +3,33 @@ import 'package:Parlando/routers/i_router.dart'; | ... | @@ -3,21 +3,33 @@ import 'package:Parlando/routers/i_router.dart'; |
| 3 | 3 | ||
| 4 | import 'page/account_edit_page.dart'; | 4 | import 'page/account_edit_page.dart'; |
| 5 | import 'page/account_page.dart'; | 5 | import 'page/account_page.dart'; |
| 6 | +import 'page/work_player.dart'; | ||
| 6 | 7 | ||
| 7 | - | 8 | +class AccountRouter implements IRouterProvider { |
| 8 | -class AccountRouter implements IRouterProvider{ | ||
| 9 | - | ||
| 10 | static String accountPage = '/account'; | 9 | static String accountPage = '/account'; |
| 11 | static String accountEditPage = '/account/edit'; | 10 | static String accountEditPage = '/account/edit'; |
| 11 | + static String workPlayer = '/account/work/player'; | ||
| 12 | 12 | ||
| 13 | @override | 13 | @override |
| 14 | void initRouter(FluroRouter router) { | 14 | void initRouter(FluroRouter router) { |
| 15 | router.define(accountPage, handler: Handler(handlerFunc: (_, __) { | 15 | router.define(accountPage, handler: Handler(handlerFunc: (_, __) { |
| 16 | - return const AccountPage(isSelfPage: true,); | 16 | + return const AccountPage( |
| 17 | + isSelfPage: true, | ||
| 18 | + ); | ||
| 17 | })); | 19 | })); |
| 18 | router.define(accountEditPage, handler: Handler(handlerFunc: (_, __) { | 20 | router.define(accountEditPage, handler: Handler(handlerFunc: (_, __) { |
| 19 | return AccountEditPage(); | 21 | return AccountEditPage(); |
| 20 | })); | 22 | })); |
| 23 | + router.define( | ||
| 24 | + workPlayer, | ||
| 25 | + handler: Handler( | ||
| 26 | + handlerFunc: (_, Map<String, List<String>> params) { | ||
| 27 | + String? id = params['id']?.first; | ||
| 28 | + return WorkPlayer( | ||
| 29 | + id: int.parse(id!), | ||
| 30 | + ); | ||
| 31 | + }, | ||
| 32 | + ), | ||
| 33 | + ); | ||
| 21 | } | 34 | } |
| 22 | - | ||
| 23 | } | 35 | } | ... | ... |
lib/account/models/video_entity.dart
0 → 100644
| 1 | +import 'dart:convert'; | ||
| 2 | +import 'package:Parlando/generated/json/base/json_field.dart'; | ||
| 3 | +import 'package:Parlando/generated/json/video_entity.g.dart'; | ||
| 4 | + | ||
| 5 | +@JsonSerializable() | ||
| 6 | +class VideoEntity { | ||
| 7 | + String? status; | ||
| 8 | + int? code; | ||
| 9 | + String? message; | ||
| 10 | + VideoData? data; | ||
| 11 | + VideoError? error; | ||
| 12 | + | ||
| 13 | + VideoEntity(); | ||
| 14 | + | ||
| 15 | + factory VideoEntity.fromJson(Map<String, dynamic> json) => | ||
| 16 | + $VideoEntityFromJson(json); | ||
| 17 | + | ||
| 18 | + Map<String, dynamic> toJson() => $VideoEntityToJson(this); | ||
| 19 | + | ||
| 20 | + @override | ||
| 21 | + String toString() { | ||
| 22 | + return jsonEncode(this); | ||
| 23 | + } | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +@JsonSerializable() | ||
| 27 | +class VideoData { | ||
| 28 | + int? id; | ||
| 29 | + @JSONField(name: "user_id") | ||
| 30 | + int? userId; | ||
| 31 | + String? title; | ||
| 32 | + String? content; | ||
| 33 | + String? url; | ||
| 34 | + int? type; | ||
| 35 | + String? duration; | ||
| 36 | + String? size; | ||
| 37 | + @JSONField(name: "poem_id") | ||
| 38 | + int? poemId; | ||
| 39 | + @JSONField(name: "temp_id") | ||
| 40 | + int? tempId; | ||
| 41 | + String? thumbnail; | ||
| 42 | + dynamic bgm; | ||
| 43 | + String? praise; | ||
| 44 | + String? view; | ||
| 45 | + String? collect; | ||
| 46 | + String? share; | ||
| 47 | + String? comment; | ||
| 48 | + String? state; | ||
| 49 | + @JSONField(name: "is_publish") | ||
| 50 | + String? isPublish; | ||
| 51 | + @JSONField(name: "is_check") | ||
| 52 | + String? isCheck; | ||
| 53 | + @JSONField(name: "created_at") | ||
| 54 | + String? createdAt; | ||
| 55 | + @JSONField(name: "updated_at") | ||
| 56 | + String? updatedAt; | ||
| 57 | + | ||
| 58 | + VideoData(); | ||
| 59 | + | ||
| 60 | + factory VideoData.fromJson(Map<String, dynamic> json) => | ||
| 61 | + $VideoDataFromJson(json); | ||
| 62 | + | ||
| 63 | + Map<String, dynamic> toJson() => $VideoDataToJson(this); | ||
| 64 | + | ||
| 65 | + @override | ||
| 66 | + String toString() { | ||
| 67 | + return jsonEncode(this); | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +@JsonSerializable() | ||
| 72 | +class VideoError { | ||
| 73 | + VideoError(); | ||
| 74 | + | ||
| 75 | + factory VideoError.fromJson(Map<String, dynamic> json) => | ||
| 76 | + $VideoErrorFromJson(json); | ||
| 77 | + | ||
| 78 | + Map<String, dynamic> toJson() => $VideoErrorToJson(this); | ||
| 79 | + | ||
| 80 | + @override | ||
| 81 | + String toString() { | ||
| 82 | + return jsonEncode(this); | ||
| 83 | + } | ||
| 84 | +} |
| ... | @@ -64,7 +64,10 @@ class AccountPageState extends State<AccountPage> { | ... | @@ -64,7 +64,10 @@ class AccountPageState extends State<AccountPage> { |
| 64 | params: [], | 64 | params: [], |
| 65 | onSuccess: (data) { | 65 | onSuccess: (data) { |
| 66 | for (MyVideosData each in data!.data!) { | 66 | for (MyVideosData each in data!.data!) { |
| 67 | - videos.add(_SmallVideo()); | 67 | + videos.add(_SmallVideo( |
| 68 | + url: each.thumbnail!, | ||
| 69 | + id: each.id!, | ||
| 70 | + )); | ||
| 68 | } | 71 | } |
| 69 | isLoadMyVideos = false; | 72 | isLoadMyVideos = false; |
| 70 | setState(() {}); | 73 | setState(() {}); |
| ... | @@ -255,11 +258,14 @@ class AccountPageState extends State<AccountPage> { | ... | @@ -255,11 +258,14 @@ class AccountPageState extends State<AccountPage> { |
| 255 | child: isLoadMyVideos | 258 | child: isLoadMyVideos |
| 256 | ? const GFLoader() | 259 | ? const GFLoader() |
| 257 | : GridView( | 260 | : GridView( |
| 261 | + padding: EdgeInsets.all(15.px), | ||
| 258 | gridDelegate: | 262 | gridDelegate: |
| 259 | const SliverGridDelegateWithFixedCrossAxisCount( | 263 | const SliverGridDelegateWithFixedCrossAxisCount( |
| 260 | - crossAxisCount: 3, //横轴三个子widget | 264 | + crossAxisCount: 3, //横轴三个子widget |
| 261 | - childAspectRatio: 1.0 //宽高比为1时,子widget | 265 | + childAspectRatio: 1.0, //宽高比为1时,子widget |
| 262 | - ), | 266 | + mainAxisSpacing: 5, |
| 267 | + crossAxisSpacing: 5, | ||
| 268 | + ), | ||
| 263 | children: videos, | 269 | children: videos, |
| 264 | ), | 270 | ), |
| 265 | ), | 271 | ), |
| ... | @@ -390,62 +396,14 @@ class _UserTag extends StatelessWidget { | ... | @@ -390,62 +396,14 @@ class _UserTag extends StatelessWidget { |
| 390 | } | 396 | } |
| 391 | } | 397 | } |
| 392 | 398 | ||
| 393 | -class _UserVideoTable extends StatelessWidget { | ||
| 394 | - const _UserVideoTable({ | ||
| 395 | - Key? key, | ||
| 396 | - }) : super(key: key); | ||
| 397 | - | ||
| 398 | - @override | ||
| 399 | - Widget build(BuildContext context) { | ||
| 400 | - return Column( | ||
| 401 | - children: <Widget>[ | ||
| 402 | - Container( | ||
| 403 | - color: ColorPlate.white, | ||
| 404 | - padding: EdgeInsets.symmetric( | ||
| 405 | - vertical: 12.px, | ||
| 406 | - ), | ||
| 407 | - child: Row( | ||
| 408 | - mainAxisAlignment: MainAxisAlignment.center, | ||
| 409 | - crossAxisAlignment: CrossAxisAlignment.center, | ||
| 410 | - children: <Widget>[ | ||
| 411 | - _PointSelectTextButton( | ||
| 412 | - true, | ||
| 413 | - ParlandoLocalizations.of(context) | ||
| 414 | - .onePoemBottomNavigationBarItemTitle, | ||
| 415 | - ), | ||
| 416 | - _PointSelectTextButton( | ||
| 417 | - false, | ||
| 418 | - ParlandoLocalizations.of(context) | ||
| 419 | - .timelineBottomNavigationBarItemTitle), | ||
| 420 | - _PointSelectTextButton( | ||
| 421 | - false, | ||
| 422 | - ParlandoLocalizations.of(context) | ||
| 423 | - .categoryBottomNavigationBarItemTitle), | ||
| 424 | - ], | ||
| 425 | - ), | ||
| 426 | - ), | ||
| 427 | - Row( | ||
| 428 | - children: const [ | ||
| 429 | - _SmallVideo(), | ||
| 430 | - _SmallVideo(), | ||
| 431 | - _SmallVideo(), | ||
| 432 | - ], | ||
| 433 | - ), | ||
| 434 | - Row( | ||
| 435 | - children: const [ | ||
| 436 | - _SmallVideo(), | ||
| 437 | - _SmallVideo(), | ||
| 438 | - _SmallVideo(), | ||
| 439 | - ], | ||
| 440 | - ), | ||
| 441 | - ], | ||
| 442 | - ); | ||
| 443 | - } | ||
| 444 | -} | ||
| 445 | - | ||
| 446 | class _SmallVideo extends StatelessWidget { | 399 | class _SmallVideo extends StatelessWidget { |
| 400 | + final String url; | ||
| 401 | + final int id; | ||
| 402 | + | ||
| 447 | const _SmallVideo({ | 403 | const _SmallVideo({ |
| 448 | Key? key, | 404 | Key? key, |
| 405 | + required this.url, | ||
| 406 | + required this.id, | ||
| 449 | }) : super(key: key); | 407 | }) : super(key: key); |
| 450 | 408 | ||
| 451 | @override | 409 | @override |
| ... | @@ -455,27 +413,16 @@ class _SmallVideo extends StatelessWidget { | ... | @@ -455,27 +413,16 @@ class _SmallVideo extends StatelessWidget { |
| 455 | onTap: () { | 413 | onTap: () { |
| 456 | NavigatorUtils.push( | 414 | NavigatorUtils.push( |
| 457 | context, | 415 | context, |
| 458 | - '${PoemRouter.poemDetailPage}?id=100', | 416 | + '${AccountRouter.workPlayer}?id=$id', |
| 459 | ); | 417 | ); |
| 460 | }, | 418 | }, |
| 461 | child: AspectRatio( | 419 | child: AspectRatio( |
| 462 | aspectRatio: 3.px / 4.0, | 420 | aspectRatio: 3.px / 4.0, |
| 463 | - child: Container( | 421 | + child: CachedNetworkImage( |
| 464 | - decoration: const BoxDecoration( | 422 | + fit: BoxFit.cover, |
| 465 | - image: DecorationImage( | 423 | + placeholder: (context, url) => const CircularProgressIndicator(), |
| 466 | - image: AssetImage("assets/images/poem/poem_background.png"), | 424 | + errorWidget: (context, url, error) => const Icon(Icons.error), |
| 467 | - fit: BoxFit.fill, | 425 | + imageUrl: url, |
| 468 | - ), | ||
| 469 | - ), | ||
| 470 | - alignment: Alignment.center, | ||
| 471 | - child: Text( | ||
| 472 | - '一言', | ||
| 473 | - style: TextStyle( | ||
| 474 | - color: Colors.black54, | ||
| 475 | - fontSize: 18.px, | ||
| 476 | - fontWeight: FontWeight.w900, | ||
| 477 | - ), | ||
| 478 | - ), | ||
| 479 | ), | 426 | ), |
| 480 | ), | 427 | ), |
| 481 | ), | 428 | ), |
| ... | @@ -483,55 +430,16 @@ class _SmallVideo extends StatelessWidget { | ... | @@ -483,55 +430,16 @@ class _SmallVideo extends StatelessWidget { |
| 483 | } | 430 | } |
| 484 | } | 431 | } |
| 485 | 432 | ||
| 486 | -class _PointSelectTextButton extends StatelessWidget { | ||
| 487 | - final bool isSelect; | ||
| 488 | - final String title; | ||
| 489 | - final Function? onTap; | ||
| 490 | - | ||
| 491 | - const _PointSelectTextButton(this.isSelect, | ||
| 492 | - this.title, { | ||
| 493 | - Key? key, | ||
| 494 | - this.onTap, | ||
| 495 | - }) : super(key: key); | ||
| 496 | - | ||
| 497 | - @override | ||
| 498 | - Widget build(BuildContext context) { | ||
| 499 | - return Expanded( | ||
| 500 | - child: Row( | ||
| 501 | - mainAxisAlignment: MainAxisAlignment.center, | ||
| 502 | - children: <Widget>[ | ||
| 503 | - isSelect | ||
| 504 | - ? Container( | ||
| 505 | - width: 6.px, | ||
| 506 | - height: 6.px, | ||
| 507 | - decoration: BoxDecoration( | ||
| 508 | - color: ColorPlate.orange, | ||
| 509 | - borderRadius: BorderRadius.circular(3), | ||
| 510 | - ), | ||
| 511 | - ) | ||
| 512 | - : Container(), | ||
| 513 | - Container( | ||
| 514 | - padding: const EdgeInsets.only(left: 2), | ||
| 515 | - child: Text( | ||
| 516 | - title, | ||
| 517 | - style: isSelect ? StandardTextStyle.big : StandardTextStyle.small, | ||
| 518 | - ), | ||
| 519 | - ) | ||
| 520 | - ], | ||
| 521 | - ), | ||
| 522 | - ); | ||
| 523 | - } | ||
| 524 | -} | ||
| 525 | - | ||
| 526 | class TextGroup extends StatelessWidget { | 433 | class TextGroup extends StatelessWidget { |
| 527 | final String title, tag; | 434 | final String title, tag; |
| 528 | final Color? color; | 435 | final Color? color; |
| 529 | 436 | ||
| 530 | - const TextGroup(this.title, | 437 | + const TextGroup( |
| 531 | - this.tag, { | 438 | + this.title, |
| 532 | - Key? key, | 439 | + this.tag, { |
| 533 | - this.color, | 440 | + Key? key, |
| 534 | - }) : super(key: key); | 441 | + this.color, |
| 442 | + }) : super(key: key); | ||
| 535 | 443 | ||
| 536 | @override | 444 | @override |
| 537 | Widget build(BuildContext context) { | 445 | Widget build(BuildContext context) { | ... | ... |
lib/account/page/work_player.dart
0 → 100644
| 1 | +import 'package:Parlando/account/models/video_entity.dart'; | ||
| 2 | +import 'package:Parlando/net/dio_utils.dart'; | ||
| 3 | +import 'package:Parlando/net/http_api.dart'; | ||
| 4 | +import 'package:Parlando/util/toast_utils.dart'; | ||
| 5 | +import 'package:fijkplayer/fijkplayer.dart'; | ||
| 6 | +import 'package:flutter/material.dart'; | ||
| 7 | +import 'package:Parlando/widgets/my_app_bar.dart'; | ||
| 8 | + | ||
| 9 | +class WorkPlayer extends StatefulWidget { | ||
| 10 | + final int id; | ||
| 11 | + | ||
| 12 | + const WorkPlayer({ | ||
| 13 | + Key? key, | ||
| 14 | + required this.id, | ||
| 15 | + }) : super(key: key); | ||
| 16 | + | ||
| 17 | + @override | ||
| 18 | + WorkPlayerState createState() => WorkPlayerState(); | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +class WorkPlayerState extends State<WorkPlayer> { | ||
| 22 | + final FijkPlayer player = FijkPlayer(); | ||
| 23 | + | ||
| 24 | + bool isLoading = false; | ||
| 25 | + | ||
| 26 | + @override | ||
| 27 | + void initState() { | ||
| 28 | + super.initState(); | ||
| 29 | + | ||
| 30 | + isLoading = true; | ||
| 31 | + DioUtils.instance.asyncRequestNetwork<VideoEntity>( | ||
| 32 | + Method.get, | ||
| 33 | + '${HttpApi.myVideos}/${widget.id}', | ||
| 34 | + params: [], | ||
| 35 | + onSuccess: (data) { | ||
| 36 | + isLoading = false; | ||
| 37 | + player.setDataSource( | ||
| 38 | + data!.data!.url!, | ||
| 39 | + autoPlay: true, | ||
| 40 | + ); | ||
| 41 | + player.setLoop(0); | ||
| 42 | + }, | ||
| 43 | + onError: (code, msg) { | ||
| 44 | + isLoading = false; | ||
| 45 | + Toast.show("获取数据失败,请稍后再试..."); | ||
| 46 | + }, | ||
| 47 | + ); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @override | ||
| 51 | + Widget build(BuildContext context) { | ||
| 52 | + return Scaffold( | ||
| 53 | + appBar: MyAppBar( | ||
| 54 | + homeMenuHeader: Container( | ||
| 55 | + alignment: Alignment.center, | ||
| 56 | + child: const Text( | ||
| 57 | + "我的临境", | ||
| 58 | + style: TextStyle( | ||
| 59 | + color: Colors.white, | ||
| 60 | + ), | ||
| 61 | + ), | ||
| 62 | + ), | ||
| 63 | + ), | ||
| 64 | + body: Stack( | ||
| 65 | + children: [ | ||
| 66 | + FijkView( | ||
| 67 | + height: MediaQuery.of(context).size.height, | ||
| 68 | + player: player, | ||
| 69 | + fit: FijkFit.fill, | ||
| 70 | + ), | ||
| 71 | + ], | ||
| 72 | + )); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @override | ||
| 76 | + void dispose() { | ||
| 77 | + player.release(); | ||
| 78 | + super.dispose(); | ||
| 79 | + } | ||
| 80 | +} |
| ... | @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; | ... | @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; |
| 7 | import 'package:Parlando/account/models/my_videos_entity.dart'; | 7 | import 'package:Parlando/account/models/my_videos_entity.dart'; |
| 8 | import 'package:Parlando/account/models/upload_avatar_entity.dart'; | 8 | import 'package:Parlando/account/models/upload_avatar_entity.dart'; |
| 9 | import 'package:Parlando/account/models/user_entity.dart'; | 9 | import 'package:Parlando/account/models/user_entity.dart'; |
| 10 | +import 'package:Parlando/account/models/video_entity.dart'; | ||
| 10 | import 'package:Parlando/category/models/category_entity.dart'; | 11 | import 'package:Parlando/category/models/category_entity.dart'; |
| 11 | import 'package:Parlando/category/models/category_item_entity.dart'; | 12 | import 'package:Parlando/category/models/category_item_entity.dart'; |
| 12 | import 'package:Parlando/home/models/home_entity.dart'; | 13 | import 'package:Parlando/home/models/home_entity.dart'; |
| ... | @@ -31,6 +32,9 @@ class JsonConvert { | ... | @@ -31,6 +32,9 @@ class JsonConvert { |
| 31 | (UserEntity).toString(): UserEntity.fromJson, | 32 | (UserEntity).toString(): UserEntity.fromJson, |
| 32 | (UserData).toString(): UserData.fromJson, | 33 | (UserData).toString(): UserData.fromJson, |
| 33 | (UserError).toString(): UserError.fromJson, | 34 | (UserError).toString(): UserError.fromJson, |
| 35 | + (VideoEntity).toString(): VideoEntity.fromJson, | ||
| 36 | + (VideoData).toString(): VideoData.fromJson, | ||
| 37 | + (VideoError).toString(): VideoError.fromJson, | ||
| 34 | (CategoryEntity).toString(): CategoryEntity.fromJson, | 38 | (CategoryEntity).toString(): CategoryEntity.fromJson, |
| 35 | (CategoryData).toString(): CategoryData.fromJson, | 39 | (CategoryData).toString(): CategoryData.fromJson, |
| 36 | (CategoryDataData).toString(): CategoryDataData.fromJson, | 40 | (CategoryDataData).toString(): CategoryDataData.fromJson, |
| ... | @@ -186,6 +190,21 @@ class JsonConvert { | ... | @@ -186,6 +190,21 @@ class JsonConvert { |
| 186 | .map<UserError>((Map<String, dynamic> e) => UserError.fromJson(e)) | 190 | .map<UserError>((Map<String, dynamic> e) => UserError.fromJson(e)) |
| 187 | .toList() as M; | 191 | .toList() as M; |
| 188 | } | 192 | } |
| 193 | + if (<VideoEntity>[] is M) { | ||
| 194 | + return data | ||
| 195 | + .map<VideoEntity>((Map<String, dynamic> e) => VideoEntity.fromJson(e)) | ||
| 196 | + .toList() as M; | ||
| 197 | + } | ||
| 198 | + if (<VideoData>[] is M) { | ||
| 199 | + return data | ||
| 200 | + .map<VideoData>((Map<String, dynamic> e) => VideoData.fromJson(e)) | ||
| 201 | + .toList() as M; | ||
| 202 | + } | ||
| 203 | + if (<VideoError>[] is M) { | ||
| 204 | + return data | ||
| 205 | + .map<VideoError>((Map<String, dynamic> e) => VideoError.fromJson(e)) | ||
| 206 | + .toList() as M; | ||
| 207 | + } | ||
| 189 | if (<CategoryEntity>[] is M) { | 208 | if (<CategoryEntity>[] is M) { |
| 190 | return data | 209 | return data |
| 191 | .map<CategoryEntity>( | 210 | .map<CategoryEntity>( | ... | ... |
| ... | @@ -166,4 +166,4 @@ MyVideosError $MyVideosErrorFromJson(Map<String, dynamic> json) { | ... | @@ -166,4 +166,4 @@ MyVideosError $MyVideosErrorFromJson(Map<String, dynamic> json) { |
| 166 | Map<String, dynamic> $MyVideosErrorToJson(MyVideosError entity) { | 166 | Map<String, dynamic> $MyVideosErrorToJson(MyVideosError entity) { |
| 167 | final Map<String, dynamic> data = <String, dynamic>{}; | 167 | final Map<String, dynamic> data = <String, dynamic>{}; |
| 168 | return data; | 168 | return data; |
| 169 | -} | 169 | +} |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
lib/generated/json/video_entity.g.dart
0 → 100644
| 1 | +import 'package:Parlando/generated/json/base/json_convert_content.dart'; | ||
| 2 | +import 'package:Parlando/account/models/video_entity.dart'; | ||
| 3 | + | ||
| 4 | +VideoEntity $VideoEntityFromJson(Map<String, dynamic> json) { | ||
| 5 | + final VideoEntity videoEntity = VideoEntity(); | ||
| 6 | + final String? status = jsonConvert.convert<String>(json['status']); | ||
| 7 | + if (status != null) { | ||
| 8 | + videoEntity.status = status; | ||
| 9 | + } | ||
| 10 | + final int? code = jsonConvert.convert<int>(json['code']); | ||
| 11 | + if (code != null) { | ||
| 12 | + videoEntity.code = code; | ||
| 13 | + } | ||
| 14 | + final String? message = jsonConvert.convert<String>(json['message']); | ||
| 15 | + if (message != null) { | ||
| 16 | + videoEntity.message = message; | ||
| 17 | + } | ||
| 18 | + final VideoData? data = jsonConvert.convert<VideoData>(json['data']); | ||
| 19 | + if (data != null) { | ||
| 20 | + videoEntity.data = data; | ||
| 21 | + } | ||
| 22 | + final VideoError? error = jsonConvert.convert<VideoError>(json['error']); | ||
| 23 | + if (error != null) { | ||
| 24 | + videoEntity.error = error; | ||
| 25 | + } | ||
| 26 | + return videoEntity; | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +Map<String, dynamic> $VideoEntityToJson(VideoEntity entity) { | ||
| 30 | + final Map<String, dynamic> data = <String, dynamic>{}; | ||
| 31 | + data['status'] = entity.status; | ||
| 32 | + data['code'] = entity.code; | ||
| 33 | + data['message'] = entity.message; | ||
| 34 | + data['data'] = entity.data?.toJson(); | ||
| 35 | + data['error'] = entity.error?.toJson(); | ||
| 36 | + return data; | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +VideoData $VideoDataFromJson(Map<String, dynamic> json) { | ||
| 40 | + final VideoData videoData = VideoData(); | ||
| 41 | + final int? id = jsonConvert.convert<int>(json['id']); | ||
| 42 | + if (id != null) { | ||
| 43 | + videoData.id = id; | ||
| 44 | + } | ||
| 45 | + final int? userId = jsonConvert.convert<int>(json['user_id']); | ||
| 46 | + if (userId != null) { | ||
| 47 | + videoData.userId = userId; | ||
| 48 | + } | ||
| 49 | + final String? title = jsonConvert.convert<String>(json['title']); | ||
| 50 | + if (title != null) { | ||
| 51 | + videoData.title = title; | ||
| 52 | + } | ||
| 53 | + final String? content = jsonConvert.convert<String>(json['content']); | ||
| 54 | + if (content != null) { | ||
| 55 | + videoData.content = content; | ||
| 56 | + } | ||
| 57 | + final String? url = jsonConvert.convert<String>(json['url']); | ||
| 58 | + if (url != null) { | ||
| 59 | + videoData.url = url; | ||
| 60 | + } | ||
| 61 | + final int? type = jsonConvert.convert<int>(json['type']); | ||
| 62 | + if (type != null) { | ||
| 63 | + videoData.type = type; | ||
| 64 | + } | ||
| 65 | + final String? duration = jsonConvert.convert<String>(json['duration']); | ||
| 66 | + if (duration != null) { | ||
| 67 | + videoData.duration = duration; | ||
| 68 | + } | ||
| 69 | + final String? size = jsonConvert.convert<String>(json['size']); | ||
| 70 | + if (size != null) { | ||
| 71 | + videoData.size = size; | ||
| 72 | + } | ||
| 73 | + final int? poemId = jsonConvert.convert<int>(json['poem_id']); | ||
| 74 | + if (poemId != null) { | ||
| 75 | + videoData.poemId = poemId; | ||
| 76 | + } | ||
| 77 | + final int? tempId = jsonConvert.convert<int>(json['temp_id']); | ||
| 78 | + if (tempId != null) { | ||
| 79 | + videoData.tempId = tempId; | ||
| 80 | + } | ||
| 81 | + final String? thumbnail = jsonConvert.convert<String>(json['thumbnail']); | ||
| 82 | + if (thumbnail != null) { | ||
| 83 | + videoData.thumbnail = thumbnail; | ||
| 84 | + } | ||
| 85 | + final dynamic? bgm = jsonConvert.convert<dynamic>(json['bgm']); | ||
| 86 | + if (bgm != null) { | ||
| 87 | + videoData.bgm = bgm; | ||
| 88 | + } | ||
| 89 | + final String? praise = jsonConvert.convert<String>(json['praise']); | ||
| 90 | + if (praise != null) { | ||
| 91 | + videoData.praise = praise; | ||
| 92 | + } | ||
| 93 | + final String? view = jsonConvert.convert<String>(json['view']); | ||
| 94 | + if (view != null) { | ||
| 95 | + videoData.view = view; | ||
| 96 | + } | ||
| 97 | + final String? collect = jsonConvert.convert<String>(json['collect']); | ||
| 98 | + if (collect != null) { | ||
| 99 | + videoData.collect = collect; | ||
| 100 | + } | ||
| 101 | + final String? share = jsonConvert.convert<String>(json['share']); | ||
| 102 | + if (share != null) { | ||
| 103 | + videoData.share = share; | ||
| 104 | + } | ||
| 105 | + final String? comment = jsonConvert.convert<String>(json['comment']); | ||
| 106 | + if (comment != null) { | ||
| 107 | + videoData.comment = comment; | ||
| 108 | + } | ||
| 109 | + final String? state = jsonConvert.convert<String>(json['state']); | ||
| 110 | + if (state != null) { | ||
| 111 | + videoData.state = state; | ||
| 112 | + } | ||
| 113 | + final String? isPublish = jsonConvert.convert<String>(json['is_publish']); | ||
| 114 | + if (isPublish != null) { | ||
| 115 | + videoData.isPublish = isPublish; | ||
| 116 | + } | ||
| 117 | + final String? isCheck = jsonConvert.convert<String>(json['is_check']); | ||
| 118 | + if (isCheck != null) { | ||
| 119 | + videoData.isCheck = isCheck; | ||
| 120 | + } | ||
| 121 | + final String? createdAt = jsonConvert.convert<String>(json['created_at']); | ||
| 122 | + if (createdAt != null) { | ||
| 123 | + videoData.createdAt = createdAt; | ||
| 124 | + } | ||
| 125 | + final String? updatedAt = jsonConvert.convert<String>(json['updated_at']); | ||
| 126 | + if (updatedAt != null) { | ||
| 127 | + videoData.updatedAt = updatedAt; | ||
| 128 | + } | ||
| 129 | + return videoData; | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +Map<String, dynamic> $VideoDataToJson(VideoData entity) { | ||
| 133 | + final Map<String, dynamic> data = <String, dynamic>{}; | ||
| 134 | + data['id'] = entity.id; | ||
| 135 | + data['user_id'] = entity.userId; | ||
| 136 | + data['title'] = entity.title; | ||
| 137 | + data['content'] = entity.content; | ||
| 138 | + data['url'] = entity.url; | ||
| 139 | + data['type'] = entity.type; | ||
| 140 | + data['duration'] = entity.duration; | ||
| 141 | + data['size'] = entity.size; | ||
| 142 | + data['poem_id'] = entity.poemId; | ||
| 143 | + data['temp_id'] = entity.tempId; | ||
| 144 | + data['thumbnail'] = entity.thumbnail; | ||
| 145 | + data['bgm'] = entity.bgm; | ||
| 146 | + data['praise'] = entity.praise; | ||
| 147 | + data['view'] = entity.view; | ||
| 148 | + data['collect'] = entity.collect; | ||
| 149 | + data['share'] = entity.share; | ||
| 150 | + data['comment'] = entity.comment; | ||
| 151 | + data['state'] = entity.state; | ||
| 152 | + data['is_publish'] = entity.isPublish; | ||
| 153 | + data['is_check'] = entity.isCheck; | ||
| 154 | + data['created_at'] = entity.createdAt; | ||
| 155 | + data['updated_at'] = entity.updatedAt; | ||
| 156 | + return data; | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +VideoError $VideoErrorFromJson(Map<String, dynamic> json) { | ||
| 160 | + final VideoError videoError = VideoError(); | ||
| 161 | + return videoError; | ||
| 162 | +} | ||
| 163 | + | ||
| 164 | +Map<String, dynamic> $VideoErrorToJson(VideoError entity) { | ||
| 165 | + final Map<String, dynamic> data = <String, dynamic>{}; | ||
| 166 | + return data; | ||
| 167 | +} |
| ... | @@ -11,6 +11,9 @@ class HttpApi { | ... | @@ -11,6 +11,9 @@ class HttpApi { |
| 11 | static const String user = 'user'; | 11 | static const String user = 'user'; |
| 12 | static const String home = 'home'; | 12 | static const String home = 'home'; |
| 13 | static const String myVideos = '/my/videos'; | 13 | static const String myVideos = '/my/videos'; |
| 14 | + static const String praise = '/praise'; | ||
| 15 | + static const String addView = '/addview'; | ||
| 16 | + static const String collect = '/collect'; | ||
| 14 | static const String search = 'search/repositories'; | 17 | static const String search = 'search/repositories'; |
| 15 | static const String subscriptions = 'users/simplezhli/subscriptions'; | 18 | static const String subscriptions = 'users/simplezhli/subscriptions'; |
| 16 | static const String upload = 'uuc/upload-inco'; | 19 | static const String upload = 'uuc/upload-inco'; | ... | ... |
| ... | @@ -51,6 +51,9 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { | ... | @@ -51,6 +51,9 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { |
| 51 | String currentPoemId = ''; | 51 | String currentPoemId = ''; |
| 52 | String currentPoemType = ''; | 52 | String currentPoemType = ''; |
| 53 | 53 | ||
| 54 | + bool isFav = false; | ||
| 55 | + bool isPraise = false; | ||
| 56 | + | ||
| 54 | @override | 57 | @override |
| 55 | void didChangeAppLifecycleState(AppLifecycleState state) async { | 58 | void didChangeAppLifecycleState(AppLifecycleState state) async { |
| 56 | if (state != AppLifecycleState.resumed) { | 59 | if (state != AppLifecycleState.resumed) { |
| ... | @@ -81,11 +84,14 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { | ... | @@ -81,11 +84,14 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { |
| 81 | for (HomeData data in data!.data!) { | 84 | for (HomeData data in data!.data!) { |
| 82 | videoDataList.add( | 85 | videoDataList.add( |
| 83 | UserVideo( | 86 | UserVideo( |
| 87 | + id: data.id!, | ||
| 84 | image: '', | 88 | image: '', |
| 85 | url: data.url!, | 89 | url: data.url!, |
| 86 | desc: data.content, | 90 | desc: data.content, |
| 87 | poemId: '${data.poemId}', | 91 | poemId: '${data.poemId}', |
| 88 | poemType: '${data.type}', | 92 | poemType: '${data.type}', |
| 93 | + isPraise: data.praise == '1' ? true : false, | ||
| 94 | + isCollect: data.collect == '1' ? true : false, | ||
| 89 | ), | 95 | ), |
| 90 | ); | 96 | ); |
| 91 | } | 97 | } |
| ... | @@ -202,6 +208,17 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { | ... | @@ -202,6 +208,17 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { |
| 202 | _videoListController.currentPlayer.videoInfo!.poemId; | 208 | _videoListController.currentPlayer.videoInfo!.poemId; |
| 203 | currentPoemType = | 209 | currentPoemType = |
| 204 | _videoListController.currentPlayer.videoInfo!.poemType; | 210 | _videoListController.currentPlayer.videoInfo!.poemType; |
| 211 | + | ||
| 212 | + String url = | ||
| 213 | + '${HttpApi.addView}/${_videoListController.currentPlayer.videoInfo!.id}'; | ||
| 214 | + // 统计观看数 | ||
| 215 | + DioUtils.instance.asyncRequestNetwork( | ||
| 216 | + Method.get, | ||
| 217 | + url, | ||
| 218 | + params: [], | ||
| 219 | + onSuccess: (data) {}, | ||
| 220 | + onError: (code, msg) {}, | ||
| 221 | + ); | ||
| 205 | }, | 222 | }, |
| 206 | key: const Key('home'), | 223 | key: const Key('home'), |
| 207 | physics: const QuickerScrollPhysics(), | 224 | physics: const QuickerScrollPhysics(), |
| ... | @@ -214,11 +231,35 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { | ... | @@ -214,11 +231,35 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { |
| 214 | var data = player.videoInfo!; | 231 | var data = player.videoInfo!; |
| 215 | // 右侧按钮列 | 232 | // 右侧按钮列 |
| 216 | Widget buttons = TikTokButtonColumn( | 233 | Widget buttons = TikTokButtonColumn( |
| 217 | - isFavorite: false, | 234 | + isPraise: _videoListController |
| 235 | + .currentPlayer.videoInfo!.isPraise, | ||
| 236 | + isCollect: _videoListController | ||
| 237 | + .currentPlayer.videoInfo!.isCollect, | ||
| 218 | onAvatar: () { | 238 | onAvatar: () { |
| 219 | tkController.animateToPage(TikTokPagePosition.right); | 239 | tkController.animateToPage(TikTokPagePosition.right); |
| 220 | }, | 240 | }, |
| 221 | - onFavorite: () {}, | 241 | + onPraise: () { |
| 242 | + String url = | ||
| 243 | + '${HttpApi.praise}/${_videoListController.currentPlayer.videoInfo!.id}'; | ||
| 244 | + DioUtils.instance.asyncRequestNetwork( | ||
| 245 | + Method.post, | ||
| 246 | + url, | ||
| 247 | + params: [], | ||
| 248 | + onSuccess: (data) {}, | ||
| 249 | + onError: (code, msg) {}, | ||
| 250 | + ); | ||
| 251 | + }, | ||
| 252 | + onCollect: () { | ||
| 253 | + String url = | ||
| 254 | + '${HttpApi.collect}/${_videoListController.currentPlayer.videoInfo!.id}'; | ||
| 255 | + DioUtils.instance.asyncRequestNetwork( | ||
| 256 | + Method.post, | ||
| 257 | + url, | ||
| 258 | + params: [], | ||
| 259 | + onSuccess: (data) {}, | ||
| 260 | + onError: (code, msg) {}, | ||
| 261 | + ); | ||
| 262 | + }, | ||
| 222 | onShare: () {}, | 263 | onShare: () {}, |
| 223 | ); | 264 | ); |
| 224 | Widget poem = TikTokVidePoem( | 265 | Widget poem = TikTokVidePoem( |
| ... | @@ -276,7 +317,6 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { | ... | @@ -276,7 +317,6 @@ class PoemPageState extends State<PoemPage> with WidgetsBindingObserver { |
| 276 | onPress: () { | 317 | onPress: () { |
| 277 | String url = | 318 | String url = |
| 278 | '${PoemRouter.poemRecordVideoPage}?id=$currentPoemId&type=$currentPoemType'; | 319 | '${PoemRouter.poemRecordVideoPage}?id=$currentPoemId&type=$currentPoemType'; |
| 279 | - print("===========================" + url); | ||
| 280 | eventBus.fire(TransEvent()); | 320 | eventBus.fire(TransEvent()); |
| 281 | NavigatorUtils.push( | 321 | NavigatorUtils.push( |
| 282 | context, | 322 | context, | ... | ... |
| ... | @@ -8,18 +8,24 @@ var videoList = [ | ... | @@ -8,18 +8,24 @@ var videoList = [ |
| 8 | ]; | 8 | ]; |
| 9 | 9 | ||
| 10 | class UserVideo { | 10 | class UserVideo { |
| 11 | + final int id; | ||
| 11 | final String url; | 12 | final String url; |
| 12 | final String image; | 13 | final String image; |
| 13 | final String? desc; | 14 | final String? desc; |
| 14 | final String poemId; | 15 | final String poemId; |
| 15 | final String poemType; | 16 | final String poemType; |
| 17 | + final bool isPraise; | ||
| 18 | + final bool isCollect; | ||
| 16 | 19 | ||
| 17 | UserVideo({ | 20 | UserVideo({ |
| 21 | + required this.id, | ||
| 18 | required this.url, | 22 | required this.url, |
| 19 | required this.image, | 23 | required this.image, |
| 20 | this.desc, | 24 | this.desc, |
| 21 | required this.poemId, | 25 | required this.poemId, |
| 22 | required this.poemType, | 26 | required this.poemType, |
| 27 | + required this.isPraise, | ||
| 28 | + required this.isCollect, | ||
| 23 | }); | 29 | }); |
| 24 | 30 | ||
| 25 | @override | 31 | @override | ... | ... |
| ... | @@ -6,18 +6,21 @@ import 'package:Parlando/extension/int_extension.dart'; | ... | @@ -6,18 +6,21 @@ import 'package:Parlando/extension/int_extension.dart'; |
| 6 | 6 | ||
| 7 | class TikTokButtonColumn extends StatelessWidget { | 7 | class TikTokButtonColumn extends StatelessWidget { |
| 8 | final double? bottomPadding; | 8 | final double? bottomPadding; |
| 9 | - final bool isFavorite; | 9 | + final bool isPraise; |
| 10 | - final Function? onFavorite; | 10 | + final bool isCollect; |
| 11 | - final Function? onComment; | 11 | + final Function? onPraise; |
| 12 | + final Function? onCollect; | ||
| 12 | final Function? onShare; | 13 | final Function? onShare; |
| 13 | final Function? onAvatar; | 14 | final Function? onAvatar; |
| 15 | + | ||
| 14 | const TikTokButtonColumn({ | 16 | const TikTokButtonColumn({ |
| 15 | Key? key, | 17 | Key? key, |
| 16 | this.bottomPadding, | 18 | this.bottomPadding, |
| 17 | - this.onFavorite, | 19 | + this.onPraise, |
| 18 | - this.onComment, | 20 | + this.onCollect, |
| 19 | this.onShare, | 21 | this.onShare, |
| 20 | - this.isFavorite = false, | 22 | + this.isPraise = false, |
| 23 | + this.isCollect = false, | ||
| 21 | this.onAvatar, | 24 | this.onAvatar, |
| 22 | }) : super(key: key); | 25 | }) : super(key: key); |
| 23 | 26 | ||
| ... | @@ -34,13 +37,12 @@ class TikTokButtonColumn extends StatelessWidget { | ... | @@ -34,13 +37,12 @@ class TikTokButtonColumn extends StatelessWidget { |
| 34 | crossAxisAlignment: CrossAxisAlignment.end, | 37 | crossAxisAlignment: CrossAxisAlignment.end, |
| 35 | children: <Widget>[ | 38 | children: <Widget>[ |
| 36 | FavoriteIcon( | 39 | FavoriteIcon( |
| 37 | - onFavorite: onFavorite, | 40 | + onFavorite: onPraise, |
| 38 | - isFavorite: isFavorite, | 41 | + isFavorite: isPraise, |
| 39 | ), | 42 | ), |
| 40 | - _IconButton( | 43 | + CollectIcon( |
| 41 | - icon: IconToText(Icons.star_border, size: 20.px), | 44 | + onCollect: onCollect, |
| 42 | - text: '收藏', | 45 | + isCollect: isCollect, |
| 43 | - onTap: onComment, | ||
| 44 | ), | 46 | ), |
| 45 | _IconButton( | 47 | _IconButton( |
| 46 | icon: IconToText(Icons.share, size: 20.px), | 48 | icon: IconToText(Icons.share, size: 20.px), |
| ... | @@ -70,12 +72,35 @@ class FavoriteIcon extends StatelessWidget { | ... | @@ -70,12 +72,35 @@ class FavoriteIcon extends StatelessWidget { |
| 70 | size: 20, | 72 | size: 20, |
| 71 | color: isFavorite! ? ColorPlate.red : null, | 73 | color: isFavorite! ? ColorPlate.red : null, |
| 72 | ), | 74 | ), |
| 73 | - text: '喜爱', | 75 | + text: '点赞', |
| 74 | onTap: onFavorite, | 76 | onTap: onFavorite, |
| 75 | ); | 77 | ); |
| 76 | } | 78 | } |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 81 | +class CollectIcon extends StatelessWidget { | ||
| 82 | + const CollectIcon({ | ||
| 83 | + Key? key, | ||
| 84 | + required this.onCollect, | ||
| 85 | + this.isCollect, | ||
| 86 | + }) : super(key: key); | ||
| 87 | + final bool? isCollect; | ||
| 88 | + final Function? onCollect; | ||
| 89 | + | ||
| 90 | + @override | ||
| 91 | + Widget build(BuildContext context) { | ||
| 92 | + return _IconButton( | ||
| 93 | + icon: IconToText( | ||
| 94 | + Icons.star_border_outlined, | ||
| 95 | + size: 20, | ||
| 96 | + color: isCollect! ? ColorPlate.red : null, | ||
| 97 | + ), | ||
| 98 | + text: '收藏', | ||
| 99 | + onTap: onCollect, | ||
| 100 | + ); | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | + | ||
| 79 | /// 把IconData转换为文字,使其可以使用文字样式 | 104 | /// 把IconData转换为文字,使其可以使用文字样式 |
| 80 | class IconToText extends StatelessWidget { | 105 | class IconToText extends StatelessWidget { |
| 81 | final IconData? icon; | 106 | final IconData? icon; |
| ... | @@ -90,6 +115,7 @@ class IconToText extends StatelessWidget { | ... | @@ -90,6 +115,7 @@ class IconToText extends StatelessWidget { |
| 90 | this.size, | 115 | this.size, |
| 91 | this.color, | 116 | this.color, |
| 92 | }) : super(key: key); | 117 | }) : super(key: key); |
| 118 | + | ||
| 93 | @override | 119 | @override |
| 94 | Widget build(BuildContext context) { | 120 | Widget build(BuildContext context) { |
| 95 | return Text( | 121 | return Text( |
| ... | @@ -109,6 +135,7 @@ class _IconButton extends StatelessWidget { | ... | @@ -109,6 +135,7 @@ class _IconButton extends StatelessWidget { |
| 109 | final Widget? icon; | 135 | final Widget? icon; |
| 110 | final String? text; | 136 | final String? text; |
| 111 | final Function? onTap; | 137 | final Function? onTap; |
| 138 | + | ||
| 112 | const _IconButton({ | 139 | const _IconButton({ |
| 113 | Key? key, | 140 | Key? key, |
| 114 | this.icon, | 141 | this.icon, |
| ... | @@ -130,8 +157,8 @@ class _IconButton extends StatelessWidget { | ... | @@ -130,8 +157,8 @@ class _IconButton extends StatelessWidget { |
| 130 | Widget body = Column( | 157 | Widget body = Column( |
| 131 | children: <Widget>[ | 158 | children: <Widget>[ |
| 132 | Tapped( | 159 | Tapped( |
| 133 | - child: icon ?? Container(), | ||
| 134 | onTap: onTap, | 160 | onTap: onTap, |
| 161 | + child: icon ?? Container(), | ||
| 135 | ), | 162 | ), |
| 136 | Container(height: 2.px), | 163 | Container(height: 2.px), |
| 137 | Text( | 164 | Text( |
| ... | @@ -146,8 +173,8 @@ class _IconButton extends StatelessWidget { | ... | @@ -146,8 +173,8 @@ class _IconButton extends StatelessWidget { |
| 146 | return Container( | 173 | return Container( |
| 147 | padding: EdgeInsets.symmetric(vertical: 10.px), | 174 | padding: EdgeInsets.symmetric(vertical: 10.px), |
| 148 | child: DefaultTextStyle( | 175 | child: DefaultTextStyle( |
| 149 | - child: body, | ||
| 150 | style: shadowStyle, | 176 | style: shadowStyle, |
| 177 | + child: body, | ||
| 151 | ), | 178 | ), |
| 152 | ); | 179 | ); |
| 153 | } | 180 | } | ... | ... |
-
Please register or login to post a comment