feat: app端首页推荐

This commit is contained in:
guozhigq
2023-08-14 10:05:16 +08:00
parent 17b02d9ae9
commit 0d852987fa
9 changed files with 140 additions and 23 deletions

View File

@ -7,3 +7,10 @@ class StyleString {
static const Radius imgRadius = Radius.circular(10);
static const double aspectRatio = 16 / 10;
}
class Constants {
static const String appKey = '27eb53fc9058f8c3';
static const String thirdSign = '04224646d1fea004e79606d3b038c84a';
static const String thirdApi =
'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png';
}

View File

@ -58,6 +58,9 @@ class Request {
log("setCookie, ${e.toString()}");
}
}
var cookieString =
cookie.map((cookie) => '${cookie.name}=${cookie.value}').join('; ');
dio.options.headers['cookie'] = cookieString;
}
// 移除cookie

View File

@ -1,6 +1,8 @@
import 'package:dio/dio.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/utils/storage.dart';
// import 'package:get/get.dart' hide Response;
class ApiInterceptor extends Interceptor {
@ -13,8 +15,26 @@ class ApiInterceptor extends Interceptor {
handler.next(options);
}
Box setting = GStrorage.setting;
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
try {
if (response.statusCode == 302) {
List<String> locations = response.headers['location']!;
if (locations.isNotEmpty) {
if (locations.first.startsWith('https://www.mcbbs.net')) {
final uri = Uri.parse(locations.first);
final accessKey = uri.queryParameters['access_key'];
final mid = uri.queryParameters['mid'];
setting.put(UserBoxKey.accessKey, {'mid': mid, 'value': accessKey});
}
}
}
} catch (err) {
print('ApiInterceptor: $err');
}
handler.next(response);
}

View File

@ -1,4 +1,7 @@
import 'package:dio/dio.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/http/api.dart';
import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/model_hot_video_item.dart';
import 'package:pilipala/models/user/fav_detail.dart';
@ -179,4 +182,19 @@ class UserHttp {
return {'status': false, 'msg': res.data['message']};
}
}
// 获取用户凭证
static Future thirdLogin() async {
var res = await Request().get(
'https://passport.bilibili.com/login/app/third',
data: {
'appkey': Constants.appKey,
'api': Constants.thirdApi,
'sign': Constants.thirdSign,
},
);
if (res.data['code'] == 0 && res.data['data']['has_login'] == 1) {
Request().get(res.data['data']['confirm_uri']);
}
}
}

View File

@ -1,5 +1,7 @@
import 'dart:developer';
import 'package:hive/hive.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/http/api.dart';
import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/common/reply_type.dart';
@ -9,12 +11,15 @@ import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/models/user/fav_folder.dart';
import 'package:pilipala/models/video/play/url.dart';
import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/utils/storage.dart';
/// res.data['code'] == 0 请求正常返回结果
/// res.data['data'] 为结果
/// 返回{'status': bool, 'data': List}
/// view层根据 status 判断渲染逻辑
class VideoHttp {
static Box setting = GStrorage.setting;
// 首页推荐视频
static Future rcmdVideoList({required int ps, required int freshIdx}) async {
try {
@ -55,6 +60,9 @@ class VideoHttp {
'device_type': 0,
'device_name': 'vivo',
'pull': freshIdx == 0 ? 'true' : 'false',
'appkey': Constants.appKey,
'access_key':
setting.get(UserBoxKey.accessKey, defaultValue: {})['value'] ?? ''
},
);
if (res.data['code'] == 0) {

View File

@ -1,3 +1,5 @@
import 'dart:developer';
class RecVideoItemAppModel {
RecVideoItemAppModel({
this.id,
@ -11,30 +13,60 @@ class RecVideoItemAppModel {
this.isFollowed,
this.owner,
this.rcmdReason,
this.goto,
this.param,
this.uri,
this.talkBack,
this.bangumiView,
this.bangumiFollow,
this.bangumiBadge,
});
int? id;
int? aid;
int? bvid;
String? bvid;
int? cid;
String? pic;
Stat? stat;
int? duration;
String? duration;
String? title;
int? isFollowed;
Owner? owner;
String? rcmdReason;
RcmdReason? rcmdReason;
String? goto;
String? param;
String? uri;
String? talkBack;
// 番剧
String? bangumiView;
String? bangumiFollow;
String? bangumiBadge;
RecVideoItemAppModel.fromJson(Map<String, dynamic> json) {
id = json['player_args']['aid'];
aid = json['player_args']['aid'];
cid = json['player_args']['cid'];
id = json['player_args'] != null
? json['player_args']['aid']
: int.parse(json['param'] ?? '-1');
aid = json['player_args'] != null ? json['player_args']['aid'] : -1;
cid = json['player_args'] != null ? json['player_args']['cid'] : -1;
pic = json['cover'];
stat = Stat.fromJson(json);
duration = json['player_args']['duration'];
duration = json['cover_right_text'];
title = json['title'];
isFollowed = 0;
owner = Owner.fromJson(json);
rcmdReason = json['rcmd_reason_style'] != null
? RcmdReason.fromJson(json['rcmd_reason_style'])
: null;
goto = json['goto'];
param = json['param'];
uri = json['uri'];
talkBack = json['talk_back'];
if (json['goto'] == 'bangumi') {
bangumiView = json['cover_left_text_1'];
bangumiFollow = json['cover_left_text_2'];
bangumiBadge = json['badge'];
}
}
}
@ -42,15 +74,15 @@ class Stat {
Stat({
this.view,
this.like,
this.danmaku,
this.danmu,
});
String? view;
String? like;
String? danmaku;
String? danmu;
Stat.fromJson(Map<String, dynamic> json) {
view = json["cover_left_text_1"];
danmaku = json['cover_left_text_2'];
danmu = json['cover_left_text_2'];
}
}
@ -58,8 +90,29 @@ class Owner {
Owner({this.name});
String? name;
int? mid;
Owner.fromJson(Map<String, dynamic> json) {
name = json['args']['up_name'];
if (json['goto'] == 'bangumi') {
log(json.toString());
}
name = json['goto'] == 'av'
? json['args']['up_name']
: json['desc_button'] != null
? json['desc_button']['text']
: '';
mid = json['args']['up_id'] ?? -1;
}
}
class RcmdReason {
RcmdReason({
this.content,
});
String? content;
RcmdReason.fromJson(Map<String, dynamic> json) {
content = json["title"] ?? '';
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/index.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/common/tab_type.dart';
import 'package:pilipala/utils/storage.dart';
@ -54,6 +55,7 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
if (res.data['code'] == 0) {
defaultSearch.value = res.data['data']['name'];
}
UserHttp.thirdLogin();
}
// 更新登录状态

View File

@ -2,15 +2,16 @@ import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/home/rcmd/result.dart';
import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/utils/storage.dart';
class RcmdController extends GetxController {
final ScrollController scrollController = ScrollController();
int count = 12;
int _currentPage = 1;
int _currentPage = 0;
int crossAxisCount = 2;
RxList<RecVideoItemModel> videoList = [RecVideoItemModel()].obs;
RxList<RecVideoItemAppModel> videoList = [RecVideoItemAppModel()].obs;
bool isLoadingMore = false;
bool flag = false;
OverlayEntry? popupDialog;
@ -19,19 +20,22 @@ class RcmdController extends GetxController {
@override
void onInit() {
super.onInit();
if (recVideo.get('cacheList') != null &&
recVideo.get('cacheList').isNotEmpty) {
List<RecVideoItemModel> list = [];
for (var i in recVideo.get('cacheList')) {
list.add(i);
}
videoList.value = list;
}
// if (recVideo.get('cacheList') != null &&
// recVideo.get('cacheList').isNotEmpty) {
// List<RecVideoItemModel> list = [];
// for (var i in recVideo.get('cacheList')) {
// list.add(i);
// }
// videoList.value = list;
// }
}
// 获取推荐
Future queryRcmdFeed(type) async {
var res = await VideoHttp.rcmdVideoList(
if (type == 'onRefresh') {
_currentPage = 0;
}
var res = await VideoHttp.rcmdVideoListApp(
ps: count,
freshIdx: _currentPage,
);
@ -47,7 +51,7 @@ class RcmdController extends GetxController {
} else if (type == 'onLoad') {
videoList.addAll(res['data']);
}
recVideo.put('cacheList', res['data']);
// recVideo.put('cacheList', res['data']);
_currentPage += 1;
}
isLoadingMore = false;

View File

@ -63,6 +63,8 @@ class UserBoxKey {
static const String userMid = 'userMid';
// 登录状态
static const String userLogin = 'userLogin';
// 凭证
static const String accessKey = 'accessKey';
}
class SettingBoxKey {