mod: 图标&样式&网页登录

This commit is contained in:
guozhigq
2023-05-08 10:17:35 +08:00
parent a66bb08ca8
commit 89766a72d9
59 changed files with 449 additions and 149 deletions

View File

@ -47,11 +47,11 @@ android {
applicationId "com.example.pilipala" applicationId "com.example.pilipala"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion // minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
minSdkVersion 17 minSdkVersion 19
} }
buildTypes { buildTypes {

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#ffffff</color>
</resources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -31,6 +31,10 @@ PODS:
- FMDB (>= 2.7.5) - FMDB (>= 2.7.5)
- url_launcher_ios (0.0.1): - url_launcher_ios (0.0.1):
- Flutter - Flutter
- webview_cookie_manager (0.0.1):
- Flutter
- webview_flutter_wkwebview (0.0.1):
- Flutter
DEPENDENCIES: DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
@ -43,6 +47,8 @@ DEPENDENCIES:
- share_plus (from `.symlinks/plugins/share_plus/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- webview_cookie_manager (from `.symlinks/plugins/webview_cookie_manager/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
@ -71,6 +77,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite/ios" :path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios: url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
webview_cookie_manager:
:path: ".symlinks/plugins/webview_cookie_manager/ios"
webview_flutter_wkwebview:
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e
@ -86,6 +96,8 @@ SPEC CHECKSUMS:
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -5,18 +5,22 @@ class Api {
static const String hotList = '/x/web-interface/popular'; static const String hotList = '/x/web-interface/popular';
// 视频详情 // 视频详情
// 竖屏 https://api.bilibili.com/x/web-interface/view?aid=527403921 // 竖屏 https://api.bilibili.com/x/web-interface/view?aid=527403921
// https://api.bilibili.com/x/web-interface/view/detail 获取视频超详细信息(web端)
static const String videoIntro = '/x/web-interface/view'; static const String videoIntro = '/x/web-interface/view';
// 视频详情页 相关视频 // 视频详情页 相关视频
static const String relatedList = '/x/web-interface/archive/related'; static const String relatedList = '/x/web-interface/archive/related';
// 用户(被)关注数、投稿数
// https://api.bilibili.com/x/relation/stat?vmid=697166795
static const String userStat = '/x/relation/stat';
// 评论列表 // 评论列表
static const String replyList = '/x/v2/reply'; static const String replyList = '/x/v2/reply';
// 楼中楼 // 楼中楼
static const String replyReplyList = '/x/v2/reply/reply'; static const String replyReplyList = '/x/v2/reply/reply';
// 用户(被)关注数、投稿数
// https://api.bilibili.com/x/relation/stat?vmid=697166795
static const String userStat = '/x/relation/stat';
// 获取用户信息
static const String userInfo = '/x/web-interface/nav';
} }

View File

@ -10,4 +10,13 @@ class UserHttp {
return {'status': false}; return {'status': false};
} }
} }
static Future<dynamic> userInfo() async {
var res = await Request().get(Api.userInfo);
if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']};
} else {
return {'status': false};
}
}
} }

View File

@ -1,3 +1,4 @@
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
@ -23,18 +24,24 @@ class MyApp extends StatelessWidget {
return GetMaterialApp( return GetMaterialApp(
title: 'PiLiPaLa', title: 'PiLiPaLa',
theme: ThemeData( theme: ThemeData(
colorScheme: lightDynamic ?? colorScheme: lightDynamic ??
ColorScheme.fromSeed( ColorScheme.fromSeed(
seedColor: Colors.green, brightness: Brightness.light), seedColor: Colors.green,
useMaterial3: true), brightness: Brightness.light,
),
useMaterial3: true,
),
darkTheme: ThemeData( darkTheme: ThemeData(
colorScheme: darkDynamic ?? colorScheme: darkDynamic ??
ColorScheme.fromSeed( ColorScheme.fromSeed(
seedColor: Colors.green, brightness: Brightness.dark), seedColor: Colors.green,
useMaterial3: true), brightness: Brightness.dark,
),
useMaterial3: true,
),
getPages: Routes.getPages, getPages: Routes.getPages,
home: const MainApp(), home: const MainApp(),
// home: const Scaffold(), builder: FlutterSmartDialog.init(),
); );
}), }),
); );

View File

@ -0,0 +1,7 @@
class UserInfoData {
UserInfoData({
this.isLogin,
});
bool? isLogin;
}

View File

@ -30,7 +30,7 @@ class HomeAppBar extends StatelessWidget {
title: const Text( title: const Text(
'PiLiPaLa', 'PiLiPaLa',
style: TextStyle( style: TextStyle(
fontSize: 19, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
letterSpacing: 1, letterSpacing: 1,
fontFamily: 'ArchivoNarrow', fontFamily: 'ArchivoNarrow',

View File

@ -0,0 +1,14 @@
import 'package:get/get.dart';
import 'package:pilipala/http/user.dart';
class MineController extends GetxController {
@override
void onInit() {
super.onInit();
// queryUserInfo();
}
Future queryUserInfo() async {
var res = await UserHttp.userInfo();
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'controller.dart';
class MinePage extends StatefulWidget { class MinePage extends StatefulWidget {
const MinePage({super.key}); const MinePage({super.key});
@ -10,6 +12,8 @@ class MinePage extends StatefulWidget {
} }
class _MinePageState extends State<MinePage> { class _MinePageState extends State<MinePage> {
final MineController _mineController = Get.put(MineController());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -30,136 +34,161 @@ class _MinePageState extends State<MinePage> {
const SizedBox(width: 10), const SizedBox(width: 10),
], ],
), ),
body: Padding( body: RefreshIndicator(
padding: const EdgeInsets.only(left: 12, right: 12), onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
child: Column( child: Column(
children: [ children: [
Row( InkWell(
children: [ onTap: () {
const SizedBox(width: 20), Get.toNamed(
ClipOval( '/webview',
child: Container( parameters: {
width: 75, 'url':
height: 75, 'https://passport.bilibili.com/h5-app/passport/login',
color: Theme.of(context).colorScheme.onInverseSurface, 'type': 'login',
child: Center( 'pageTitle': '登录bilibili',
child: Image.asset('assets/images/loading.png'), },
);
},
child: Padding(
padding: const EdgeInsets.only(top: 10, bottom: 10),
child: 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(width: 14), ),
Text( ),
'点击登录', const SizedBox(height: 10),
style: Theme.of(context).textTheme.titleMedium, Padding(
), padding: const EdgeInsets.only(left: 12, right: 12),
], child: 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), const SizedBox(height: 20),
LayoutBuilder( Padding(
builder: (context, constraints) { padding: const EdgeInsets.only(left: 12, right: 12),
TextStyle style = TextStyle( child: LayoutBuilder(
fontSize: Theme.of(context).textTheme.titleMedium!.fontSize, builder: (context, constraints) {
color: Theme.of(context).colorScheme.primary, return SizedBox(
fontWeight: FontWeight.bold); height: constraints.maxWidth / 4 * 0.8,
return SizedBox( child: GridView.count(
height: constraints.maxWidth / 3 * 0.6, primary: false,
child: GridView.count( padding: const EdgeInsets.all(0),
primary: false, crossAxisCount: 4,
padding: const EdgeInsets.all(0), childAspectRatio: 1.25,
crossAxisCount: 3, children: <Widget>[
childAspectRatio: 1.67, ActionItem(
children: <Widget>[ icon: const Icon(FontAwesomeIcons.download),
InkWell( onTap: () => {},
onTap: () {}, text: '离线缓存',
borderRadius: StyleString.mdRadius,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('-', style: style),
const SizedBox(height: 8),
Text(
'动态',
style: Theme.of(context).textTheme.labelMedium,
),
],
), ),
), ActionItem(
InkWell( icon: const Icon(FontAwesomeIcons.clockRotateLeft),
onTap: () {}, onTap: () => {},
borderRadius: StyleString.mdRadius, text: '历史记录',
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'50',
style: style,
),
const SizedBox(height: 8),
Text(
'关注',
style: Theme.of(context).textTheme.labelMedium,
),
],
), ),
), ActionItem(
InkWell( icon: const Icon(FontAwesomeIcons.star),
onTap: () {}, onTap: () => {},
borderRadius: StyleString.mdRadius, text: '我的收藏',
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'-',
style: style,
),
const SizedBox(height: 8),
Text(
'粉丝',
style: Theme.of(context).textTheme.labelMedium,
),
],
), ),
), ActionItem(
], icon: const Icon(FontAwesomeIcons.film),
), onTap: () => {},
); text: '稍后再看',
}, ),
), ],
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: '稍后再看',
),
],
),
);
},
), ),
], ],
), ),
@ -188,7 +217,10 @@ class ActionItem extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(icon!.icon!), Icon(
icon!.icon!,
color: Theme.of(context).colorScheme.outline,
),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
text!, text!,

View File

@ -247,7 +247,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
children: const [ children: const [
Icon( Icon(
FontAwesomeIcons.lemon, FontAwesomeIcons.lemon,
size: 17, size: 15,
), ),
SizedBox(width: 4), SizedBox(width: 4),
Text('关注'), Text('关注'),
@ -334,10 +334,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
? widget.videoDetail!.stat!.coin!.toString() ? widget.videoDetail!.stat!.coin!.toString()
: '-'), : '-'),
ActionItem( ActionItem(
icon: const Icon( icon: const Icon(FontAwesomeIcons.star),
FontAwesomeIcons.heart,
size: 17,
),
onTap: () => {}, onTap: () => {},
selectStatus: false, selectStatus: false,
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
@ -386,10 +383,11 @@ class ActionItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(icon!.icon!, Icon(icon!.icon!,
size: 20,
color: selectStatus color: selectStatus
? Theme.of(context).primaryColor ? Theme.of(context).primaryColor
: Theme.of(context).colorScheme.outline), : Theme.of(context).colorScheme.outline),
const SizedBox(height: 2), const SizedBox(height: 4),
AnimatedOpacity( AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1, opacity: loadingStatus! ? 0 : 1,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),

View File

@ -164,7 +164,7 @@ class ReplyItem extends StatelessWidget {
TextSpan( TextSpan(
children: [ children: [
if (replyItem!.isTop!) if (replyItem!.isTop!)
WidgetSpan(child: UpTag(tagText: '置顶')), WidgetSpan(child: UpTag(tagText: 'TOP')),
buildContent(context, replyItem!.content!), buildContent(context, replyItem!.content!),
], ],
), ),
@ -200,6 +200,15 @@ class ReplyItem extends StatelessWidget {
.labelMedium! .labelMedium!
.copyWith(color: Theme.of(context).colorScheme.outline), .copyWith(color: Theme.of(context).colorScheme.outline),
), ),
if (replyItem!.replyControl != null &&
replyItem!.replyControl!.location != null)
Text(
'${replyItem!.replyControl!.location!}',
style: Theme.of(context)
.textTheme
.labelMedium!
.copyWith(color: Theme.of(context).colorScheme.outline),
),
const Spacer(), const Spacer(),
if (replyControl!.isUpTop!) if (replyControl!.isUpTop!)
Icon(Icons.favorite, color: Colors.red[400], size: 18), Icon(Icons.favorite, color: Colors.red[400], size: 18),
@ -209,7 +218,7 @@ class ReplyItem extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
Icon( Icon(
Icons.thumb_up_alt_outlined, FontAwesomeIcons.thumbsUp,
size: 16, size: 16,
color: color, color: color,
), ),

View File

@ -74,7 +74,7 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
body: Column( body: Column(
children: [ children: [
Container( Container(
height: 50, height: 45,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
bottom: BorderSide( bottom: BorderSide(
@ -91,7 +91,6 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
margin: const EdgeInsets.only(left: 20), margin: const EdgeInsets.only(left: 20),
child: Obx( child: Obx(
() => TabBar( () => TabBar(
splashBorderRadius: BorderRadius.circular(6),
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
tabs: videoDetailController.tabs tabs: videoDetailController.tabs
.map((String name) => Tab(text: name)) .map((String name) => Tab(text: name))

View File

@ -0,0 +1,69 @@
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/utils/cookie.dart';
import 'package:webview_cookie_manager/webview_cookie_manager.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebviewController extends GetxController {
String url = '';
String type = '';
String pageTitle = '';
final WebViewController controller = WebViewController();
@override
void onInit() {
super.onInit();
url = Get.parameters['url']!;
type = Get.parameters['type']!;
pageTitle = Get.parameters['pageTitle']!;
webviewInit();
}
webviewInit() {
controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
// 页面加载
onProgress: (int progress) {
// Update loading bar.
},
onPageStarted: (String url) {},
// 加载完成
onPageFinished: (String url) async {
if (url.startsWith(
'https://passport.bilibili.com/web/sso/exchange_cookie') ||
url.startsWith('https://m.bilibili.com/')) {
try {
var cookies =
await WebviewCookieManager().getCookies(HttpString.baseUrl);
var apiCookies =
await WebviewCookieManager().getCookies(HttpString.baseUrl);
await SetCookie.onSet(cookies, HttpString.baseUrl);
await SetCookie.onSet(apiCookies, HttpString.baseApiUrl);
var result = await UserHttp.userInfo();
bool isLogin = result['data']['isLogin'];
if (isLogin) {
SmartDialog.showToast('登录成功');
Get.back();
}
} catch (e) {
print(e);
}
}
},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith('https://www.youtube.com/')) {
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..loadRequest(Uri.parse(url));
}
}

View File

@ -0,0 +1,4 @@
library webview;
export './controller.dart';
export './view.dart';

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'controller.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebviewPage extends StatefulWidget {
const WebviewPage({super.key});
@override
State<WebviewPage> createState() => _WebviewPageState();
}
class _WebviewPageState extends State<WebviewPage> {
final WebviewController _webviewController = Get.put(WebviewController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(
_webviewController.pageTitle,
style: Theme.of(context).textTheme.titleMedium,
),
),
body: WebViewWidget(controller: _webviewController.controller),
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/hot/index.dart'; import 'package:pilipala/pages/hot/index.dart';
import 'package:pilipala/pages/preview/index.dart'; import 'package:pilipala/pages/preview/index.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/pages/webview/index.dart';
class Routes { class Routes {
static final List<GetPage> getPages = [ static final List<GetPage> getPages = [
@ -13,6 +14,8 @@ class Routes {
// 视频详情 // 视频详情
GetPage(name: '/video', page: () => const VideoDetailPage()), GetPage(name: '/video', page: () => const VideoDetailPage()),
// 图片预览 // 图片预览
GetPage(name: '/preview', page: () => const ImagePreview()) GetPage(name: '/preview', page: () => const ImagePreview()),
//
GetPage(name: '/webview', page: () => const WebviewPage())
]; ];
} }

27
lib/utils/cookie.dart Normal file
View File

@ -0,0 +1,27 @@
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:pilipala/http/init.dart';
import 'package:pilipala/utils/utils.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
class SetCookie {
static onSet(List cookiesList, String url) async {
// domain url
List<Cookie> jarCookies = [];
if (cookiesList.isNotEmpty) {
for (var i in cookiesList) {
Cookie jarCookie = Cookie(i.name, i.value);
jarCookies.add(jarCookie);
}
}
String cookiePath = await Utils.getCookiePath();
PersistCookieJar cookieJar = PersistCookieJar(
ignoreExpires: true,
storage: FileStorage(cookiePath),
);
await cookieJar.saveFromResponse(Uri.parse(url), jarCookies);
// 重新设置 cookie
Request.setCookie();
return true;
}
}

View File

@ -262,6 +262,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
flutter_smart_dialog:
dependency: "direct main"
description:
name: flutter_smart_dialog
sha256: da7ed8fe78e301e3c2cdaa533d13ed3edcf1853c1ba1a7383b481739569f7b2a
url: "https://pub.dev"
source: hosted
version: "4.9.0+6"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -725,6 +733,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.3" version: "0.3.3"
webview_cookie_manager:
dependency: "direct main"
description:
name: webview_cookie_manager
sha256: "425a9feac5cd2cb62a71da3dda5ac2eaf9ece5481ee8d79f3868dc5ba8223ad3"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
webview_flutter:
dependency: "direct main"
description:
name: webview_flutter
sha256: "1a37bdbaaf5fbe09ad8579ab09ecfd473284ce482f900b5aea27cf834386a567"
url: "https://pub.dev"
source: hosted
version: "4.2.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: "1acea8def62592123e2fbbca164ed8681a98a890bdcbb88f916d5b4a22687759"
url: "https://pub.dev"
source: hosted
version: "3.7.0"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "78715dc442b7849dbde74e92bb67de1cecf5addf95531c5fb474e72f5fe9a507"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: "61f33512810bf1ee9ac89761a4b02663ff64e8227b7dc80654642acd660fd49d"
url: "https://pub.dev"
source: hosted
version: "3.4.2"
win32: win32:
dependency: transitive dependency: transitive
description: description:

View File

@ -63,9 +63,13 @@ dependencies:
# webView # webView
url_launcher: ^6.1.9 url_launcher: ^6.1.9
flutter_inappwebview: 5.4.4 flutter_inappwebview: 5.4.4
webview_cookie_manager: ^2.0.6
webview_flutter: ^4.2.0
extended_nested_scroll_view: ^6.0.0 extended_nested_scroll_view: ^6.0.0
font_awesome_flutter: ^10.4.0 font_awesome_flutter: ^10.4.0
# toast
flutter_smart_dialog: ^4.9.0+6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -77,6 +81,21 @@ dev_dependencies:
# package. See that file for information about deactivating specific lint # package. See that file for information about deactivating specific lint
# rules and activating additional ones. # rules and activating additional ones.
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
# flutter_launcher_icons:
# git:
# url: https://github.com/nvi9/flutter_launcher_icons.git
# ref: e045d40
flutter_icons:
android: true
ios: true
remove_alpha_ios: false
image_path: assets/images/logo/logo_android.png
image_path_android: assets/images/logo/logo_android.png
image_path_ios: assets/images/logo/logo_ios.png
adaptive_icon_background: "#ffffff"
adaptive_icon_foreground: assets/images/logo/logo_android.png
adaptive_icon_monochrome: assets/images/logo/logo_android.png
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec