mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 03:06:59 +08:00
Compare commits
28 Commits
dev
...
db30aa8041
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db30aa8041 | ||
|
|
6f95456d20 | ||
|
|
de6e402d97 | ||
|
|
6341660788 | ||
|
|
a1dbcae93e | ||
|
|
1526137a64 | ||
|
|
3097b56816 | ||
|
|
db74eccf77 | ||
|
|
14890d342a | ||
|
|
51163dd985 | ||
|
|
f0d9b3a9a7 | ||
|
|
8f3707fbf1 | ||
|
|
f52bbe9804 | ||
|
|
3ec54868d0 | ||
|
|
c0b55f9af3 | ||
|
|
279f21857d | ||
|
|
b897103af0 | ||
|
|
353664fbd4 | ||
|
|
de3505ce07 | ||
|
|
cdc1720358 | ||
|
|
904d210ba2 | ||
|
|
db8dd85b63 | ||
|
|
8ad130567e | ||
|
|
7eb21bc5a2 | ||
|
|
ea4316a847 | ||
|
|
2bbc97a950 | ||
|
|
0178d105ba | ||
|
|
771fa75f48 |
2
.github/workflows/mac.yml
vendored
2
.github/workflows/mac.yml
vendored
@@ -13,7 +13,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-mac-app:
|
build-mac-app:
|
||||||
name: Release Mac
|
name: Release Mac
|
||||||
runs-on: macos-latest
|
runs-on: macos-26
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|||||||
7
.github/workflows/win_x64.yml
vendored
7
.github/workflows/win_x64.yml
vendored
@@ -57,7 +57,6 @@ jobs:
|
|||||||
mv dist/**/*.exe PiliPlus-Win-Setup/PiliPlus_windows_${{env.version}}_x64_setup.exe
|
mv dist/**/*.exe PiliPlus-Win-Setup/PiliPlus_windows_${{env.version}}_x64_setup.exe
|
||||||
|
|
||||||
- name: Compress
|
- name: Compress
|
||||||
if: ${{ github.event.inputs.tag != '' }}
|
|
||||||
run: |
|
run: |
|
||||||
Compress-Archive -Path "Release/PiliPlus-Win" -DestinationPath "PiliPlus_windows_${{env.version}}_x64_portable.zip"
|
Compress-Archive -Path "Release/PiliPlus-Win" -DestinationPath "PiliPlus_windows_${{env.version}}_x64_portable.zip"
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
@@ -75,9 +74,9 @@ jobs:
|
|||||||
- name: Upload windows file release
|
- name: Upload windows file release
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
archive: true
|
archive: false
|
||||||
name: PiliPlus_windows_${{env.version}}_x64_portable
|
name: Windows-file-x64-release
|
||||||
path: Release
|
path: PiliPlus_windows_*.zip
|
||||||
|
|
||||||
- name: Upload windows setup release
|
- name: Upload windows setup release
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.example.piliplus">
|
package="com.example.piliplus">
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
@@ -16,8 +17,7 @@
|
|||||||
</queries>
|
</queries>
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name=
|
<action android:name="android.support.customtabs.action.CustomTabsService" />
|
||||||
"android.support.customtabs.action.CustomTabsService" />
|
|
||||||
</intent>
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
|
|
||||||
@@ -35,56 +35,62 @@
|
|||||||
</intent>
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
|
|
||||||
<application
|
<application xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:enableOnBackInvokedCallback="false"
|
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
android:enableOnBackInvokedCallback="false"
|
||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
tools:replace="android:allowBackup">
|
tools:replace="android:allowBackup">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||||
android:value="false" />
|
android:value="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:theme="@style/LaunchTheme"
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
android:exported="true"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:launchMode="singleTask"
|
||||||
android:supportsPictureInPicture="true"
|
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
>
|
android:supportsPictureInPicture="true"
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
|
||||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
|
<meta-data
|
||||||
|
android:name="android.app.shortcuts"
|
||||||
|
android:resource="@xml/shortcuts" />
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="flutter_deeplinking_enabled"
|
||||||
|
android:value="false" />
|
||||||
|
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
the Android process has started. This theme is visible to the user
|
the Android process has started. This theme is visible to the user
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
to determine the Window background behind the Flutter UI. -->
|
to determine the Window background behind the Flutter UI. -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
android:resource="@style/NormalTheme"
|
android:resource="@style/NormalTheme" />
|
||||||
/>
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter android:label="PiliPlus">
|
<intent-filter android:label="PiliPlus">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="http"/>
|
|
||||||
<data android:scheme="https"/>
|
<data android:scheme="http" />
|
||||||
<data android:host="*.bilibili.com"/>
|
<data android:scheme="https" />
|
||||||
<data android:host="*.bilibili.cn"/>
|
<data android:host="*.bilibili.com" />
|
||||||
<data android:host="*.bilibili.tv"/>
|
<data android:host="*.bilibili.cn" />
|
||||||
<data android:host="bilibili.com"/>
|
<data android:host="*.bilibili.tv" />
|
||||||
<data android:host="bilibili.cn"/>
|
<data android:host="bilibili.com" />
|
||||||
<data android:host="bilibili.tv"/>
|
<data android:host="bilibili.cn" />
|
||||||
|
<data android:host="bilibili.tv" />
|
||||||
<data android:host="b23.tv" />
|
<data android:host="b23.tv" />
|
||||||
<!--<data android:host="live.bilibili.com"/>-->
|
<!--<data android:host="live.bilibili.com"/>-->
|
||||||
<!--<data android:host="www.bilibili.com"/>-->
|
<!--<data android:host="www.bilibili.com"/>-->
|
||||||
@@ -100,36 +106,56 @@
|
|||||||
<intent-filter android:label="PiliPlus">
|
<intent-filter android:label="PiliPlus">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<action android:name="android.intent.action.SEARCH" />
|
<action android:name="android.intent.action.SEARCH" />
|
||||||
|
<action android:name="com.example.piliplus.SHORTCUT" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="bilibili"/>
|
|
||||||
|
<data android:scheme="bilibili" />
|
||||||
|
<data android:host="download" />
|
||||||
<data android:host="forward" />
|
<data android:host="forward" />
|
||||||
<data android:host="comment"
|
<data
|
||||||
|
android:host="comment"
|
||||||
android:pathPattern="/detail/.*/.*/.*" />
|
android:pathPattern="/detail/.*/.*/.*" />
|
||||||
<data android:host="uper" />
|
<data android:host="uper" />
|
||||||
<data android:host="article"
|
<data
|
||||||
|
android:host="article"
|
||||||
android:pathPattern="/readlist" />
|
android:pathPattern="/readlist" />
|
||||||
<data android:host="opus" />
|
<data android:host="opus" />
|
||||||
<data android:host="advertise" android:path="/home" />
|
<data
|
||||||
|
android:host="advertise"
|
||||||
|
android:path="/home" />
|
||||||
<data android:host="clip" />
|
<data android:host="clip" />
|
||||||
<data android:host="search" android:pathPattern=".*" />
|
<data
|
||||||
|
android:host="search"
|
||||||
|
android:pathPattern=".*" />
|
||||||
<data android:host="stardust-search" />
|
<data android:host="stardust-search" />
|
||||||
<data android:host="music" />
|
<data android:host="music" />
|
||||||
<data android:host="cheese" />
|
<data android:host="cheese" />
|
||||||
<data android:host="bangumi"
|
<data
|
||||||
|
android:host="bangumi"
|
||||||
android:pathPattern="/season.*" />
|
android:pathPattern="/season.*" />
|
||||||
<data android:host="bangumi" android:pathPattern="/.*" />
|
<data
|
||||||
<data android:host="pictureshow"
|
android:host="bangumi"
|
||||||
|
android:pathPattern="/.*" />
|
||||||
|
<data
|
||||||
|
android:host="pictureshow"
|
||||||
android:pathPrefix="/creative_center" />
|
android:pathPrefix="/creative_center" />
|
||||||
<data android:host="cliparea" />
|
<data android:host="cliparea" />
|
||||||
<data android:host="im" />
|
<data android:host="im" />
|
||||||
<data android:host="im" android:path="/notifications" />
|
<data
|
||||||
|
android:host="im"
|
||||||
|
android:path="/notifications" />
|
||||||
<data android:host="following" />
|
<data android:host="following" />
|
||||||
<data android:host="following"
|
<data
|
||||||
|
android:host="following"
|
||||||
android:pathPattern="/detail/.*" />
|
android:pathPattern="/detail/.*" />
|
||||||
<data android:host="following"
|
<data
|
||||||
|
android:host="following"
|
||||||
android:path="/publishInfo/" />
|
android:path="/publishInfo/" />
|
||||||
<data android:host="laser" android:pathPattern="/.*" />
|
<data
|
||||||
|
android:host="laser"
|
||||||
|
android:pathPattern="/.*" />
|
||||||
<data android:host="livearea" />
|
<data android:host="livearea" />
|
||||||
<data android:host="live" />
|
<data android:host="live" />
|
||||||
<data android:host="catalog" />
|
<data android:host="catalog" />
|
||||||
@@ -147,28 +173,44 @@
|
|||||||
<data android:host="video" />
|
<data android:host="video" />
|
||||||
<data android:host="story" />
|
<data android:host="story" />
|
||||||
<data android:host="podcast" />
|
<data android:host="podcast" />
|
||||||
<data android:host="main" android:path="/favorite" />
|
<data
|
||||||
<data android:host="pgc" android:path="/theater/match" />
|
android:host="main"
|
||||||
<data android:host="pgc" android:path="/theater/square" />
|
android:path="/favorite" />
|
||||||
<data android:host="m.bilibili.com"
|
<data
|
||||||
|
android:host="pgc"
|
||||||
|
android:path="/theater/match" />
|
||||||
|
<data
|
||||||
|
android:host="pgc"
|
||||||
|
android:path="/theater/square" />
|
||||||
|
<data
|
||||||
|
android:host="m.bilibili.com"
|
||||||
android:path="/topic-detail" />
|
android:path="/topic-detail" />
|
||||||
<data android:host="article" />
|
<data android:host="article" />
|
||||||
<data android:host="pegasus"
|
<data
|
||||||
|
android:host="pegasus"
|
||||||
android:pathPattern="/channel/v2/.*" />
|
android:pathPattern="/channel/v2/.*" />
|
||||||
<data android:host="feed" android:pathPattern="/channel" />
|
<data
|
||||||
|
android:host="feed"
|
||||||
|
android:pathPattern="/channel" />
|
||||||
<data android:host="vip" />
|
<data android:host="vip" />
|
||||||
<data android:host="user_center" android:path="/vip" />
|
<data
|
||||||
|
android:host="user_center"
|
||||||
|
android:path="/vip" />
|
||||||
<data android:host="history" />
|
<data android:host="history" />
|
||||||
<data android:host="charge" android:path="/rank" />
|
<data
|
||||||
|
android:host="charge"
|
||||||
|
android:path="/rank" />
|
||||||
<data android:host="assistant" />
|
<data android:host="assistant" />
|
||||||
<data android:host="feedback" />
|
<data android:host="feedback" />
|
||||||
<data android:host="auth" android:path="/launch" />
|
<data
|
||||||
|
android:host="auth"
|
||||||
|
android:path="/launch" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<service
|
<service
|
||||||
android:name="com.ryanheise.audioservice.AudioService"
|
android:name="com.ryanheise.audioservice.AudioService"
|
||||||
|
android:exported="true"
|
||||||
android:foregroundServiceType="mediaPlayback"
|
android:foregroundServiceType="mediaPlayback"
|
||||||
android:exported="true"
|
|
||||||
tools:ignore="Instantiatable">
|
tools:ignore="Instantiatable">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.media.browse.MediaBrowserService" />
|
<action android:name="android.media.browse.MediaBrowserService" />
|
||||||
@@ -177,32 +219,37 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.yalantis.ucrop.UCropActivity"
|
android:name="com.yalantis.ucrop.UCropActivity"
|
||||||
android:theme="@style/Ucrop.CropTheme"/>
|
android:theme="@style/Ucrop.CropTheme" />
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
|
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
tools:ignore="Instantiatable">
|
tools:ignore="Instantiatable">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
<uses-permission
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
android:maxSdkVersion="28" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<!--
|
<!--
|
||||||
Media access permissions.
|
Media access permissions.
|
||||||
Android 13 or higher.
|
Android 13 or higher.
|
||||||
@@ -210,5 +257,5 @@
|
|||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package com.example.piliplus
|
package com.example.piliplus
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.app.PictureInPictureParams
|
import android.app.PictureInPictureParams
|
||||||
import android.app.SearchManager
|
import android.app.SearchManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
|
import android.content.pm.ShortcutManager
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.drawable.Icon
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
@@ -16,6 +21,7 @@ import com.ryanheise.audioservice.AudioServiceActivity
|
|||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class MainActivity : AudioServiceActivity() {
|
class MainActivity : AudioServiceActivity() {
|
||||||
private lateinit var methodChannel: MethodChannel
|
private lateinit var methodChannel: MethodChannel
|
||||||
@@ -133,6 +139,38 @@ class MainActivity : AudioServiceActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"createShortcut" -> {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
try {
|
||||||
|
val shortcutManager =
|
||||||
|
context.getSystemService(ShortcutManager::class.java)
|
||||||
|
if (shortcutManager.isRequestPinShortcutSupported) {
|
||||||
|
val id = call.argument<String>("id")!!
|
||||||
|
val uri = call.argument<String>("uri")!!
|
||||||
|
val label = call.argument<String>("label")!!
|
||||||
|
val icon = call.argument<String>("icon")!!
|
||||||
|
val bitmap = BitmapFactory.decodeFile(icon)
|
||||||
|
val shortcut =
|
||||||
|
ShortcutInfo.Builder(context, id)
|
||||||
|
.setShortLabel(label)
|
||||||
|
.setIcon(Icon.createWithAdaptiveBitmap(bitmap))
|
||||||
|
.setIntent(Intent(Intent.ACTION_VIEW, uri.toUri()))
|
||||||
|
.build()
|
||||||
|
val pinIntent =
|
||||||
|
shortcutManager.createShortcutResultIntent(shortcut)
|
||||||
|
val pendingIntent = PendingIntent.getBroadcast(
|
||||||
|
context, 0, pinIntent, PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
shortcutManager.requestPinShortcut(
|
||||||
|
shortcut,
|
||||||
|
pendingIntent.intentSender
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
android/app/src/main/res/drawable/download.xml
Normal file
10
android/app/src/main/res/drawable/download.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#515151"
|
||||||
|
android:pathData="M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z" />
|
||||||
|
</vector>
|
||||||
10
android/app/src/main/res/drawable/search.xml
Normal file
10
android/app/src/main/res/drawable/search.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#515151"
|
||||||
|
android:pathData="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
|
||||||
|
</vector>
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">PiliPlus</string>
|
<string name="app_name">PiliPlus</string>
|
||||||
|
<string name="search">搜索</string>
|
||||||
|
<string name="offline_video">离线视频</string>
|
||||||
</resources>
|
</resources>
|
||||||
20
android/app/src/main/res/xml-v25/shortcuts.xml
Normal file
20
android/app/src/main/res/xml-v25/shortcuts.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<shortcut
|
||||||
|
android:icon="@drawable/search"
|
||||||
|
android:shortcutId="search"
|
||||||
|
android:shortcutLongLabel="@string/search"
|
||||||
|
android:shortcutShortLabel="@string/search">
|
||||||
|
<intent
|
||||||
|
android:action="com.example.piliplus.SHORTCUT"
|
||||||
|
android:data="bilibili://search" />
|
||||||
|
</shortcut>
|
||||||
|
<shortcut
|
||||||
|
android:icon="@drawable/download"
|
||||||
|
android:shortcutId="offline_video"
|
||||||
|
android:shortcutLongLabel="@string/offline_video"
|
||||||
|
android:shortcutShortLabel="@string/offline_video">
|
||||||
|
<intent
|
||||||
|
android:action="com.example.piliplus.SHORTCUT"
|
||||||
|
android:data="bilibili://download" />
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|
||||||
@@ -6,8 +6,6 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- audio_session (0.0.1):
|
- audio_session (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- auto_orientation (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- battery_plus (1.0.0):
|
- battery_plus (1.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- chat_bottom_container (0.0.1):
|
- chat_bottom_container (0.0.1):
|
||||||
@@ -83,6 +81,8 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- media_kit_video (0.0.1):
|
- media_kit_video (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- native_device_orientation (0.0.1):
|
||||||
|
- Flutter
|
||||||
- OrderedSet (6.0.3)
|
- OrderedSet (6.0.3)
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -114,7 +114,6 @@ DEPENDENCIES:
|
|||||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||||
- audio_service (from `.symlinks/plugins/audio_service/darwin`)
|
- audio_service (from `.symlinks/plugins/audio_service/darwin`)
|
||||||
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
||||||
- auto_orientation (from `.symlinks/plugins/auto_orientation/ios`)
|
|
||||||
- battery_plus (from `.symlinks/plugins/battery_plus/ios`)
|
- battery_plus (from `.symlinks/plugins/battery_plus/ios`)
|
||||||
- chat_bottom_container (from `.symlinks/plugins/chat_bottom_container/ios`)
|
- chat_bottom_container (from `.symlinks/plugins/chat_bottom_container/ios`)
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
@@ -133,6 +132,7 @@ DEPENDENCIES:
|
|||||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||||
|
- native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- saver_gallery (from `.symlinks/plugins/saver_gallery/ios`)
|
- saver_gallery (from `.symlinks/plugins/saver_gallery/ios`)
|
||||||
@@ -160,8 +160,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/audio_service/darwin"
|
:path: ".symlinks/plugins/audio_service/darwin"
|
||||||
audio_session:
|
audio_session:
|
||||||
:path: ".symlinks/plugins/audio_session/ios"
|
:path: ".symlinks/plugins/audio_session/ios"
|
||||||
auto_orientation:
|
|
||||||
:path: ".symlinks/plugins/auto_orientation/ios"
|
|
||||||
battery_plus:
|
battery_plus:
|
||||||
:path: ".symlinks/plugins/battery_plus/ios"
|
:path: ".symlinks/plugins/battery_plus/ios"
|
||||||
chat_bottom_container:
|
chat_bottom_container:
|
||||||
@@ -198,6 +196,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
|
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
|
||||||
media_kit_video:
|
media_kit_video:
|
||||||
:path: ".symlinks/plugins/media_kit_video/ios"
|
:path: ".symlinks/plugins/media_kit_video/ios"
|
||||||
|
native_device_orientation:
|
||||||
|
:path: ".symlinks/plugins/native_device_orientation/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
@@ -221,7 +221,6 @@ SPEC CHECKSUMS:
|
|||||||
app_links: a754cbec3c255bd4bbb4d236ecc06f28cd9a7ce8
|
app_links: a754cbec3c255bd4bbb4d236ecc06f28cd9a7ce8
|
||||||
audio_service: aa99a6ba2ae7565996015322b0bb024e1d25c6fd
|
audio_service: aa99a6ba2ae7565996015322b0bb024e1d25c6fd
|
||||||
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
|
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
|
||||||
auto_orientation: a1600c9ed72e6e96982fb4e1214463343342432a
|
|
||||||
battery_plus: b42253f6d2dde71712f8c36fef456d99121c5977
|
battery_plus: b42253f6d2dde71712f8c36fef456d99121c5977
|
||||||
chat_bottom_container: f1eb8323db77a87db50f361142c679f11e892d1b
|
chat_bottom_container: f1eb8323db77a87db50f361142c679f11e892d1b
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
@@ -243,6 +242,7 @@ SPEC CHECKSUMS:
|
|||||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||||
media_kit_native_event_loop: 5fba1a849a6c87a34985f1e178a0de5bd444a0cf
|
media_kit_native_event_loop: 5fba1a849a6c87a34985f1e178a0de5bd444a0cf
|
||||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||||
|
native_device_orientation: e3580675687d5034770da198f6839ebf2122ef94
|
||||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||||
|
|||||||
@@ -131,5 +131,13 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIStatusBarHidden</key>
|
<key>UIStatusBarHidden</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>NSLocalNetworkUsageDescription</key>
|
||||||
|
<string>需要访问本地网络以发现和连接 DLNA 投屏设备</string>
|
||||||
|
<key>NSBonjourServices</key>
|
||||||
|
<array>
|
||||||
|
<string>_ssdp._udp</string>
|
||||||
|
<string>_upnp._tcp</string>
|
||||||
|
<string>_http._tcp</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import 'package:flutter/material.dart';
|
|||||||
Widget avatars({
|
Widget avatars({
|
||||||
required ColorScheme colorScheme,
|
required ColorScheme colorScheme,
|
||||||
required Iterable<Owner> users,
|
required Iterable<Owner> users,
|
||||||
|
double gap = 6.0,
|
||||||
}) {
|
}) {
|
||||||
const gap = 6.0;
|
|
||||||
const size = 22.0;
|
const size = 22.0;
|
||||||
const padding = 0.8;
|
const padding = 0.8;
|
||||||
const offset = size - gap;
|
final offset = size - gap;
|
||||||
const imgSize = size - 2 * padding;
|
const imgSize = size - 2 * padding;
|
||||||
if (users.length == 1) {
|
if (users.length == 1) {
|
||||||
return NetworkImgLayer(
|
return NetworkImgLayer(
|
||||||
|
|||||||
777
lib/common/widgets/floating_navigation_bar.dart
Normal file
777
lib/common/widgets/floating_navigation_bar.dart
Normal file
@@ -0,0 +1,777 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:PiliPlus/utils/extension/theme_ext.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
const double _kMaxLabelTextScaleFactor = 1.3;
|
||||||
|
|
||||||
|
const _kNavigationHeight = 64.0;
|
||||||
|
const _kIndicatorHeight = _kNavigationHeight - 2 * _kIndicatorPaddingInt;
|
||||||
|
const _kIndicatorWidth = 86.0;
|
||||||
|
const _kIndicatorPaddingInt = 4.0;
|
||||||
|
const _kIndicatorPadding = EdgeInsets.all(_kIndicatorPaddingInt);
|
||||||
|
const _kBorderRadius = BorderRadius.all(.circular(_kNavigationHeight / 2));
|
||||||
|
const _kNavigationShape = RoundedSuperellipseBorder(
|
||||||
|
borderRadius: _kBorderRadius,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// ref [NavigationBar]
|
||||||
|
class FloatingNavigationBar extends StatelessWidget {
|
||||||
|
// ignore: prefer_const_constructors_in_immutables
|
||||||
|
FloatingNavigationBar({
|
||||||
|
super.key,
|
||||||
|
this.animationDuration = const Duration(milliseconds: 500),
|
||||||
|
this.selectedIndex = 0,
|
||||||
|
required this.destinations,
|
||||||
|
this.onDestinationSelected,
|
||||||
|
this.backgroundColor,
|
||||||
|
this.elevation,
|
||||||
|
this.shadowColor,
|
||||||
|
this.surfaceTintColor,
|
||||||
|
this.indicatorColor,
|
||||||
|
this.indicatorShape,
|
||||||
|
this.labelBehavior,
|
||||||
|
this.overlayColor,
|
||||||
|
this.labelTextStyle,
|
||||||
|
this.labelPadding,
|
||||||
|
this.bottomPadding = 8.0,
|
||||||
|
}) : assert(destinations.length >= 2),
|
||||||
|
assert(0 <= selectedIndex && selectedIndex < destinations.length);
|
||||||
|
|
||||||
|
final Duration animationDuration;
|
||||||
|
final int selectedIndex;
|
||||||
|
final List<Widget> destinations;
|
||||||
|
final ValueChanged<int>? onDestinationSelected;
|
||||||
|
final Color? backgroundColor;
|
||||||
|
final double? elevation;
|
||||||
|
final Color? shadowColor;
|
||||||
|
final Color? surfaceTintColor;
|
||||||
|
final Color? indicatorColor;
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
final NavigationDestinationLabelBehavior? labelBehavior;
|
||||||
|
final WidgetStateProperty<Color?>? overlayColor;
|
||||||
|
final WidgetStateProperty<TextStyle?>? labelTextStyle;
|
||||||
|
final EdgeInsetsGeometry? labelPadding;
|
||||||
|
final double bottomPadding;
|
||||||
|
|
||||||
|
VoidCallback _handleTap(int index) {
|
||||||
|
return onDestinationSelected != null
|
||||||
|
? () => onDestinationSelected!(index)
|
||||||
|
: () {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final defaults = _NavigationBarDefaultsM3(context);
|
||||||
|
|
||||||
|
final navigationBarTheme = NavigationBarTheme.of(context);
|
||||||
|
final effectiveLabelBehavior =
|
||||||
|
labelBehavior ??
|
||||||
|
navigationBarTheme.labelBehavior ??
|
||||||
|
defaults.labelBehavior!;
|
||||||
|
|
||||||
|
final padding = MediaQuery.viewPaddingOf(context);
|
||||||
|
|
||||||
|
return UnconstrainedBox(
|
||||||
|
child: Padding(
|
||||||
|
padding: .fromLTRB(
|
||||||
|
padding.left,
|
||||||
|
0,
|
||||||
|
padding.right,
|
||||||
|
bottomPadding + padding.bottom,
|
||||||
|
),
|
||||||
|
child: SizedBox(
|
||||||
|
height: _kNavigationHeight,
|
||||||
|
width: destinations.length * _kIndicatorWidth,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: ElevationOverlay.applySurfaceTint(
|
||||||
|
backgroundColor ??
|
||||||
|
navigationBarTheme.backgroundColor ??
|
||||||
|
defaults.backgroundColor!,
|
||||||
|
surfaceTintColor ??
|
||||||
|
navigationBarTheme.surfaceTintColor ??
|
||||||
|
defaults.surfaceTintColor,
|
||||||
|
elevation ??
|
||||||
|
navigationBarTheme.elevation ??
|
||||||
|
defaults.elevation!,
|
||||||
|
),
|
||||||
|
shape: RoundedSuperellipseBorder(
|
||||||
|
side: defaults.borderSide,
|
||||||
|
borderRadius: _kBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: _kIndicatorPadding,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: .stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
for (int i = 0; i < destinations.length; i++)
|
||||||
|
Expanded(
|
||||||
|
child: _SelectableAnimatedBuilder(
|
||||||
|
duration: animationDuration,
|
||||||
|
isSelected: i == selectedIndex,
|
||||||
|
builder: (context, animation) {
|
||||||
|
return _NavigationDestinationInfo(
|
||||||
|
index: i,
|
||||||
|
selectedIndex: selectedIndex,
|
||||||
|
totalNumberOfDestinations: destinations.length,
|
||||||
|
selectedAnimation: animation,
|
||||||
|
labelBehavior: effectiveLabelBehavior,
|
||||||
|
indicatorColor: indicatorColor,
|
||||||
|
indicatorShape: indicatorShape,
|
||||||
|
overlayColor: overlayColor,
|
||||||
|
onTap: _handleTap(i),
|
||||||
|
labelTextStyle: labelTextStyle,
|
||||||
|
labelPadding: labelPadding,
|
||||||
|
child: destinations[i],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FloatingNavigationDestination extends StatelessWidget {
|
||||||
|
const FloatingNavigationDestination({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
this.selectedIcon,
|
||||||
|
required this.label,
|
||||||
|
this.tooltip,
|
||||||
|
this.enabled = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget icon;
|
||||||
|
|
||||||
|
final Widget? selectedIcon;
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
final String? tooltip;
|
||||||
|
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final info = _NavigationDestinationInfo.of(context);
|
||||||
|
const selectedState = <WidgetState>{WidgetState.selected};
|
||||||
|
const unselectedState = <WidgetState>{};
|
||||||
|
const disabledState = <WidgetState>{WidgetState.disabled};
|
||||||
|
|
||||||
|
final navigationBarTheme = NavigationBarTheme.of(context);
|
||||||
|
final defaults = _NavigationBarDefaultsM3(context);
|
||||||
|
final animation = info.selectedAnimation;
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
alignment: .center,
|
||||||
|
clipBehavior: .none,
|
||||||
|
children: [
|
||||||
|
NavigationIndicator(
|
||||||
|
animation: animation,
|
||||||
|
color:
|
||||||
|
info.indicatorColor ??
|
||||||
|
navigationBarTheme.indicatorColor ??
|
||||||
|
defaults.indicatorColor!,
|
||||||
|
),
|
||||||
|
_NavigationDestinationBuilder(
|
||||||
|
label: label,
|
||||||
|
tooltip: tooltip,
|
||||||
|
enabled: enabled,
|
||||||
|
buildIcon: (context) {
|
||||||
|
final IconThemeData selectedIconTheme =
|
||||||
|
navigationBarTheme.iconTheme?.resolve(selectedState) ??
|
||||||
|
defaults.iconTheme!.resolve(selectedState)!;
|
||||||
|
final IconThemeData unselectedIconTheme =
|
||||||
|
navigationBarTheme.iconTheme?.resolve(unselectedState) ??
|
||||||
|
defaults.iconTheme!.resolve(unselectedState)!;
|
||||||
|
final IconThemeData disabledIconTheme =
|
||||||
|
navigationBarTheme.iconTheme?.resolve(disabledState) ??
|
||||||
|
defaults.iconTheme!.resolve(disabledState)!;
|
||||||
|
|
||||||
|
final Widget selectedIconWidget = IconTheme.merge(
|
||||||
|
data: enabled ? selectedIconTheme : disabledIconTheme,
|
||||||
|
child: selectedIcon ?? icon,
|
||||||
|
);
|
||||||
|
final Widget unselectedIconWidget = IconTheme.merge(
|
||||||
|
data: enabled ? unselectedIconTheme : disabledIconTheme,
|
||||||
|
child: icon,
|
||||||
|
);
|
||||||
|
return _StatusTransitionWidgetBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (context, child) {
|
||||||
|
return animation.isForwardOrCompleted
|
||||||
|
? selectedIconWidget
|
||||||
|
: unselectedIconWidget;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
buildLabel: (context) {
|
||||||
|
final TextStyle? effectiveSelectedLabelTextStyle =
|
||||||
|
info.labelTextStyle?.resolve(selectedState) ??
|
||||||
|
navigationBarTheme.labelTextStyle?.resolve(selectedState) ??
|
||||||
|
defaults.labelTextStyle!.resolve(selectedState);
|
||||||
|
final TextStyle? effectiveUnselectedLabelTextStyle =
|
||||||
|
info.labelTextStyle?.resolve(unselectedState) ??
|
||||||
|
navigationBarTheme.labelTextStyle?.resolve(unselectedState) ??
|
||||||
|
defaults.labelTextStyle!.resolve(unselectedState);
|
||||||
|
final TextStyle? effectiveDisabledLabelTextStyle =
|
||||||
|
info.labelTextStyle?.resolve(disabledState) ??
|
||||||
|
navigationBarTheme.labelTextStyle?.resolve(disabledState) ??
|
||||||
|
defaults.labelTextStyle!.resolve(disabledState);
|
||||||
|
final EdgeInsetsGeometry labelPadding =
|
||||||
|
info.labelPadding ??
|
||||||
|
navigationBarTheme.labelPadding ??
|
||||||
|
defaults.labelPadding!;
|
||||||
|
|
||||||
|
final textStyle = enabled
|
||||||
|
? animation.isForwardOrCompleted
|
||||||
|
? effectiveSelectedLabelTextStyle
|
||||||
|
: effectiveUnselectedLabelTextStyle
|
||||||
|
: effectiveDisabledLabelTextStyle;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: labelPadding,
|
||||||
|
child: MediaQuery.withClampedTextScaling(
|
||||||
|
maxScaleFactor: _kMaxLabelTextScaleFactor,
|
||||||
|
child: Text(label, style: textStyle),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NavigationDestinationBuilder extends StatefulWidget {
|
||||||
|
const _NavigationDestinationBuilder({
|
||||||
|
required this.buildIcon,
|
||||||
|
required this.buildLabel,
|
||||||
|
required this.label,
|
||||||
|
this.tooltip,
|
||||||
|
this.enabled = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
final WidgetBuilder buildIcon;
|
||||||
|
|
||||||
|
final WidgetBuilder buildLabel;
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
final String? tooltip;
|
||||||
|
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_NavigationDestinationBuilder> createState() =>
|
||||||
|
_NavigationDestinationBuilderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NavigationDestinationBuilderState
|
||||||
|
extends State<_NavigationDestinationBuilder> {
|
||||||
|
final GlobalKey iconKey = GlobalKey();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final info = _NavigationDestinationInfo.of(context);
|
||||||
|
|
||||||
|
final child = GestureDetector(
|
||||||
|
behavior: .opaque,
|
||||||
|
onTap: widget.enabled ? info.onTap : null,
|
||||||
|
child: _NavigationBarDestinationLayout(
|
||||||
|
icon: widget.buildIcon(context),
|
||||||
|
iconKey: iconKey,
|
||||||
|
label: widget.buildLabel(context),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (info.labelBehavior == .alwaysShow) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return _NavigationBarDestinationTooltip(
|
||||||
|
message: widget.tooltip ?? widget.label,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NavigationDestinationInfo extends InheritedWidget {
|
||||||
|
const _NavigationDestinationInfo({
|
||||||
|
required this.index,
|
||||||
|
required this.selectedIndex,
|
||||||
|
required this.totalNumberOfDestinations,
|
||||||
|
required this.selectedAnimation,
|
||||||
|
required this.labelBehavior,
|
||||||
|
required this.indicatorColor,
|
||||||
|
required this.indicatorShape,
|
||||||
|
required this.overlayColor,
|
||||||
|
required this.onTap,
|
||||||
|
this.labelTextStyle,
|
||||||
|
this.labelPadding,
|
||||||
|
required super.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int index;
|
||||||
|
|
||||||
|
final int selectedIndex;
|
||||||
|
|
||||||
|
final int totalNumberOfDestinations;
|
||||||
|
|
||||||
|
final Animation<double> selectedAnimation;
|
||||||
|
|
||||||
|
final NavigationDestinationLabelBehavior labelBehavior;
|
||||||
|
|
||||||
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
|
final WidgetStateProperty<Color?>? overlayColor;
|
||||||
|
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
final WidgetStateProperty<TextStyle?>? labelTextStyle;
|
||||||
|
|
||||||
|
final EdgeInsetsGeometry? labelPadding;
|
||||||
|
|
||||||
|
static _NavigationDestinationInfo of(BuildContext context) {
|
||||||
|
final _NavigationDestinationInfo? result = context
|
||||||
|
.dependOnInheritedWidgetOfExactType<_NavigationDestinationInfo>();
|
||||||
|
assert(
|
||||||
|
result != null,
|
||||||
|
'Navigation destinations need a _NavigationDestinationInfo parent, '
|
||||||
|
'which is usually provided by NavigationBar.',
|
||||||
|
);
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(_NavigationDestinationInfo oldWidget) {
|
||||||
|
return index != oldWidget.index ||
|
||||||
|
totalNumberOfDestinations != oldWidget.totalNumberOfDestinations ||
|
||||||
|
selectedAnimation != oldWidget.selectedAnimation ||
|
||||||
|
labelBehavior != oldWidget.labelBehavior ||
|
||||||
|
onTap != oldWidget.onTap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NavigationIndicator extends StatelessWidget {
|
||||||
|
const NavigationIndicator({
|
||||||
|
super.key,
|
||||||
|
required this.animation,
|
||||||
|
this.color,
|
||||||
|
this.width = _kIndicatorWidth,
|
||||||
|
this.height = _kIndicatorHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Animation<double> animation;
|
||||||
|
|
||||||
|
final Color? color;
|
||||||
|
|
||||||
|
final double width;
|
||||||
|
|
||||||
|
final double height;
|
||||||
|
|
||||||
|
static final _anim = Tween<double>(
|
||||||
|
begin: .5,
|
||||||
|
end: 1.0,
|
||||||
|
).chain(CurveTween(curve: Curves.easeInOutCubicEmphasized));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (context, child) {
|
||||||
|
final double scale = animation.isDismissed
|
||||||
|
? 0.0
|
||||||
|
: _anim.evaluate(animation);
|
||||||
|
|
||||||
|
return Transform(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
transform: Matrix4.diagonal3Values(scale, 1.0, 1.0),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
child: _StatusTransitionWidgetBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (context, child) {
|
||||||
|
return _SelectableAnimatedBuilder(
|
||||||
|
isSelected: animation.isForwardOrCompleted,
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
alwaysDoFullAnimation: true,
|
||||||
|
builder: (context, fadeAnimation) {
|
||||||
|
return FadeTransition(
|
||||||
|
opacity: fadeAnimation,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
shape: _kNavigationShape,
|
||||||
|
color: color ?? Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
child: const SizedBox(
|
||||||
|
width: _kIndicatorWidth,
|
||||||
|
height: _kIndicatorHeight,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NavigationBarDestinationLayout extends StatelessWidget {
|
||||||
|
const _NavigationBarDestinationLayout({
|
||||||
|
required this.icon,
|
||||||
|
required this.iconKey,
|
||||||
|
required this.label,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget icon;
|
||||||
|
|
||||||
|
final GlobalKey iconKey;
|
||||||
|
|
||||||
|
final Widget label;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return _DestinationLayoutAnimationBuilder(
|
||||||
|
builder: (context, animation) {
|
||||||
|
return CustomMultiChildLayout(
|
||||||
|
delegate: _NavigationDestinationLayoutDelegate(animation: animation),
|
||||||
|
children: <Widget>[
|
||||||
|
LayoutId(
|
||||||
|
id: _NavigationDestinationLayoutDelegate.iconId,
|
||||||
|
child: KeyedSubtree(key: iconKey, child: icon),
|
||||||
|
),
|
||||||
|
LayoutId(
|
||||||
|
id: _NavigationDestinationLayoutDelegate.labelId,
|
||||||
|
child: FadeTransition(
|
||||||
|
alwaysIncludeSemantics: true,
|
||||||
|
opacity: animation,
|
||||||
|
child: label,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DestinationLayoutAnimationBuilder extends StatelessWidget {
|
||||||
|
const _DestinationLayoutAnimationBuilder({required this.builder});
|
||||||
|
|
||||||
|
final Widget Function(BuildContext, Animation<double>) builder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final info = _NavigationDestinationInfo.of(context);
|
||||||
|
switch (info.labelBehavior) {
|
||||||
|
case NavigationDestinationLabelBehavior.alwaysShow:
|
||||||
|
return builder(context, kAlwaysCompleteAnimation);
|
||||||
|
case NavigationDestinationLabelBehavior.alwaysHide:
|
||||||
|
return builder(context, kAlwaysDismissedAnimation);
|
||||||
|
case NavigationDestinationLabelBehavior.onlyShowSelected:
|
||||||
|
return _CurvedAnimationBuilder(
|
||||||
|
animation: info.selectedAnimation,
|
||||||
|
curve: Curves.easeInOutCubicEmphasized,
|
||||||
|
reverseCurve: Curves.easeInOutCubicEmphasized.flipped,
|
||||||
|
builder: builder,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NavigationBarDestinationTooltip extends StatelessWidget {
|
||||||
|
const _NavigationBarDestinationTooltip({
|
||||||
|
required this.message,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Tooltip(
|
||||||
|
message: message,
|
||||||
|
verticalOffset: 34,
|
||||||
|
excludeFromSemantics: true,
|
||||||
|
preferBelow: false,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NavigationDestinationLayoutDelegate extends MultiChildLayoutDelegate {
|
||||||
|
_NavigationDestinationLayoutDelegate({required this.animation})
|
||||||
|
: super(relayout: animation);
|
||||||
|
|
||||||
|
final Animation<double> animation;
|
||||||
|
|
||||||
|
static const int iconId = 1;
|
||||||
|
|
||||||
|
static const int labelId = 2;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void performLayout(Size size) {
|
||||||
|
double halfWidth(Size size) => size.width / 2;
|
||||||
|
double halfHeight(Size size) => size.height / 2;
|
||||||
|
|
||||||
|
final Size iconSize = layoutChild(iconId, BoxConstraints.loose(size));
|
||||||
|
final Size labelSize = layoutChild(labelId, BoxConstraints.loose(size));
|
||||||
|
|
||||||
|
final double yPositionOffset = Tween<double>(
|
||||||
|
begin: halfHeight(iconSize),
|
||||||
|
|
||||||
|
end: halfHeight(iconSize) + halfHeight(labelSize),
|
||||||
|
).transform(animation.value);
|
||||||
|
final double iconYPosition = halfHeight(size) - yPositionOffset;
|
||||||
|
|
||||||
|
positionChild(
|
||||||
|
iconId,
|
||||||
|
Offset(
|
||||||
|
halfWidth(size) - halfWidth(iconSize),
|
||||||
|
iconYPosition,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
positionChild(
|
||||||
|
labelId,
|
||||||
|
Offset(
|
||||||
|
halfWidth(size) - halfWidth(labelSize),
|
||||||
|
|
||||||
|
iconYPosition + iconSize.height,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRelayout(_NavigationDestinationLayoutDelegate oldDelegate) {
|
||||||
|
return oldDelegate.animation != animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StatusTransitionWidgetBuilder extends StatusTransitionWidget {
|
||||||
|
const _StatusTransitionWidgetBuilder({
|
||||||
|
required super.animation,
|
||||||
|
required this.builder,
|
||||||
|
// ignore: unused_element_parameter
|
||||||
|
this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final TransitionBuilder builder;
|
||||||
|
|
||||||
|
final Widget? child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => builder(context, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SelectableAnimatedBuilder extends StatefulWidget {
|
||||||
|
const _SelectableAnimatedBuilder({
|
||||||
|
required this.isSelected,
|
||||||
|
this.duration = const Duration(milliseconds: 200),
|
||||||
|
this.alwaysDoFullAnimation = false,
|
||||||
|
required this.builder,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool isSelected;
|
||||||
|
|
||||||
|
final Duration duration;
|
||||||
|
|
||||||
|
final bool alwaysDoFullAnimation;
|
||||||
|
|
||||||
|
final Widget Function(BuildContext, Animation<double>) builder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SelectableAnimatedBuilderState createState() =>
|
||||||
|
_SelectableAnimatedBuilderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SelectableAnimatedBuilderState extends State<_SelectableAnimatedBuilder>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = AnimationController(vsync: this);
|
||||||
|
_controller.duration = widget.duration;
|
||||||
|
_controller.value = widget.isSelected ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(_SelectableAnimatedBuilder oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.duration != widget.duration) {
|
||||||
|
_controller.duration = widget.duration;
|
||||||
|
}
|
||||||
|
if (oldWidget.isSelected != widget.isSelected) {
|
||||||
|
if (widget.isSelected) {
|
||||||
|
_controller.forward(from: widget.alwaysDoFullAnimation ? 0 : null);
|
||||||
|
} else {
|
||||||
|
_controller.reverse(from: widget.alwaysDoFullAnimation ? 1 : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.builder(context, _controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CurvedAnimationBuilder extends StatefulWidget {
|
||||||
|
const _CurvedAnimationBuilder({
|
||||||
|
required this.animation,
|
||||||
|
required this.curve,
|
||||||
|
required this.reverseCurve,
|
||||||
|
required this.builder,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Animation<double> animation;
|
||||||
|
final Curve curve;
|
||||||
|
final Curve reverseCurve;
|
||||||
|
final Widget Function(BuildContext, Animation<double>) builder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CurvedAnimationBuilderState createState() => _CurvedAnimationBuilderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CurvedAnimationBuilderState extends State<_CurvedAnimationBuilder> {
|
||||||
|
late AnimationStatus _animationDirection;
|
||||||
|
AnimationStatus? _preservedDirection;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_animationDirection = widget.animation.status;
|
||||||
|
_updateStatus(widget.animation.status);
|
||||||
|
widget.animation.addStatusListener(_updateStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
widget.animation.removeStatusListener(_updateStatus);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateStatus(AnimationStatus status) {
|
||||||
|
if (_animationDirection != status) {
|
||||||
|
setState(() {
|
||||||
|
_animationDirection = status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
switch (status) {
|
||||||
|
case AnimationStatus.forward || AnimationStatus.reverse
|
||||||
|
when _preservedDirection != null:
|
||||||
|
break;
|
||||||
|
case AnimationStatus.forward || AnimationStatus.reverse:
|
||||||
|
setState(() {
|
||||||
|
_preservedDirection = status;
|
||||||
|
});
|
||||||
|
case AnimationStatus.completed || AnimationStatus.dismissed:
|
||||||
|
setState(() {
|
||||||
|
_preservedDirection = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final shouldUseForwardCurve =
|
||||||
|
(_preservedDirection ?? _animationDirection) != AnimationStatus.reverse;
|
||||||
|
|
||||||
|
final Animation<double> curvedAnimation = CurveTween(
|
||||||
|
curve: shouldUseForwardCurve ? widget.curve : widget.reverseCurve,
|
||||||
|
).animate(widget.animation);
|
||||||
|
|
||||||
|
return widget.builder(context, curvedAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _indicatorDark = Color(0x15FFFFFF);
|
||||||
|
const _indicatorLight = Color(0x10000000);
|
||||||
|
|
||||||
|
class _NavigationBarDefaultsM3 extends NavigationBarThemeData {
|
||||||
|
_NavigationBarDefaultsM3(this.context)
|
||||||
|
: super(
|
||||||
|
height: _kNavigationHeight,
|
||||||
|
elevation: 3.0,
|
||||||
|
labelBehavior: NavigationDestinationLabelBehavior.alwaysShow,
|
||||||
|
);
|
||||||
|
|
||||||
|
final BuildContext context;
|
||||||
|
late final _colors = Theme.of(context).colorScheme;
|
||||||
|
late final _textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
|
BorderSide get borderSide => _colors.brightness.isDark
|
||||||
|
? const BorderSide(color: Color(0x08FFFFFF))
|
||||||
|
: const BorderSide(color: Color(0x08000000));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get backgroundColor => _colors.surfaceContainer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get shadowColor => Colors.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get surfaceTintColor => Colors.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WidgetStateProperty<IconThemeData?>? get iconTheme {
|
||||||
|
return WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||||
|
return IconThemeData(
|
||||||
|
size: 24.0,
|
||||||
|
color: states.contains(WidgetState.disabled)
|
||||||
|
? _colors.onSurfaceVariant.withValues(alpha: 0.38)
|
||||||
|
: states.contains(WidgetState.selected)
|
||||||
|
? _colors.onSecondaryContainer
|
||||||
|
: _colors.onSurfaceVariant,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get indicatorColor =>
|
||||||
|
_colors.brightness.isDark ? _indicatorDark : _indicatorLight;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ShapeBorder? get indicatorShape => const StadiumBorder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
WidgetStateProperty<TextStyle?>? get labelTextStyle {
|
||||||
|
return WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||||
|
final TextStyle style = _textTheme.labelMedium!;
|
||||||
|
return style.apply(
|
||||||
|
color: states.contains(WidgetState.disabled)
|
||||||
|
? _colors.onSurfaceVariant.withValues(alpha: 0.38)
|
||||||
|
: states.contains(WidgetState.selected)
|
||||||
|
? _colors.onSurface
|
||||||
|
: _colors.onSurfaceVariant,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
EdgeInsetsGeometry? get labelPadding => const EdgeInsets.only(top: 2);
|
||||||
|
}
|
||||||
@@ -830,6 +830,10 @@ abstract final class Api {
|
|||||||
|
|
||||||
static const String dynReserve = '/x/dynamic/feed/reserve/click';
|
static const String dynReserve = '/x/dynamic/feed/reserve/click';
|
||||||
|
|
||||||
|
static const String spaceReserve = '/x/space/reserve';
|
||||||
|
|
||||||
|
static const String spaceReserveCancel = '/x/space/reserve/cancel';
|
||||||
|
|
||||||
static const String favPugv = '/pugv/app/web/favorite/page';
|
static const String favPugv = '/pugv/app/web/favorite/page';
|
||||||
|
|
||||||
static const String addFavPugv = '/pugv/app/web/favorite/add';
|
static const String addFavPugv = '/pugv/app/web/favorite/add';
|
||||||
@@ -997,4 +1001,7 @@ abstract final class Api {
|
|||||||
|
|
||||||
static const String liveMedalWall =
|
static const String liveMedalWall =
|
||||||
'${HttpString.liveBaseUrl}/xlive/web-ucenter/user/MedalWall';
|
'${HttpString.liveBaseUrl}/xlive/web-ucenter/user/MedalWall';
|
||||||
|
|
||||||
|
static const String memberGuard =
|
||||||
|
'${HttpString.liveBaseUrl}/xlive/app-ucenter/v1/guard/MainGuardCardAll';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import 'package:PiliPlus/models_new/member/coin_like_arc/data.dart';
|
|||||||
import 'package:PiliPlus/models_new/member/search_archive/data.dart';
|
import 'package:PiliPlus/models_new/member/search_archive/data.dart';
|
||||||
import 'package:PiliPlus/models_new/member/season_web/data.dart';
|
import 'package:PiliPlus/models_new/member/season_web/data.dart';
|
||||||
import 'package:PiliPlus/models_new/member_card_info/data.dart';
|
import 'package:PiliPlus/models_new/member_card_info/data.dart';
|
||||||
|
import 'package:PiliPlus/models_new/member_guard/data.dart';
|
||||||
import 'package:PiliPlus/models_new/space/space/data.dart';
|
import 'package:PiliPlus/models_new/space/space/data.dart';
|
||||||
import 'package:PiliPlus/models_new/space/space_archive/data.dart';
|
import 'package:PiliPlus/models_new/space/space_archive/data.dart';
|
||||||
import 'package:PiliPlus/models_new/space/space_article/data.dart';
|
import 'package:PiliPlus/models_new/space/space_article/data.dart';
|
||||||
@@ -830,4 +831,23 @@ abstract final class MemberHttp {
|
|||||||
return Error(res.data['message']);
|
return Error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<MemberGuardData>> memberGuard({
|
||||||
|
required Object ruid,
|
||||||
|
required int page,
|
||||||
|
}) async {
|
||||||
|
final res = await Request().get(
|
||||||
|
Api.memberGuard,
|
||||||
|
queryParameters: {
|
||||||
|
'page': page,
|
||||||
|
'page_size': 20,
|
||||||
|
'ruid': ruid,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return Success(MemberGuardData.fromJson(res.data['data']));
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -431,7 +431,9 @@ abstract final class UserHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LoadingState<void>> spaceSettingMod(Map data) async {
|
static Future<LoadingState<void>> spaceSettingMod(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
) async {
|
||||||
final res = await Request().post(
|
final res = await Request().post(
|
||||||
Api.spaceSettingMod,
|
Api.spaceSettingMod,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
@@ -569,4 +571,23 @@ abstract final class UserHttp {
|
|||||||
return Error(res.data['message']);
|
return Error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<void>> spaceReserve({
|
||||||
|
required Object sid,
|
||||||
|
required bool isFollow,
|
||||||
|
}) async {
|
||||||
|
final res = await Request().post(
|
||||||
|
isFollow ? Api.spaceReserveCancel : Api.spaceReserve,
|
||||||
|
data: {
|
||||||
|
'sid': sid,
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
},
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return const Success(null);
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:PiliPlus/common/widgets/scale_app.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/scroll_behavior.dart';
|
import 'package:PiliPlus/common/widgets/scroll_behavior.dart';
|
||||||
import 'package:PiliPlus/http/init.dart';
|
import 'package:PiliPlus/http/init.dart';
|
||||||
import 'package:PiliPlus/models/common/theme/theme_color_type.dart';
|
import 'package:PiliPlus/models/common/theme/theme_color_type.dart';
|
||||||
|
import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
|
||||||
import 'package:PiliPlus/router/app_pages.dart';
|
import 'package:PiliPlus/router/app_pages.dart';
|
||||||
import 'package:PiliPlus/services/account_service.dart';
|
import 'package:PiliPlus/services/account_service.dart';
|
||||||
import 'package:PiliPlus/services/download/download_service.dart';
|
import 'package:PiliPlus/services/download/download_service.dart';
|
||||||
@@ -28,6 +29,7 @@ import 'package:PiliPlus/utils/storage_pref.dart';
|
|||||||
import 'package:PiliPlus/utils/theme_utils.dart';
|
import 'package:PiliPlus/utils/theme_utils.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:catcher_2/catcher_2.dart';
|
import 'package:catcher_2/catcher_2.dart';
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:dynamic_color/dynamic_color.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -82,6 +84,10 @@ Future<void> _initAppPath() async {
|
|||||||
appSupportDirPath = (await getApplicationSupportDirectory()).path;
|
appSupportDirPath = (await getApplicationSupportDirectory()).path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initSdkInt() async {
|
||||||
|
Utils.sdkInt = (await DeviceInfoPlugin().androidInfo).version.sdkInt;
|
||||||
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
ScaledWidgetsFlutterBinding.ensureInitialized();
|
ScaledWidgetsFlutterBinding.ensureInitialized();
|
||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
@@ -104,15 +110,8 @@ void main() async {
|
|||||||
|
|
||||||
if (PlatformUtils.isMobile) {
|
if (PlatformUtils.isMobile) {
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
SystemChrome.setPreferredOrientations(
|
if (Platform.isAndroid) _initSdkInt(),
|
||||||
[
|
if (Pref.horizontalScreen) ?fullMode() else ?portraitUpMode(),
|
||||||
DeviceOrientation.portraitUp,
|
|
||||||
if (Pref.horizontalScreen) ...[
|
|
||||||
DeviceOrientation.landscapeLeft,
|
|
||||||
DeviceOrientation.landscapeRight,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
setupServiceLocator(),
|
setupServiceLocator(),
|
||||||
]);
|
]);
|
||||||
} else if (Platform.isWindows) {
|
} else if (Platform.isWindows) {
|
||||||
@@ -131,12 +130,10 @@ void main() async {
|
|||||||
Request.setCookie();
|
Request.setCookie();
|
||||||
RequestUtils.syncHistoryStatus();
|
RequestUtils.syncHistoryStatus();
|
||||||
|
|
||||||
SmartDialog.config.toast = SmartConfigToast(
|
SmartDialog.config.toast = SmartConfigToast(displayType: .onlyRefresh);
|
||||||
displayType: SmartToastType.onlyRefresh,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (PlatformUtils.isMobile) {
|
if (PlatformUtils.isMobile) {
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
SystemChrome.setEnabledSystemUIMode(.edgeToEdge);
|
||||||
SystemChrome.setSystemUIOverlayStyle(
|
SystemChrome.setSystemUIOverlayStyle(
|
||||||
const SystemUiOverlayStyle(
|
const SystemUiOverlayStyle(
|
||||||
systemNavigationBarColor: Colors.transparent,
|
systemNavigationBarColor: Colors.transparent,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ enum AccountType {
|
|||||||
main('主账号'),
|
main('主账号'),
|
||||||
heartbeat('记录观看'),
|
heartbeat('记录观看'),
|
||||||
recommend('推荐'),
|
recommend('推荐'),
|
||||||
video('视频取流')
|
video('视频取流'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ enum AudioNormalization {
|
|||||||
// ref https://github.com/KRTirtho/spotube/commit/da10ab2e291d4ba4d3082b9a6ae535639fb8f1b7
|
// ref https://github.com/KRTirtho/spotube/commit/da10ab2e291d4ba4d3082b9a6ae535639fb8f1b7
|
||||||
dynaudnorm('预设 dynaudnorm', 'dynaudnorm=g=5:f=250:r=0.9:p=0.5'),
|
dynaudnorm('预设 dynaudnorm', 'dynaudnorm=g=5:f=250:r=0.9:p=0.5'),
|
||||||
loudnorm('预设 loudnorm', 'loudnorm=I=-16:LRA=11:TP=-1.5'),
|
loudnorm('预设 loudnorm', 'loudnorm=I=-16:LRA=11:TP=-1.5'),
|
||||||
custom('自定义参数')
|
custom('自定义参数'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ enum BadgeType {
|
|||||||
none(),
|
none(),
|
||||||
vip('大会员'),
|
vip('大会员'),
|
||||||
person('认证个人', Color(0xFFFFCC00)),
|
person('认证个人', Color(0xFFFFCC00)),
|
||||||
institution('认证机构', Colors.lightBlueAccent)
|
institution('认证机构', Colors.lightBlueAccent),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String? desc;
|
final String? desc;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:PiliPlus/models/common/enum_with_label.dart';
|
|||||||
|
|
||||||
enum BarHideType with EnumWithLabel {
|
enum BarHideType with EnumWithLabel {
|
||||||
instant('即时'),
|
instant('即时'),
|
||||||
sync('同步')
|
sync('同步'),
|
||||||
;
|
;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
enum DmBlockType {
|
enum DmBlockType {
|
||||||
keyword('关键词'),
|
keyword('关键词'),
|
||||||
regex('正则'),
|
regex('正则'),
|
||||||
uid('用户')
|
uid('用户'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
enum DynamicBadgeMode {
|
enum DynamicBadgeMode {
|
||||||
hidden('隐藏'),
|
hidden('隐藏'),
|
||||||
point('红点'),
|
point('红点'),
|
||||||
number('数字')
|
number('数字'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String desc;
|
final String desc;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ enum DynamicsTabType {
|
|||||||
video('投稿'),
|
video('投稿'),
|
||||||
pgc('番剧'),
|
pgc('番剧'),
|
||||||
article('专栏'),
|
article('专栏'),
|
||||||
up('UP')
|
up('UP'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ enum UpPanelPosition {
|
|||||||
leftFixed('左侧常驻'),
|
leftFixed('左侧常驻'),
|
||||||
rightFixed('右侧常驻'),
|
rightFixed('右侧常驻'),
|
||||||
leftDrawer('左侧抽屉'),
|
leftDrawer('左侧抽屉'),
|
||||||
rightDrawer('右侧抽屉')
|
rightDrawer('右侧抽屉'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
enum EpisodeType {
|
enum EpisodeType {
|
||||||
part('分P'),
|
part('分P'),
|
||||||
season('合集'),
|
season('合集'),
|
||||||
pgc('剧集')
|
pgc('剧集'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
enum FavOrderType {
|
enum FavOrderType {
|
||||||
mtime('最近收藏'),
|
mtime('最近收藏'),
|
||||||
view('最多播放'),
|
view('最多播放'),
|
||||||
pubtime('最近投稿')
|
pubtime('最近投稿'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ enum FavTabType {
|
|||||||
article('专栏', FavArticlePage()),
|
article('专栏', FavArticlePage()),
|
||||||
note('笔记', FavNotePage()),
|
note('笔记', FavNotePage()),
|
||||||
topic('话题', FavTopicPage()),
|
topic('话题', FavTopicPage()),
|
||||||
cheese('课堂', FavCheesePage())
|
cheese('课堂', FavCheesePage()),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
enum FollowOrderType {
|
enum FollowOrderType {
|
||||||
def('', '最近关注'),
|
def('', '最近关注'),
|
||||||
attention('attention', '最常访问')
|
attention('attention', '最常访问'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String type;
|
final String type;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ enum HomeTabType implements EnumWithLabel {
|
|||||||
hot('热门'),
|
hot('热门'),
|
||||||
rank('分区'),
|
rank('分区'),
|
||||||
bangumi('番剧'),
|
bangumi('番剧'),
|
||||||
cinema('影视')
|
cinema('影视'),
|
||||||
;
|
;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
enum LaterViewType {
|
enum LaterViewType {
|
||||||
all(0, '全部'),
|
all(0, '全部'),
|
||||||
// toView(1, '未看'),
|
// toView(1, '未看'),
|
||||||
unfinished(2, '未看完')
|
unfinished(2, '未看完'),
|
||||||
// viewed(3, '已看完'),
|
// viewed(3, '已看完'),
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ enum LiveContributionRankType {
|
|||||||
online_rank('在线榜', 'contribution_rank'),
|
online_rank('在线榜', 'contribution_rank'),
|
||||||
daily_rank('日榜', 'today_rank'),
|
daily_rank('日榜', 'today_rank'),
|
||||||
weekly_rank('周榜', 'current_week_rank'),
|
weekly_rank('周榜', 'current_week_rank'),
|
||||||
monthly_rank('月榜', 'current_month_rank')
|
monthly_rank('月榜', 'current_month_rank'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ enum ContributeType {
|
|||||||
season(Api.spaceSeason),
|
season(Api.spaceSeason),
|
||||||
series(Api.spaceSeries),
|
series(Api.spaceSeries),
|
||||||
bangumi(Api.spaceBangumi),
|
bangumi(Api.spaceBangumi),
|
||||||
comic(Api.spaceComic)
|
comic(Api.spaceComic),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String api;
|
final String api;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ enum MemberTabType {
|
|||||||
favorite('收藏'),
|
favorite('收藏'),
|
||||||
bangumi('番剧'),
|
bangumi('番剧'),
|
||||||
cheese('课堂'),
|
cheese('课堂'),
|
||||||
shop('小店')
|
shop('小店'),
|
||||||
;
|
;
|
||||||
|
|
||||||
static bool showMemberShop = Pref.showMemberShop;
|
static bool showMemberShop = Pref.showMemberShop;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ enum MsgUnReadType {
|
|||||||
reply('回复我的'),
|
reply('回复我的'),
|
||||||
at('@我'),
|
at('@我'),
|
||||||
like('收到的赞'),
|
like('收到的赞'),
|
||||||
sysMsg('系统通知')
|
sysMsg('系统通知'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import 'package:flutter/material.dart';
|
|||||||
enum NavigationBarType implements EnumWithLabel {
|
enum NavigationBarType implements EnumWithLabel {
|
||||||
home(
|
home(
|
||||||
'首页',
|
'首页',
|
||||||
Icon(Icons.home_outlined, size: 23),
|
Icon(Icons.home_outlined, size: 24),
|
||||||
Icon(Icons.home, size: 21),
|
Icon(Icons.home, size: 24),
|
||||||
HomePage(),
|
HomePage(),
|
||||||
),
|
),
|
||||||
dynamics(
|
dynamics(
|
||||||
@@ -19,10 +19,10 @@ enum NavigationBarType implements EnumWithLabel {
|
|||||||
),
|
),
|
||||||
mine(
|
mine(
|
||||||
'我的',
|
'我的',
|
||||||
Icon(Icons.person_outline, size: 21),
|
Icon(Icons.person_outline, size: 24),
|
||||||
Icon(Icons.person, size: 21),
|
Icon(Icons.person, size: 24),
|
||||||
MinePage(),
|
MinePage(),
|
||||||
)
|
),
|
||||||
;
|
;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:PiliPlus/http/api.dart';
|
|||||||
|
|
||||||
enum PgcReviewType {
|
enum PgcReviewType {
|
||||||
long(label: '长评', api: Api.pgcReviewL),
|
long(label: '长评', api: Api.pgcReviewL),
|
||||||
short(label: '短评', api: Api.pgcReviewS)
|
short(label: '短评', api: Api.pgcReviewS),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
@@ -15,7 +15,7 @@ enum PgcReviewType {
|
|||||||
|
|
||||||
enum PgcReviewSortType {
|
enum PgcReviewSortType {
|
||||||
def('默认', 0),
|
def('默认', 0),
|
||||||
latest('最新', 1)
|
latest('最新', 1),
|
||||||
;
|
;
|
||||||
|
|
||||||
final int sort;
|
final int sort;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ enum RankType {
|
|||||||
documentary('记录', seasonType: 3),
|
documentary('记录', seasonType: 3),
|
||||||
movie('电影', seasonType: 2),
|
movie('电影', seasonType: 2),
|
||||||
tv('剧集', seasonType: 5),
|
tv('剧集', seasonType: 5),
|
||||||
variety('综艺', seasonType: 7)
|
variety('综艺', seasonType: 7),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
|
|||||||
enum ReplyOptionType {
|
enum ReplyOptionType {
|
||||||
allow('允许评论'),
|
allow('允许评论'),
|
||||||
close('关闭评论'),
|
close('关闭评论'),
|
||||||
choose('精选评论')
|
choose('精选评论'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
enum ReplySortType {
|
enum ReplySortType {
|
||||||
time('最新评论', '最新'),
|
time('最新评论', '最新'),
|
||||||
hot('最热评论', '最热'),
|
hot('最热评论', '最热'),
|
||||||
select('精选评论', '精选')
|
select('精选评论', '精选'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ enum ArticleOrderType {
|
|||||||
pubdate('最新发布'),
|
pubdate('最新发布'),
|
||||||
click('最多点击'),
|
click('最多点击'),
|
||||||
attention('最多喜欢'),
|
attention('最多喜欢'),
|
||||||
scores('最多评论')
|
scores('最多评论'),
|
||||||
;
|
;
|
||||||
|
|
||||||
String get order => name;
|
String get order => name;
|
||||||
@@ -20,7 +20,7 @@ enum ArticleZoneType {
|
|||||||
interest('兴趣', 29),
|
interest('兴趣', 29),
|
||||||
novel('轻小说', 16),
|
novel('轻小说', 16),
|
||||||
tech('科技', 17),
|
tech('科技', 17),
|
||||||
note('笔记', 41)
|
note('笔记', 41),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ enum SearchType {
|
|||||||
// 用户:bili_user
|
// 用户:bili_user
|
||||||
bili_user('用户'),
|
bili_user('用户'),
|
||||||
// 专栏:article
|
// 专栏:article
|
||||||
article('专栏')
|
article('专栏'),
|
||||||
;
|
;
|
||||||
// 相簿:photo
|
// 相簿:photo
|
||||||
// photo
|
// photo
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ enum UserOrderType {
|
|||||||
fansDesc('粉丝数由高到低', 0, 'fans'),
|
fansDesc('粉丝数由高到低', 0, 'fans'),
|
||||||
fansAsc('粉丝数由低到高', 1, 'fans'),
|
fansAsc('粉丝数由低到高', 1, 'fans'),
|
||||||
levelDesc('Lv等级由高到低', 0, 'level'),
|
levelDesc('Lv等级由高到低', 0, 'level'),
|
||||||
levelAsc('Lv等级由低到高', 1, 'level')
|
levelAsc('Lv等级由低到高', 1, 'level'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
@@ -16,7 +16,7 @@ enum UserType {
|
|||||||
all('全部用户'),
|
all('全部用户'),
|
||||||
up('UP主'),
|
up('UP主'),
|
||||||
common('普通用户'),
|
common('普通用户'),
|
||||||
verified('认证用户')
|
verified('认证用户'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ enum VideoPubTimeType {
|
|||||||
all('不限'),
|
all('不限'),
|
||||||
day('最近一天'),
|
day('最近一天'),
|
||||||
week('最近一周'),
|
week('最近一周'),
|
||||||
halfYear('最近半年')
|
halfYear('最近半年'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
@@ -14,7 +14,7 @@ enum VideoDurationType {
|
|||||||
tenMins('0-10分钟'),
|
tenMins('0-10分钟'),
|
||||||
halfHour('10-30分钟'),
|
halfHour('10-30分钟'),
|
||||||
hour('30-60分钟'),
|
hour('30-60分钟'),
|
||||||
hourPlus('60分钟+')
|
hourPlus('60分钟+'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
@@ -43,7 +43,7 @@ enum VideoZoneType {
|
|||||||
cinephile('影视', tids: 181),
|
cinephile('影视', tids: 181),
|
||||||
documentary('记录', tids: 177),
|
documentary('记录', tids: 177),
|
||||||
movie('电影', tids: 23),
|
movie('电影', tids: 23),
|
||||||
tv('电视', tids: 11)
|
tv('电视', tids: 11),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
@@ -58,7 +58,7 @@ enum ArchiveFilterType {
|
|||||||
pubdate('新发布'),
|
pubdate('新发布'),
|
||||||
dm('弹幕多'),
|
dm('弹幕多'),
|
||||||
stow('收藏多'),
|
stow('收藏多'),
|
||||||
scores('评论多')
|
scores('评论多'),
|
||||||
;
|
;
|
||||||
// 专栏
|
// 专栏
|
||||||
// attention('最多喜欢'),
|
// attention('最多喜欢'),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ enum SettingType {
|
|||||||
styleSetting('外观设置'),
|
styleSetting('外观设置'),
|
||||||
extraSetting('其它设置'),
|
extraSetting('其它设置'),
|
||||||
webdavSetting('WebDAV 设置'),
|
webdavSetting('WebDAV 设置'),
|
||||||
about('关于')
|
about('关于'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ enum ActionType {
|
|||||||
skip('跳过'),
|
skip('跳过'),
|
||||||
mute('静音'),
|
mute('静音'),
|
||||||
full('整个视频'),
|
full('整个视频'),
|
||||||
poi('精彩时刻')
|
poi('精彩时刻'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ enum SkipType implements EnumWithLabel {
|
|||||||
skipOnce('跳过一次'),
|
skipOnce('跳过一次'),
|
||||||
skipManually('手动跳过'),
|
skipManually('手动跳过'),
|
||||||
showOnly('仅显示'),
|
showOnly('仅显示'),
|
||||||
disable('禁用')
|
disable('禁用'),
|
||||||
;
|
;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ enum StatType {
|
|||||||
reply(Icons.comment_outlined, '评论'),
|
reply(Icons.comment_outlined, '评论'),
|
||||||
follow(Icons.favorite_border, '关注'),
|
follow(Icons.favorite_border, '关注'),
|
||||||
play(Icons.play_circle_outlined, '播放'),
|
play(Icons.play_circle_outlined, '播放'),
|
||||||
listen(Icons.headset_outlined, '播放')
|
listen(Icons.headset_outlined, '播放'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final IconData iconData;
|
final IconData iconData;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:PiliPlus/models/common/enum_with_label.dart';
|
|||||||
enum SuperResolutionType with EnumWithLabel {
|
enum SuperResolutionType with EnumWithLabel {
|
||||||
disable('禁用'),
|
disable('禁用'),
|
||||||
efficiency('效率'),
|
efficiency('效率'),
|
||||||
quality('画质')
|
quality('画质'),
|
||||||
;
|
;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
|
|||||||
enum ThemeType {
|
enum ThemeType {
|
||||||
light('浅色'),
|
light('浅色'),
|
||||||
dark('深色'),
|
dark('深色'),
|
||||||
system('跟随系统')
|
system('跟随系统'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String desc;
|
final String desc;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ enum AudioQuality {
|
|||||||
dolby_30255(30255, '杜比全景声'),
|
dolby_30255(30255, '杜比全景声'),
|
||||||
k192(30280, '192K'),
|
k192(30280, '192K'),
|
||||||
k132(30232, '132K'),
|
k132(30232, '132K'),
|
||||||
k64(30216, '64K')
|
k64(30216, '64K'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final int code;
|
final int code;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ enum CDNService {
|
|||||||
aliov('aliov(阿里云海外)', 'upos-sz-mirroraliov.bilivideo.com'),
|
aliov('aliov(阿里云海外)', 'upos-sz-mirroraliov.bilivideo.com'),
|
||||||
cosov('cosov(腾讯云海外)', 'upos-sz-mirrorcosov.bilivideo.com'),
|
cosov('cosov(腾讯云海外)', 'upos-sz-mirrorcosov.bilivideo.com'),
|
||||||
hwov('hwov(华为云海外)', 'upos-sz-mirrorhwov.bilivideo.com'),
|
hwov('hwov(华为云海外)', 'upos-sz-mirrorhwov.bilivideo.com'),
|
||||||
hk_bcache('hk_bcache(Bilibili海外)', 'cn-hk-eq-bcache-01.bilivideo.com')
|
hk_bcache('hk_bcache(Bilibili海外)', 'cn-hk-eq-bcache-01.bilivideo.com'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String desc;
|
final String desc;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ enum LiveQuality {
|
|||||||
bluRay(400, '蓝光'),
|
bluRay(400, '蓝光'),
|
||||||
superHD(250, '超清'),
|
superHD(250, '超清'),
|
||||||
smooth(150, '高清'),
|
smooth(150, '高清'),
|
||||||
flunt(80, '流畅')
|
flunt(80, '流畅'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final int code;
|
final int code;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ enum SourceType {
|
|||||||
extraId: 4,
|
extraId: 4,
|
||||||
playlistSource: PlaylistSource.MEDIA_LIST,
|
playlistSource: PlaylistSource.MEDIA_LIST,
|
||||||
),
|
),
|
||||||
file
|
file,
|
||||||
;
|
;
|
||||||
|
|
||||||
final int? mediaType;
|
final int? mediaType;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ enum SubtitlePrefType {
|
|||||||
off('默认不显示字幕'),
|
off('默认不显示字幕'),
|
||||||
on('优先选择非自动生成(ai)字幕'),
|
on('优先选择非自动生成(ai)字幕'),
|
||||||
withoutAi('跳过自动生成(ai)字幕,选择第一个可用字幕'),
|
withoutAi('跳过自动生成(ai)字幕,选择第一个可用字幕'),
|
||||||
auto('静音时等同第二项,非静音时等同第三项')
|
auto('静音时等同第二项,非静音时等同第三项'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String desc;
|
final String desc;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ enum VideoDecodeFormatType {
|
|||||||
DVH1(['dvh1']),
|
DVH1(['dvh1']),
|
||||||
AV1(['av01']),
|
AV1(['av01']),
|
||||||
HEVC(['hev1', 'hvc1']),
|
HEVC(['hev1', 'hvc1']),
|
||||||
AVC(['avc1'])
|
AVC(['avc1']),
|
||||||
;
|
;
|
||||||
|
|
||||||
String get description => name;
|
String get description => name;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ enum VideoQuality {
|
|||||||
high720(64, '720P 准高清', '720P'),
|
high720(64, '720P 准高清', '720P'),
|
||||||
clear480(32, '480P 标清', '480P'),
|
clear480(32, '480P 标清', '480P'),
|
||||||
fluent360(16, '360P 流畅', '360P'),
|
fluent360(16, '360P 流畅', '360P'),
|
||||||
speed240(6, '240P 极速', '240P')
|
speed240(6, '240P 极速', '240P'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final int code;
|
final int code;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ enum VideoType {
|
|||||||
type: 10,
|
type: 10,
|
||||||
replyType: 33,
|
replyType: 33,
|
||||||
api: Api.pugvUrl,
|
api: Api.pugvUrl,
|
||||||
)
|
),
|
||||||
;
|
;
|
||||||
|
|
||||||
final int type;
|
final int type;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ enum WebviewMenuItem {
|
|||||||
openInBrowser('浏览器中打开'),
|
openInBrowser('浏览器中打开'),
|
||||||
clearCache('清除缓存'),
|
clearCache('清除缓存'),
|
||||||
resetCookie('重新设置Cookie'),
|
resetCookie('重新设置Cookie'),
|
||||||
goBack('返回')
|
goBack('返回'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -5,19 +5,7 @@ class AccountMyInfoData {
|
|||||||
num? coins;
|
num? coins;
|
||||||
String? birthday;
|
String? birthday;
|
||||||
String? face;
|
String? face;
|
||||||
int? faceNftNew;
|
|
||||||
int? sex;
|
int? sex;
|
||||||
int? level;
|
|
||||||
int? rank;
|
|
||||||
int? silence;
|
|
||||||
int? emailStatus;
|
|
||||||
int? telStatus;
|
|
||||||
int? identification;
|
|
||||||
int? isTourist;
|
|
||||||
int? pinPrompting;
|
|
||||||
int? inRegAudit;
|
|
||||||
bool? hasFaceNft;
|
|
||||||
bool? setBirthday;
|
|
||||||
|
|
||||||
AccountMyInfoData({
|
AccountMyInfoData({
|
||||||
this.mid,
|
this.mid,
|
||||||
@@ -26,19 +14,7 @@ class AccountMyInfoData {
|
|||||||
this.coins,
|
this.coins,
|
||||||
this.birthday,
|
this.birthday,
|
||||||
this.face,
|
this.face,
|
||||||
this.faceNftNew,
|
|
||||||
this.sex,
|
this.sex,
|
||||||
this.level,
|
|
||||||
this.rank,
|
|
||||||
this.silence,
|
|
||||||
this.emailStatus,
|
|
||||||
this.telStatus,
|
|
||||||
this.identification,
|
|
||||||
this.isTourist,
|
|
||||||
this.pinPrompting,
|
|
||||||
this.inRegAudit,
|
|
||||||
this.hasFaceNft,
|
|
||||||
this.setBirthday,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory AccountMyInfoData.fromJson(Map<String, dynamic> json) =>
|
factory AccountMyInfoData.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -49,18 +25,6 @@ class AccountMyInfoData {
|
|||||||
coins: json['coins'] as num?,
|
coins: json['coins'] as num?,
|
||||||
birthday: json['birthday'] as String?,
|
birthday: json['birthday'] as String?,
|
||||||
face: json['face'] as String?,
|
face: json['face'] as String?,
|
||||||
faceNftNew: json['face_nft_new'] as int?,
|
|
||||||
sex: json['sex'] as int?,
|
sex: json['sex'] as int?,
|
||||||
level: json['level'] as int?,
|
|
||||||
rank: json['rank'] as int?,
|
|
||||||
silence: json['silence'] as int?,
|
|
||||||
emailStatus: json['email_status'] as int?,
|
|
||||||
telStatus: json['tel_status'] as int?,
|
|
||||||
identification: json['identification'] as int?,
|
|
||||||
isTourist: json['is_tourist'] as int?,
|
|
||||||
pinPrompting: json['pin_prompting'] as int?,
|
|
||||||
inRegAudit: json['in_reg_audit'] as int?,
|
|
||||||
hasFaceNft: json['has_face_nft'] as bool?,
|
|
||||||
setBirthday: json['set_birthday'] as bool?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,26 @@
|
|||||||
import 'package:PiliPlus/models_new/article/article_info/share_channel.dart';
|
|
||||||
import 'package:PiliPlus/models_new/article/article_info/stats.dart';
|
import 'package:PiliPlus/models_new/article/article_info/stats.dart';
|
||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
|
|
||||||
class ArticleInfoData {
|
class ArticleInfoData {
|
||||||
int? like;
|
|
||||||
bool? attention;
|
|
||||||
bool? favorite;
|
bool? favorite;
|
||||||
num? coin;
|
|
||||||
Stats? stats;
|
Stats? stats;
|
||||||
String? title;
|
String? title;
|
||||||
String? bannerUrl;
|
|
||||||
int? mid;
|
|
||||||
String? authorName;
|
|
||||||
bool? isAuthor;
|
|
||||||
List<String>? imageUrls;
|
|
||||||
List<String>? originImageUrls;
|
List<String>? originImageUrls;
|
||||||
bool? shareable;
|
|
||||||
bool? showLaterWatch;
|
|
||||||
bool? showSmallWindow;
|
|
||||||
bool? inList;
|
|
||||||
int? pre;
|
|
||||||
int? next;
|
|
||||||
List<ShareChannel>? shareChannels;
|
|
||||||
int? type;
|
|
||||||
String? videoUrl;
|
|
||||||
String? location;
|
|
||||||
bool? disableShare;
|
|
||||||
|
|
||||||
ArticleInfoData({
|
ArticleInfoData({
|
||||||
this.like,
|
|
||||||
this.attention,
|
|
||||||
this.favorite,
|
this.favorite,
|
||||||
this.coin,
|
|
||||||
this.stats,
|
this.stats,
|
||||||
this.title,
|
this.title,
|
||||||
this.bannerUrl,
|
|
||||||
this.mid,
|
|
||||||
this.authorName,
|
|
||||||
this.isAuthor,
|
|
||||||
this.imageUrls,
|
|
||||||
this.originImageUrls,
|
this.originImageUrls,
|
||||||
this.shareable,
|
|
||||||
this.showLaterWatch,
|
|
||||||
this.showSmallWindow,
|
|
||||||
this.inList,
|
|
||||||
this.pre,
|
|
||||||
this.next,
|
|
||||||
this.shareChannels,
|
|
||||||
this.type,
|
|
||||||
this.videoUrl,
|
|
||||||
this.location,
|
|
||||||
this.disableShare,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ArticleInfoData.fromJson(Map<String, dynamic> json) =>
|
factory ArticleInfoData.fromJson(Map<String, dynamic> json) =>
|
||||||
ArticleInfoData(
|
ArticleInfoData(
|
||||||
like: json['like'] as int?,
|
|
||||||
attention: json['attention'] as bool?,
|
|
||||||
favorite: json['favorite'] as bool?,
|
favorite: json['favorite'] as bool?,
|
||||||
coin: json['coin'] as num?,
|
|
||||||
stats: json['stats'] == null
|
stats: json['stats'] == null
|
||||||
? null
|
? null
|
||||||
: Stats.fromJson(json['stats'] as Map<String, dynamic>),
|
: Stats.fromJson(json['stats'] as Map<String, dynamic>),
|
||||||
title: json['title'] as String?,
|
title: json['title'] as String?,
|
||||||
bannerUrl: json['banner_url'] as String?,
|
|
||||||
mid: json['mid'] as int?,
|
|
||||||
authorName: json['author_name'] as String?,
|
|
||||||
isAuthor: json['is_author'] as bool?,
|
|
||||||
imageUrls: (json['image_urls'] as List?)?.fromCast(),
|
|
||||||
originImageUrls: (json['origin_image_urls'] as List?)?.fromCast(),
|
originImageUrls: (json['origin_image_urls'] as List?)?.fromCast(),
|
||||||
shareable: json['shareable'] as bool?,
|
|
||||||
showLaterWatch: json['show_later_watch'] as bool?,
|
|
||||||
showSmallWindow: json['show_small_window'] as bool?,
|
|
||||||
inList: json['in_list'] as bool?,
|
|
||||||
pre: json['pre'] as int?,
|
|
||||||
next: json['next'] as int?,
|
|
||||||
shareChannels: (json['share_channels'] as List<dynamic>?)
|
|
||||||
?.map((e) => ShareChannel.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
type: json['type'] as int?,
|
|
||||||
videoUrl: json['video_url'] as String?,
|
|
||||||
location: json['location'] as String?,
|
|
||||||
disableShare: json['disable_share'] as bool?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
class ShareChannel {
|
|
||||||
String? name;
|
|
||||||
String? picture;
|
|
||||||
String? shareChannel;
|
|
||||||
|
|
||||||
ShareChannel({this.name, this.picture, this.shareChannel});
|
|
||||||
|
|
||||||
factory ShareChannel.fromJson(Map<String, dynamic> json) => ShareChannel(
|
|
||||||
name: json['name'] as String?,
|
|
||||||
picture: json['picture'] as String?,
|
|
||||||
shareChannel: json['share_channel'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,32 +1,20 @@
|
|||||||
class Stats {
|
class Stats {
|
||||||
int? view;
|
|
||||||
int? favorite;
|
int? favorite;
|
||||||
int? like;
|
int? like;
|
||||||
int? dislike;
|
|
||||||
int? reply;
|
int? reply;
|
||||||
int? share;
|
int? share;
|
||||||
num? coin;
|
|
||||||
int? dynam1c;
|
|
||||||
|
|
||||||
Stats({
|
Stats({
|
||||||
this.view,
|
|
||||||
this.favorite,
|
this.favorite,
|
||||||
this.like,
|
this.like,
|
||||||
this.dislike,
|
|
||||||
this.reply,
|
this.reply,
|
||||||
this.share,
|
this.share,
|
||||||
this.coin,
|
|
||||||
this.dynam1c,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Stats.fromJson(Map<String, dynamic> json) => Stats(
|
factory Stats.fromJson(Map<String, dynamic> json) => Stats(
|
||||||
view: json['view'] as int?,
|
|
||||||
favorite: json['favorite'] as int?,
|
favorite: json['favorite'] as int?,
|
||||||
like: json['like'] as int?,
|
like: json['like'] as int?,
|
||||||
dislike: json['dislike'] as int?,
|
|
||||||
reply: json['reply'] as int?,
|
reply: json['reply'] as int?,
|
||||||
share: json['share'] as int?,
|
share: json['share'] as int?,
|
||||||
coin: json['coin'] as num?,
|
|
||||||
dynam1c: json['dynamic'] as int?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,32 @@
|
|||||||
import 'package:PiliPlus/models_new/article/article_list/category.dart';
|
|
||||||
import 'package:PiliPlus/models_new/article/article_list/stats.dart';
|
import 'package:PiliPlus/models_new/article/article_list/stats.dart';
|
||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
|
|
||||||
class ArticleListItemModel {
|
class ArticleListItemModel {
|
||||||
int? id;
|
int? id;
|
||||||
String? title;
|
String? title;
|
||||||
int? state;
|
|
||||||
int? publishTime;
|
|
||||||
int? words;
|
|
||||||
List<String>? imageUrls;
|
List<String>? imageUrls;
|
||||||
Category? category;
|
|
||||||
List<Category>? categories;
|
|
||||||
String? summary;
|
String? summary;
|
||||||
int? type;
|
|
||||||
String? dynIdStr;
|
String? dynIdStr;
|
||||||
int? attributes;
|
|
||||||
int? authorUid;
|
|
||||||
int? onlyFans;
|
|
||||||
Stats? stats;
|
Stats? stats;
|
||||||
int? likeState;
|
|
||||||
|
|
||||||
ArticleListItemModel({
|
ArticleListItemModel({
|
||||||
this.id,
|
this.id,
|
||||||
this.title,
|
this.title,
|
||||||
this.state,
|
|
||||||
this.publishTime,
|
|
||||||
this.words,
|
|
||||||
this.imageUrls,
|
this.imageUrls,
|
||||||
this.category,
|
|
||||||
this.categories,
|
|
||||||
this.summary,
|
this.summary,
|
||||||
this.type,
|
|
||||||
this.dynIdStr,
|
this.dynIdStr,
|
||||||
this.attributes,
|
|
||||||
this.authorUid,
|
|
||||||
this.onlyFans,
|
|
||||||
this.stats,
|
this.stats,
|
||||||
this.likeState,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ArticleListItemModel.fromJson(Map<String, dynamic> json) =>
|
factory ArticleListItemModel.fromJson(Map<String, dynamic> json) =>
|
||||||
ArticleListItemModel(
|
ArticleListItemModel(
|
||||||
id: json['id'] as int?,
|
id: json['id'] as int?,
|
||||||
title: json['title'] as String?,
|
title: json['title'] as String?,
|
||||||
state: json['state'] as int?,
|
|
||||||
publishTime: json['publish_time'] as int?,
|
|
||||||
words: json['words'] as int?,
|
|
||||||
imageUrls: (json['image_urls'] as List?)?.fromCast(),
|
imageUrls: (json['image_urls'] as List?)?.fromCast(),
|
||||||
category: json['category'] == null
|
|
||||||
? null
|
|
||||||
: Category.fromJson(json['category'] as Map<String, dynamic>),
|
|
||||||
categories: (json['categories'] as List<dynamic>?)
|
|
||||||
?.map((e) => Category.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
summary: json['summary'] as String?,
|
summary: json['summary'] as String?,
|
||||||
type: json['type'] as int?,
|
|
||||||
dynIdStr: json['dyn_id_str'] as String?,
|
dynIdStr: json['dyn_id_str'] as String?,
|
||||||
attributes: json['attributes'] as int?,
|
|
||||||
authorUid: json['author_uid'] as int?,
|
|
||||||
onlyFans: json['only_fans'] as int?,
|
|
||||||
stats: json['stats'] == null
|
stats: json['stats'] == null
|
||||||
? null
|
? null
|
||||||
: Stats.fromJson(json['stats'] as Map<String, dynamic>),
|
: Stats.fromJson(json['stats'] as Map<String, dynamic>),
|
||||||
likeState: json['like_state'] as int?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
class Category {
|
|
||||||
int? id;
|
|
||||||
int? parentId;
|
|
||||||
String? name;
|
|
||||||
|
|
||||||
Category({this.id, this.parentId, this.name});
|
|
||||||
|
|
||||||
factory Category.fromJson(Map<String, dynamic> json) => Category(
|
|
||||||
id: json['id'] as int?,
|
|
||||||
parentId: json['parent_id'] as int?,
|
|
||||||
name: json['name'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,16 @@
|
|||||||
import 'package:PiliPlus/models/model_owner.dart';
|
import 'package:PiliPlus/models/model_owner.dart';
|
||||||
import 'package:PiliPlus/models_new/article/article_list/article.dart';
|
import 'package:PiliPlus/models_new/article/article_list/article.dart';
|
||||||
import 'package:PiliPlus/models_new/article/article_list/last.dart';
|
|
||||||
import 'package:PiliPlus/models_new/article/article_list/list.dart';
|
import 'package:PiliPlus/models_new/article/article_list/list.dart';
|
||||||
|
|
||||||
class ArticleListData {
|
class ArticleListData {
|
||||||
ArticleListInfo? list;
|
ArticleListInfo? list;
|
||||||
List<ArticleListItemModel>? articles;
|
List<ArticleListItemModel>? articles;
|
||||||
Owner? author;
|
Owner? author;
|
||||||
Last? last;
|
|
||||||
bool? attention;
|
|
||||||
|
|
||||||
ArticleListData({
|
ArticleListData({
|
||||||
this.list,
|
this.list,
|
||||||
this.articles,
|
this.articles,
|
||||||
this.author,
|
this.author,
|
||||||
this.last,
|
|
||||||
this.attention,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ArticleListData.fromJson(Map<String, dynamic> json) =>
|
factory ArticleListData.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -31,9 +26,5 @@ class ArticleListData {
|
|||||||
author: json['author'] == null
|
author: json['author'] == null
|
||||||
? null
|
? null
|
||||||
: Owner.fromJson(json['author'] as Map<String, dynamic>),
|
: Owner.fromJson(json['author'] as Map<String, dynamic>),
|
||||||
last: json['last'] == null
|
|
||||||
? null
|
|
||||||
: Last.fromJson(json['last'] as Map<String, dynamic>),
|
|
||||||
attention: json['attention'] as bool?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
class Label {
|
|
||||||
String? path;
|
|
||||||
String? text;
|
|
||||||
String? labelTheme;
|
|
||||||
|
|
||||||
Label({this.path, this.text, this.labelTheme});
|
|
||||||
|
|
||||||
factory Label.fromJson(Map<String, dynamic> json) => Label(
|
|
||||||
path: json['path'] as String?,
|
|
||||||
text: json['text'] as String?,
|
|
||||||
labelTheme: json['label_theme'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
import 'package:PiliPlus/models_new/article/article_list/category.dart';
|
|
||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
|
||||||
|
|
||||||
class Last {
|
|
||||||
int? id;
|
|
||||||
String? title;
|
|
||||||
int? state;
|
|
||||||
int? publishTime;
|
|
||||||
int? words;
|
|
||||||
List<String>? imageUrls;
|
|
||||||
Category? category;
|
|
||||||
dynamic categories;
|
|
||||||
String? summary;
|
|
||||||
int? type;
|
|
||||||
String? dynIdStr;
|
|
||||||
int? attributes;
|
|
||||||
int? authorUid;
|
|
||||||
int? onlyFans;
|
|
||||||
|
|
||||||
Last({
|
|
||||||
this.id,
|
|
||||||
this.title,
|
|
||||||
this.state,
|
|
||||||
this.publishTime,
|
|
||||||
this.words,
|
|
||||||
this.imageUrls,
|
|
||||||
this.category,
|
|
||||||
this.categories,
|
|
||||||
this.summary,
|
|
||||||
this.type,
|
|
||||||
this.dynIdStr,
|
|
||||||
this.attributes,
|
|
||||||
this.authorUid,
|
|
||||||
this.onlyFans,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory Last.fromJson(Map<String, dynamic> json) => Last(
|
|
||||||
id: json['id'] as int?,
|
|
||||||
title: json['title'] as String?,
|
|
||||||
state: json['state'] as int?,
|
|
||||||
publishTime: json['publish_time'] as int?,
|
|
||||||
words: json['words'] as int?,
|
|
||||||
imageUrls: (json['image_urls'] as List?)?.fromCast(),
|
|
||||||
category: json['category'] == null
|
|
||||||
? null
|
|
||||||
: Category.fromJson(json['category'] as Map<String, dynamic>),
|
|
||||||
categories: json['categories'] as dynamic,
|
|
||||||
summary: json['summary'] as String?,
|
|
||||||
type: json['type'] as int?,
|
|
||||||
dynIdStr: json['dyn_id_str'] as String?,
|
|
||||||
attributes: json['attributes'] as int?,
|
|
||||||
authorUid: json['author_uid'] as int?,
|
|
||||||
onlyFans: json['only_fans'] as int?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,54 +1,30 @@
|
|||||||
class ArticleListInfo {
|
class ArticleListInfo {
|
||||||
int? id;
|
int? id;
|
||||||
int? mid;
|
|
||||||
String? name;
|
String? name;
|
||||||
String? imageUrl;
|
String? imageUrl;
|
||||||
int? updateTime;
|
int? updateTime;
|
||||||
int? ctime;
|
|
||||||
int? publishTime;
|
|
||||||
String? summary;
|
|
||||||
int? words;
|
int? words;
|
||||||
int? read;
|
int? read;
|
||||||
int? articlesCount;
|
int? articlesCount;
|
||||||
int? state;
|
|
||||||
String? reason;
|
|
||||||
String? applyTime;
|
|
||||||
String? checkTime;
|
|
||||||
|
|
||||||
ArticleListInfo({
|
ArticleListInfo({
|
||||||
this.id,
|
this.id,
|
||||||
this.mid,
|
|
||||||
this.name,
|
this.name,
|
||||||
this.imageUrl,
|
this.imageUrl,
|
||||||
this.updateTime,
|
this.updateTime,
|
||||||
this.ctime,
|
|
||||||
this.publishTime,
|
|
||||||
this.summary,
|
|
||||||
this.words,
|
this.words,
|
||||||
this.read,
|
this.read,
|
||||||
this.articlesCount,
|
this.articlesCount,
|
||||||
this.state,
|
|
||||||
this.reason,
|
|
||||||
this.applyTime,
|
|
||||||
this.checkTime,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ArticleListInfo.fromJson(Map<String, dynamic> json) =>
|
factory ArticleListInfo.fromJson(Map<String, dynamic> json) =>
|
||||||
ArticleListInfo(
|
ArticleListInfo(
|
||||||
id: json['id'] as int?,
|
id: json['id'] as int?,
|
||||||
mid: json['mid'] as int?,
|
|
||||||
name: json['name'] as String?,
|
name: json['name'] as String?,
|
||||||
imageUrl: json['image_url'] as String?,
|
imageUrl: json['image_url'] as String?,
|
||||||
updateTime: json['update_time'] as int?,
|
updateTime: json['update_time'] as int?,
|
||||||
ctime: json['ctime'] as int?,
|
|
||||||
publishTime: json['publish_time'] as int?,
|
|
||||||
summary: json['summary'] as String?,
|
|
||||||
words: json['words'] as int?,
|
words: json['words'] as int?,
|
||||||
read: json['read'] as int?,
|
read: json['read'] as int?,
|
||||||
articlesCount: json['articles_count'] as int?,
|
articlesCount: json['articles_count'] as int?,
|
||||||
state: json['state'] as int?,
|
|
||||||
reason: json['reason'] as String?,
|
|
||||||
applyTime: json['apply_time'] as String?,
|
|
||||||
checkTime: json['check_time'] as String?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,17 @@
|
|||||||
class Stats {
|
class Stats {
|
||||||
int? view;
|
int? view;
|
||||||
int? favorite;
|
|
||||||
int? like;
|
int? like;
|
||||||
int? dislike;
|
|
||||||
int? reply;
|
int? reply;
|
||||||
int? share;
|
|
||||||
num? coin;
|
|
||||||
int? dynam1c;
|
|
||||||
|
|
||||||
Stats({
|
Stats({
|
||||||
this.view,
|
this.view,
|
||||||
this.favorite,
|
|
||||||
this.like,
|
this.like,
|
||||||
this.dislike,
|
|
||||||
this.reply,
|
this.reply,
|
||||||
this.share,
|
|
||||||
this.coin,
|
|
||||||
this.dynam1c,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Stats.fromJson(Map<String, dynamic> json) => Stats(
|
factory Stats.fromJson(Map<String, dynamic> json) => Stats(
|
||||||
view: json['view'] as int?,
|
view: json['view'] as int?,
|
||||||
favorite: json['favorite'] as int?,
|
|
||||||
like: json['like'] as int?,
|
like: json['like'] as int?,
|
||||||
dislike: json['dislike'] as int?,
|
|
||||||
reply: json['reply'] as int?,
|
reply: json['reply'] as int?,
|
||||||
share: json['share'] as int?,
|
|
||||||
coin: json['coin'] as num?,
|
|
||||||
dynam1c: json['dynamic'] as int?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
class Category {
|
|
||||||
int? id;
|
|
||||||
int? parentId;
|
|
||||||
String? name;
|
|
||||||
|
|
||||||
Category({this.id, this.parentId, this.name});
|
|
||||||
|
|
||||||
factory Category.fromJson(Map<String, dynamic> json) => Category(
|
|
||||||
id: json['id'] as int?,
|
|
||||||
parentId: json['parent_id'] as int?,
|
|
||||||
name: json['name'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,95 +1,28 @@
|
|||||||
import 'package:PiliPlus/models/model_avatar.dart';
|
import 'package:PiliPlus/models/model_avatar.dart';
|
||||||
import 'package:PiliPlus/models_new/article/article_view/category.dart';
|
|
||||||
import 'package:PiliPlus/models_new/article/article_view/media.dart';
|
|
||||||
import 'package:PiliPlus/models_new/article/article_view/ops.dart';
|
import 'package:PiliPlus/models_new/article/article_view/ops.dart';
|
||||||
import 'package:PiliPlus/models_new/article/article_view/opus.dart';
|
import 'package:PiliPlus/models_new/article/article_view/opus.dart';
|
||||||
import 'package:PiliPlus/models_new/article/article_view/stats.dart';
|
|
||||||
import 'package:PiliPlus/models_new/article/article_view/tag.dart';
|
|
||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
|
|
||||||
class ArticleViewData {
|
class ArticleViewData {
|
||||||
int? id;
|
int? id;
|
||||||
Category? category;
|
|
||||||
List<Category>? categories;
|
|
||||||
String? title;
|
String? title;
|
||||||
String? summary;
|
|
||||||
String? bannerUrl;
|
|
||||||
int? templateId;
|
|
||||||
int? state;
|
|
||||||
Avatar? author;
|
Avatar? author;
|
||||||
int? reprint;
|
|
||||||
List<String>? imageUrls;
|
|
||||||
int? publishTime;
|
int? publishTime;
|
||||||
int? ctime;
|
|
||||||
int? mtime;
|
|
||||||
Stats? stats;
|
|
||||||
List<Tag>? tags;
|
|
||||||
int? words;
|
|
||||||
List<String>? originImageUrls;
|
List<String>? originImageUrls;
|
||||||
dynamic list;
|
|
||||||
bool? isLike;
|
|
||||||
Media? media;
|
|
||||||
String? applyTime;
|
|
||||||
String? checkTime;
|
|
||||||
int? original;
|
|
||||||
int? actId;
|
|
||||||
dynamic dispute;
|
|
||||||
dynamic authenMark;
|
|
||||||
int? coverAvid;
|
|
||||||
dynamic topVideoInfo;
|
|
||||||
int? type;
|
int? type;
|
||||||
int? checkState;
|
|
||||||
int? originTemplateId;
|
|
||||||
int? privatePub;
|
|
||||||
dynamic contentPicList;
|
|
||||||
String? content;
|
String? content;
|
||||||
String? keywords;
|
|
||||||
int? versionId;
|
|
||||||
String? dynIdStr;
|
String? dynIdStr;
|
||||||
int? totalArtNum;
|
|
||||||
ArticleOpus? opus;
|
ArticleOpus? opus;
|
||||||
List<ArticleOps>? ops;
|
List<ArticleOps>? ops;
|
||||||
|
|
||||||
ArticleViewData({
|
ArticleViewData({
|
||||||
this.id,
|
this.id,
|
||||||
this.category,
|
|
||||||
this.categories,
|
|
||||||
this.title,
|
|
||||||
this.summary,
|
|
||||||
this.bannerUrl,
|
|
||||||
this.templateId,
|
|
||||||
this.state,
|
|
||||||
this.author,
|
this.author,
|
||||||
this.reprint,
|
|
||||||
this.imageUrls,
|
|
||||||
this.publishTime,
|
this.publishTime,
|
||||||
this.ctime,
|
|
||||||
this.mtime,
|
|
||||||
this.stats,
|
|
||||||
this.tags,
|
|
||||||
this.words,
|
|
||||||
this.originImageUrls,
|
this.originImageUrls,
|
||||||
this.list,
|
|
||||||
this.isLike,
|
|
||||||
this.media,
|
|
||||||
this.applyTime,
|
|
||||||
this.checkTime,
|
|
||||||
this.original,
|
|
||||||
this.actId,
|
|
||||||
this.dispute,
|
|
||||||
this.authenMark,
|
|
||||||
this.coverAvid,
|
|
||||||
this.topVideoInfo,
|
|
||||||
this.type,
|
this.type,
|
||||||
this.checkState,
|
|
||||||
this.originTemplateId,
|
|
||||||
this.privatePub,
|
|
||||||
this.contentPicList,
|
|
||||||
this.content,
|
this.content,
|
||||||
this.keywords,
|
|
||||||
this.versionId,
|
|
||||||
this.dynIdStr,
|
this.dynIdStr,
|
||||||
this.totalArtNum,
|
|
||||||
this.opus,
|
this.opus,
|
||||||
this.ops,
|
this.ops,
|
||||||
});
|
});
|
||||||
@@ -97,56 +30,14 @@ class ArticleViewData {
|
|||||||
factory ArticleViewData.fromJson(Map<String, dynamic> json) =>
|
factory ArticleViewData.fromJson(Map<String, dynamic> json) =>
|
||||||
ArticleViewData(
|
ArticleViewData(
|
||||||
id: json['id'] as int?,
|
id: json['id'] as int?,
|
||||||
category: json['category'] == null
|
|
||||||
? null
|
|
||||||
: Category.fromJson(json['category'] as Map<String, dynamic>),
|
|
||||||
categories: (json['categories'] as List<dynamic>?)
|
|
||||||
?.map((e) => Category.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
title: json['title'] as String?,
|
|
||||||
summary: json['summary'] as String?,
|
|
||||||
bannerUrl: json['banner_url'] as String?,
|
|
||||||
templateId: json['template_id'] as int?,
|
|
||||||
state: json['state'] as int?,
|
|
||||||
author: json['author'] == null
|
author: json['author'] == null
|
||||||
? null
|
? null
|
||||||
: Avatar.fromJson(json['author'] as Map<String, dynamic>),
|
: Avatar.fromJson(json['author'] as Map<String, dynamic>),
|
||||||
reprint: json['reprint'] as int?,
|
|
||||||
imageUrls: (json['image_urls'] as List?)?.fromCast(),
|
|
||||||
publishTime: json['publish_time'] as int?,
|
publishTime: json['publish_time'] as int?,
|
||||||
ctime: json['ctime'] as int?,
|
|
||||||
mtime: json['mtime'] as int?,
|
|
||||||
stats: json['stats'] == null
|
|
||||||
? null
|
|
||||||
: Stats.fromJson(json['stats'] as Map<String, dynamic>),
|
|
||||||
tags: (json['tags'] as List<dynamic>?)
|
|
||||||
?.map((e) => Tag.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
words: json['words'] as int?,
|
|
||||||
originImageUrls: (json['origin_image_urls'] as List?)?.fromCast(),
|
originImageUrls: (json['origin_image_urls'] as List?)?.fromCast(),
|
||||||
list: json['list'] as dynamic,
|
|
||||||
isLike: json['is_like'] as bool?,
|
|
||||||
media: json['media'] == null
|
|
||||||
? null
|
|
||||||
: Media.fromJson(json['media'] as Map<String, dynamic>),
|
|
||||||
applyTime: json['apply_time'] as String?,
|
|
||||||
checkTime: json['check_time'] as String?,
|
|
||||||
original: json['original'] as int?,
|
|
||||||
actId: json['act_id'] as int?,
|
|
||||||
dispute: json['dispute'] as dynamic,
|
|
||||||
authenMark: json['authenMark'] as dynamic,
|
|
||||||
coverAvid: json['cover_avid'] as int?,
|
|
||||||
topVideoInfo: json['top_video_info'] as dynamic,
|
|
||||||
type: json['type'] as int?,
|
type: json['type'] as int?,
|
||||||
checkState: json['check_state'] as int?,
|
|
||||||
originTemplateId: json['origin_template_id'] as int?,
|
|
||||||
privatePub: json['private_pub'] as int?,
|
|
||||||
contentPicList: json['content_pic_list'] as dynamic,
|
|
||||||
content: json['content'] as String?,
|
content: json['content'] as String?,
|
||||||
keywords: json['keywords'] as String?,
|
|
||||||
versionId: json['version_id'] as int?,
|
|
||||||
dynIdStr: json['dyn_id_str'] as String?,
|
dynIdStr: json['dyn_id_str'] as String?,
|
||||||
totalArtNum: json['total_art_num'] as int?,
|
|
||||||
opus: json['opus'] == null
|
opus: json['opus'] == null
|
||||||
? null
|
? null
|
||||||
: ArticleOpus.fromJson(json['opus'] as Map<String, dynamic>),
|
: ArticleOpus.fromJson(json['opus'] as Map<String, dynamic>),
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
class Label {
|
|
||||||
String? path;
|
|
||||||
String? text;
|
|
||||||
String? labelTheme;
|
|
||||||
|
|
||||||
Label({this.path, this.text, this.labelTheme});
|
|
||||||
|
|
||||||
factory Label.fromJson(Map<String, dynamic> json) => Label(
|
|
||||||
path: json['path'] as String?,
|
|
||||||
text: json['text'] as String?,
|
|
||||||
labelTheme: json['label_theme'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
class Media {
|
|
||||||
int? score;
|
|
||||||
int? mediaId;
|
|
||||||
String? title;
|
|
||||||
String? cover;
|
|
||||||
String? area;
|
|
||||||
int? typeId;
|
|
||||||
String? typeName;
|
|
||||||
int? spoiler;
|
|
||||||
int? seasonId;
|
|
||||||
|
|
||||||
Media({
|
|
||||||
this.score,
|
|
||||||
this.mediaId,
|
|
||||||
this.title,
|
|
||||||
this.cover,
|
|
||||||
this.area,
|
|
||||||
this.typeId,
|
|
||||||
this.typeName,
|
|
||||||
this.spoiler,
|
|
||||||
this.seasonId,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory Media.fromJson(Map<String, dynamic> json) => Media(
|
|
||||||
score: json['score'] as int?,
|
|
||||||
mediaId: json['media_id'] as int?,
|
|
||||||
title: json['title'] as String?,
|
|
||||||
cover: json['cover'] as String?,
|
|
||||||
area: json['area'] as String?,
|
|
||||||
typeId: json['type_id'] as int?,
|
|
||||||
typeName: json['type_name'] as String?,
|
|
||||||
spoiler: json['spoiler'] as int?,
|
|
||||||
seasonId: json['season_id'] as int?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
import 'package:PiliPlus/models/dynamics/article_content_model.dart';
|
import 'package:PiliPlus/models/dynamics/article_content_model.dart';
|
||||||
|
|
||||||
class ArticleOpus {
|
class ArticleOpus {
|
||||||
int? opusid;
|
|
||||||
int? opussource;
|
|
||||||
String? title;
|
|
||||||
List<ArticleContentModel>? content;
|
List<ArticleContentModel>? content;
|
||||||
|
|
||||||
ArticleOpus.fromJson(Map<String, dynamic> json) {
|
ArticleOpus.fromJson(Map<String, dynamic> json) {
|
||||||
opusid = json['opus_id'];
|
|
||||||
opussource = json['opus_source'];
|
|
||||||
title = json['title'];
|
|
||||||
if (json['content']?['paragraphs'] case List list) {
|
if (json['content']?['paragraphs'] case List list) {
|
||||||
content = list.map((i) => ArticleContentModel.fromJson(i)).toList();
|
content = list.map((i) => ArticleContentModel.fromJson(i)).toList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
class Stats {
|
|
||||||
int? view;
|
|
||||||
int? favorite;
|
|
||||||
int? like;
|
|
||||||
int? dislike;
|
|
||||||
int? reply;
|
|
||||||
int? share;
|
|
||||||
num? coin;
|
|
||||||
int? dynam1c;
|
|
||||||
|
|
||||||
Stats({
|
|
||||||
this.view,
|
|
||||||
this.favorite,
|
|
||||||
this.like,
|
|
||||||
this.dislike,
|
|
||||||
this.reply,
|
|
||||||
this.share,
|
|
||||||
this.coin,
|
|
||||||
this.dynam1c,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory Stats.fromJson(Map<String, dynamic> json) => Stats(
|
|
||||||
view: json['view'] as int?,
|
|
||||||
favorite: json['favorite'] as int?,
|
|
||||||
like: json['like'] as int?,
|
|
||||||
dislike: json['dislike'] as int?,
|
|
||||||
reply: json['reply'] as int?,
|
|
||||||
share: json['share'] as int?,
|
|
||||||
coin: json['coin'] as num?,
|
|
||||||
dynam1c: json['dynamic'] as int?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
class Tag {
|
|
||||||
int? tid;
|
|
||||||
String? name;
|
|
||||||
|
|
||||||
Tag({this.tid, this.name});
|
|
||||||
|
|
||||||
factory Tag.fromJson(Map<String, dynamic> json) => Tag(
|
|
||||||
tid: json['tid'] as int?,
|
|
||||||
name: json['name'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -2,16 +2,14 @@ import 'package:PiliPlus/models_new/blacklist/list.dart';
|
|||||||
|
|
||||||
class BlackListData {
|
class BlackListData {
|
||||||
List<BlackListItem>? list;
|
List<BlackListItem>? list;
|
||||||
int? reVersion;
|
|
||||||
int? total;
|
int? total;
|
||||||
|
|
||||||
BlackListData({this.list, this.reVersion, this.total});
|
BlackListData({this.list, this.total});
|
||||||
|
|
||||||
factory BlackListData.fromJson(Map<String, dynamic> json) => BlackListData(
|
factory BlackListData.fromJson(Map<String, dynamic> json) => BlackListData(
|
||||||
list: (json['list'] as List<dynamic>?)
|
list: (json['list'] as List<dynamic>?)
|
||||||
?.map((e) => BlackListItem.fromJson(e as Map<String, dynamic>))
|
?.map((e) => BlackListItem.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
reVersion: json['re_version'] as int?,
|
|
||||||
total: json['total'] as int?,
|
total: json['total'] as int?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,20 @@
|
|||||||
import 'package:PiliPlus/models/model_avatar.dart';
|
|
||||||
|
|
||||||
class BlackListItem {
|
class BlackListItem {
|
||||||
int? mid;
|
int? mid;
|
||||||
int? attribute;
|
|
||||||
int? mtime;
|
int? mtime;
|
||||||
dynamic tag;
|
|
||||||
int? special;
|
|
||||||
String? uname;
|
String? uname;
|
||||||
String? face;
|
String? face;
|
||||||
String? sign;
|
|
||||||
int? faceNft;
|
|
||||||
BaseOfficialVerify? officialVerify;
|
|
||||||
Vip? vip;
|
|
||||||
String? nftIcon;
|
|
||||||
String? recReason;
|
|
||||||
String? trackId;
|
|
||||||
String? followTime;
|
|
||||||
|
|
||||||
BlackListItem({
|
BlackListItem({
|
||||||
this.mid,
|
this.mid,
|
||||||
this.attribute,
|
|
||||||
this.mtime,
|
this.mtime,
|
||||||
this.tag,
|
|
||||||
this.special,
|
|
||||||
this.uname,
|
this.uname,
|
||||||
this.face,
|
this.face,
|
||||||
this.sign,
|
|
||||||
this.faceNft,
|
|
||||||
this.officialVerify,
|
|
||||||
this.vip,
|
|
||||||
this.nftIcon,
|
|
||||||
this.recReason,
|
|
||||||
this.trackId,
|
|
||||||
this.followTime,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory BlackListItem.fromJson(Map<String, dynamic> json) => BlackListItem(
|
factory BlackListItem.fromJson(Map<String, dynamic> json) => BlackListItem(
|
||||||
mid: json['mid'] as int?,
|
mid: json['mid'] as int?,
|
||||||
attribute: json['attribute'] as int?,
|
|
||||||
mtime: json['mtime'] as int?,
|
mtime: json['mtime'] as int?,
|
||||||
tag: json['tag'] as dynamic,
|
|
||||||
special: json['special'] as int?,
|
|
||||||
uname: json['uname'] as String?,
|
uname: json['uname'] as String?,
|
||||||
face: json['face'] as String?,
|
face: json['face'] as String?,
|
||||||
sign: json['sign'] as String?,
|
|
||||||
faceNft: json['face_nft'] as int?,
|
|
||||||
officialVerify: json['official_verify'] == null
|
|
||||||
? null
|
|
||||||
: BaseOfficialVerify.fromJson(
|
|
||||||
json['official_verify'] as Map<String, dynamic>,
|
|
||||||
),
|
|
||||||
vip: json['vip'] == null
|
|
||||||
? null
|
|
||||||
: Vip.fromJson(json['vip'] as Map<String, dynamic>),
|
|
||||||
nftIcon: json['nft_icon'] as String?,
|
|
||||||
recReason: json['rec_reason'] as String?,
|
|
||||||
trackId: json['track_id'] as String?,
|
|
||||||
followTime: json['follow_time'] as String?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import 'package:PiliPlus/models_new/coin_log/list.dart';
|
import 'package:PiliPlus/models_new/coin_log/list.dart';
|
||||||
|
|
||||||
class CoinLogData {
|
class CoinLogData {
|
||||||
List<CoinLogItem>? list;
|
CoinLogData({this.list});
|
||||||
int? count;
|
|
||||||
|
|
||||||
CoinLogData({this.list, this.count});
|
List<CoinLogItem>? list;
|
||||||
|
|
||||||
factory CoinLogData.fromJson(Map<String, dynamic> json) => CoinLogData(
|
factory CoinLogData.fromJson(Map<String, dynamic> json) => CoinLogData(
|
||||||
list: (json['list'] as List<dynamic>?)
|
list: (json['list'] as List<dynamic>?)
|
||||||
?.map((e) => CoinLogItem.fromJson(e as Map<String, dynamic>))
|
?.map((e) => CoinLogItem.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
count: json['count'] as int?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
class CoinLogItem {
|
class CoinLogItem {
|
||||||
final String time;
|
|
||||||
final String delta;
|
|
||||||
final String reason;
|
|
||||||
|
|
||||||
const CoinLogItem({
|
const CoinLogItem({
|
||||||
required this.time,
|
required this.time,
|
||||||
required this.delta,
|
required this.delta,
|
||||||
required this.reason,
|
required this.reason,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final String time;
|
||||||
|
final String delta;
|
||||||
|
final String reason;
|
||||||
|
|
||||||
factory CoinLogItem.fromJson(Map<String, dynamic> json) => CoinLogItem(
|
factory CoinLogItem.fromJson(Map<String, dynamic> json) => CoinLogItem(
|
||||||
time: json['time'],
|
time: json['time'],
|
||||||
delta: (json['delta'] as num).toString(),
|
delta: (json['delta'] as num).toString(),
|
||||||
|
|||||||
@@ -1,31 +1,13 @@
|
|||||||
class DanmakuPost {
|
class DanmakuPost {
|
||||||
DanmakuPost({
|
DanmakuPost({
|
||||||
required this.action,
|
|
||||||
required this.animation,
|
|
||||||
required this.colorfulSrc,
|
|
||||||
required this.dmContent,
|
|
||||||
required this.dmid,
|
required this.dmid,
|
||||||
required this.dmidStr,
|
|
||||||
required this.visible,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String? action;
|
|
||||||
final String? animation;
|
|
||||||
final dynamic colorfulSrc;
|
|
||||||
final String? dmContent;
|
|
||||||
final int? dmid;
|
final int? dmid;
|
||||||
final String? dmidStr;
|
|
||||||
final bool? visible;
|
|
||||||
|
|
||||||
factory DanmakuPost.fromJson(Map<String, dynamic> json) {
|
factory DanmakuPost.fromJson(Map<String, dynamic> json) {
|
||||||
return DanmakuPost(
|
return DanmakuPost(
|
||||||
action: json["action"],
|
|
||||||
animation: json["animation"],
|
|
||||||
colorfulSrc: json["colorful_src"],
|
|
||||||
dmContent: json["dm_content"],
|
|
||||||
dmid: json["dmid"],
|
dmid: json["dmid"],
|
||||||
dmidStr: json["dmid_str"],
|
|
||||||
visible: json["visible"],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
import 'dart:io' show Platform, Process;
|
||||||
|
|
||||||
import 'package:PiliPlus/models/common/video/video_type.dart';
|
import 'package:PiliPlus/models/common/video/video_type.dart';
|
||||||
import 'package:PiliPlus/pages/common/multi_select/base.dart'
|
import 'package:PiliPlus/pages/common/multi_select/base.dart'
|
||||||
show MultiSelectData;
|
show MultiSelectData;
|
||||||
import 'package:PiliPlus/utils/page_utils.dart';
|
import 'package:PiliPlus/utils/page_utils.dart';
|
||||||
|
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/route_manager.dart';
|
import 'package:get/route_manager.dart';
|
||||||
|
|
||||||
class BiliDownloadEntryInfo with MultiSelectData {
|
class BiliDownloadEntryInfo with MultiSelectData {
|
||||||
@@ -68,10 +72,7 @@ class BiliDownloadEntryInfo with MultiSelectData {
|
|||||||
itemBuilder: (_) => [
|
itemBuilder: (_) => [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
height: 38,
|
height: 38,
|
||||||
child: const Text(
|
child: const Text('查看详情页', style: TextStyle(fontSize: 13)),
|
||||||
'查看详情页',
|
|
||||||
style: TextStyle(fontSize: 13),
|
|
||||||
),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (ep case final ep?) {
|
if (ep case final ep?) {
|
||||||
if (ep.from == VideoType.pugv.name) {
|
if (ep.from == VideoType.pugv.name) {
|
||||||
@@ -97,14 +98,34 @@ class BiliDownloadEntryInfo with MultiSelectData {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
if (PlatformUtils.isDesktop)
|
||||||
|
PopupMenuItem(
|
||||||
|
height: 38,
|
||||||
|
child: const Text('打开本地文件夹', style: TextStyle(fontSize: 13)),
|
||||||
|
onTap: () async {
|
||||||
|
try {
|
||||||
|
final String executable;
|
||||||
|
if (Platform.isWindows) {
|
||||||
|
executable = 'explorer';
|
||||||
|
} else if (Platform.isMacOS) {
|
||||||
|
executable = 'open';
|
||||||
|
} else if (Platform.isLinux) {
|
||||||
|
executable = 'xdg-open';
|
||||||
|
} else {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
await Process.run(executable, [entryDirPath]);
|
||||||
|
} catch (e) {
|
||||||
|
SmartDialog.showToast(e.toString());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
if (ownerId case final mid?)
|
if (ownerId case final mid?)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
height: 38,
|
height: 38,
|
||||||
child: Text(
|
child: Text(
|
||||||
'访问${ownerName != null ? ':$ownerName' : '用户主页'}',
|
'访问${ownerName != null ? ':$ownerName' : '用户主页'}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(fontSize: 13),
|
||||||
fontSize: 13,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
onTap: () => Get.toNamed('/member?mid=$mid'),
|
onTap: () => Get.toNamed('/member?mid=$mid'),
|
||||||
),
|
),
|
||||||
@@ -395,7 +416,7 @@ enum DownloadStatus {
|
|||||||
failDanmaku('获取弹幕失败'),
|
failDanmaku('获取弹幕失败'),
|
||||||
failPlayUrl('获取播放地址失败'),
|
failPlayUrl('获取播放地址失败'),
|
||||||
pause('暂停中'),
|
pause('暂停中'),
|
||||||
wait('等待中')
|
wait('等待中'),
|
||||||
;
|
;
|
||||||
|
|
||||||
final String message;
|
final String message;
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ import 'package:PiliPlus/models_new/dynamic/dyn_mention/item.dart';
|
|||||||
|
|
||||||
class MentionGroup {
|
class MentionGroup {
|
||||||
String? groupName;
|
String? groupName;
|
||||||
int? groupType;
|
|
||||||
List<MentionItem>? items;
|
List<MentionItem>? items;
|
||||||
|
|
||||||
MentionGroup({this.groupName, this.groupType, this.items});
|
MentionGroup({this.groupName, this.items});
|
||||||
|
|
||||||
factory MentionGroup.fromJson(Map<String, dynamic> json) => MentionGroup(
|
factory MentionGroup.fromJson(Map<String, dynamic> json) => MentionGroup(
|
||||||
groupName: json['group_name'] as String?,
|
groupName: json['group_name'] as String?,
|
||||||
groupType: json['group_type'] as int?,
|
|
||||||
items: (json['items'] as List<dynamic>?)
|
items: (json['items'] as List<dynamic>?)
|
||||||
?.map((e) => MentionItem.fromJson(e as Map<String, dynamic>))
|
?.map((e) => MentionItem.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ class MentionItem with MultiSelectData {
|
|||||||
final String? face;
|
final String? face;
|
||||||
final int? fans;
|
final int? fans;
|
||||||
final String? name;
|
final String? name;
|
||||||
final int? officialVerifyType;
|
|
||||||
final String? uid;
|
final String? uid;
|
||||||
|
|
||||||
MentionItem({
|
MentionItem({
|
||||||
this.face,
|
this.face,
|
||||||
this.fans,
|
this.fans,
|
||||||
this.name,
|
this.name,
|
||||||
this.officialVerifyType,
|
|
||||||
this.uid,
|
this.uid,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -19,7 +17,6 @@ class MentionItem with MultiSelectData {
|
|||||||
face: json['face'] as String?,
|
face: json['face'] as String?,
|
||||||
fans: json['fans'] as int?,
|
fans: json['fans'] as int?,
|
||||||
name: json['name'] as String?,
|
name: json['name'] as String?,
|
||||||
officialVerifyType: json['official_verify_type'] as int?,
|
|
||||||
uid: json['uid'] as String?,
|
uid: json['uid'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
class DynReserveData {
|
class DynReserveData {
|
||||||
int? finalBtnStatus;
|
int? finalBtnStatus;
|
||||||
int? btnMode;
|
|
||||||
int? reserveUpdate;
|
int? reserveUpdate;
|
||||||
String? descUpdate;
|
String? descUpdate;
|
||||||
String? toast;
|
|
||||||
|
|
||||||
DynReserveData({
|
DynReserveData({
|
||||||
this.finalBtnStatus,
|
this.finalBtnStatus,
|
||||||
this.btnMode,
|
|
||||||
this.reserveUpdate,
|
this.reserveUpdate,
|
||||||
this.descUpdate,
|
this.descUpdate,
|
||||||
this.toast,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory DynReserveData.fromJson(Map<String, dynamic> json) => DynReserveData(
|
factory DynReserveData.fromJson(Map<String, dynamic> json) => DynReserveData(
|
||||||
finalBtnStatus: json['final_btn_status'] as int?,
|
finalBtnStatus: json['final_btn_status'] as int?,
|
||||||
btnMode: json['btn_mode'] as int?,
|
|
||||||
reserveUpdate: json['reserve_update'] as int?,
|
reserveUpdate: json['reserve_update'] as int?,
|
||||||
descUpdate: json['desc_update'] as String?,
|
descUpdate: json['desc_update'] as String?,
|
||||||
toast: json['toast'] as String?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,18 @@
|
|||||||
class ReserveInfoData {
|
class ReserveInfoData {
|
||||||
int? id;
|
int? id;
|
||||||
String? title;
|
String? title;
|
||||||
int? stime;
|
|
||||||
int? etime;
|
|
||||||
int? type;
|
|
||||||
int? livePlanStartTime;
|
int? livePlanStartTime;
|
||||||
int? lotteryType;
|
|
||||||
String? lotteryId;
|
|
||||||
int? subType;
|
|
||||||
|
|
||||||
ReserveInfoData({
|
ReserveInfoData({
|
||||||
this.id,
|
this.id,
|
||||||
this.title,
|
this.title,
|
||||||
this.stime,
|
|
||||||
this.etime,
|
|
||||||
this.type,
|
|
||||||
this.livePlanStartTime,
|
this.livePlanStartTime,
|
||||||
this.lotteryType,
|
|
||||||
this.lotteryId,
|
|
||||||
this.subType,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ReserveInfoData.fromJson(Map<String, dynamic> json) =>
|
factory ReserveInfoData.fromJson(Map<String, dynamic> json) =>
|
||||||
ReserveInfoData(
|
ReserveInfoData(
|
||||||
id: json['id'] as int?,
|
id: json['id'] as int?,
|
||||||
title: json['title'] as String?,
|
title: json['title'] as String?,
|
||||||
stime: json['stime'] as int?,
|
|
||||||
etime: json['etime'] as int?,
|
|
||||||
type: json['type'] as int?,
|
|
||||||
livePlanStartTime: json['live_plan_start_time'] as int?,
|
livePlanStartTime: json['live_plan_start_time'] as int?,
|
||||||
lotteryType: json['lottery_type'] as int?,
|
|
||||||
lotteryId: json['lottery_id'] as String?,
|
|
||||||
subType: json['sub_type'] as int?,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'id': id,
|
|
||||||
'title': title,
|
|
||||||
'stime': stime,
|
|
||||||
'etime': etime,
|
|
||||||
'type': type,
|
|
||||||
'live_plan_start_time': livePlanStartTime,
|
|
||||||
'lottery_type': lotteryType,
|
|
||||||
'lottery_id': lotteryId,
|
|
||||||
'sub_type': subType,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,15 @@ import 'package:PiliPlus/models_new/dynamic/dyn_topic_feed/all_sort_by.dart';
|
|||||||
|
|
||||||
class TopicSortByConf {
|
class TopicSortByConf {
|
||||||
List<AllSortBy>? allSortBy;
|
List<AllSortBy>? allSortBy;
|
||||||
int? defaultSortBy;
|
|
||||||
int? showSortBy;
|
int? showSortBy;
|
||||||
|
|
||||||
TopicSortByConf({this.allSortBy, this.defaultSortBy, this.showSortBy});
|
TopicSortByConf({this.allSortBy, this.showSortBy});
|
||||||
|
|
||||||
factory TopicSortByConf.fromJson(Map<String, dynamic> json) {
|
factory TopicSortByConf.fromJson(Map<String, dynamic> json) {
|
||||||
return TopicSortByConf(
|
return TopicSortByConf(
|
||||||
allSortBy: (json['all_sort_by'] as List<dynamic>?)
|
allSortBy: (json['all_sort_by'] as List<dynamic>?)
|
||||||
?.map((e) => AllSortBy.fromJson(e as Map<String, dynamic>))
|
?.map((e) => AllSortBy.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
defaultSortBy: json['default_sort_by'] as int?,
|
|
||||||
showSortBy: json['show_sort_by'] as int?,
|
showSortBy: json['show_sort_by'] as int?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,20 @@
|
|||||||
import 'package:PiliPlus/models_new/dynamic/dyn_topic_pub_search/new_topic.dart';
|
|
||||||
import 'package:PiliPlus/models_new/dynamic/dyn_topic_pub_search/page_info.dart';
|
import 'package:PiliPlus/models_new/dynamic/dyn_topic_pub_search/page_info.dart';
|
||||||
import 'package:PiliPlus/models_new/dynamic/dyn_topic_top/topic_item.dart';
|
import 'package:PiliPlus/models_new/dynamic/dyn_topic_top/topic_item.dart';
|
||||||
|
|
||||||
class TopicPubSearchData {
|
class TopicPubSearchData {
|
||||||
NewTopic? newTopic;
|
|
||||||
bool? hasCreateJurisdiction;
|
|
||||||
List<TopicItem>? topicItems;
|
List<TopicItem>? topicItems;
|
||||||
String? requestId;
|
|
||||||
PageInfo? pageInfo;
|
PageInfo? pageInfo;
|
||||||
|
|
||||||
TopicPubSearchData({
|
TopicPubSearchData({
|
||||||
this.newTopic,
|
|
||||||
this.hasCreateJurisdiction,
|
|
||||||
this.topicItems,
|
this.topicItems,
|
||||||
this.requestId,
|
|
||||||
this.pageInfo,
|
this.pageInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory TopicPubSearchData.fromJson(Map<String, dynamic> json) =>
|
factory TopicPubSearchData.fromJson(Map<String, dynamic> json) =>
|
||||||
TopicPubSearchData(
|
TopicPubSearchData(
|
||||||
newTopic: json['new_topic'] == null
|
|
||||||
? null
|
|
||||||
: NewTopic.fromJson(json['new_topic'] as Map<String, dynamic>),
|
|
||||||
hasCreateJurisdiction: json['has_create_jurisdiction'] as bool?,
|
|
||||||
topicItems: (json['topic_items'] as List<dynamic>?)
|
topicItems: (json['topic_items'] as List<dynamic>?)
|
||||||
?.map((e) => TopicItem.fromJson(e as Map<String, dynamic>))
|
?.map((e) => TopicItem.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
requestId: json['request_id'] as String?,
|
|
||||||
pageInfo: json['page_info'] == null
|
pageInfo: json['page_info'] == null
|
||||||
? null
|
? null
|
||||||
: PageInfo.fromJson(json['page_info'] as Map<String, dynamic>),
|
: PageInfo.fromJson(json['page_info'] as Map<String, dynamic>),
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
class NewTopic {
|
|
||||||
String? name;
|
|
||||||
|
|
||||||
NewTopic({this.name});
|
|
||||||
|
|
||||||
factory NewTopic.fromJson(Map<String, dynamic> json) => NewTopic(
|
|
||||||
name: json['name'] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
class PageInfo {
|
class PageInfo {
|
||||||
int? offset;
|
|
||||||
bool? hasMore;
|
bool? hasMore;
|
||||||
|
|
||||||
PageInfo({this.offset, this.hasMore});
|
PageInfo({this.hasMore});
|
||||||
|
|
||||||
factory PageInfo.fromJson(Map<String, dynamic> json) => PageInfo(
|
factory PageInfo.fromJson(Map<String, dynamic> json) => PageInfo(
|
||||||
offset: json['offset'] as int?,
|
|
||||||
hasMore: json['has_more'] as bool?,
|
hasMore: json['has_more'] as bool?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,10 @@ import 'package:PiliPlus/models_new/dynamic/dyn_topic_top/topic_item.dart';
|
|||||||
class TopDetails {
|
class TopDetails {
|
||||||
TopicItem? topicItem;
|
TopicItem? topicItem;
|
||||||
TopicCreator? topicCreator;
|
TopicCreator? topicCreator;
|
||||||
bool? hasCreateJurisdiction;
|
|
||||||
int? wordColor;
|
|
||||||
bool? closePubLayerEntry;
|
|
||||||
|
|
||||||
TopDetails({
|
TopDetails({
|
||||||
this.topicItem,
|
this.topicItem,
|
||||||
this.topicCreator,
|
this.topicCreator,
|
||||||
this.hasCreateJurisdiction,
|
|
||||||
this.wordColor,
|
|
||||||
this.closePubLayerEntry,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory TopDetails.fromJson(Map<String, dynamic> json) => TopDetails(
|
factory TopDetails.fromJson(Map<String, dynamic> json) => TopDetails(
|
||||||
@@ -23,8 +17,5 @@ class TopDetails {
|
|||||||
topicCreator: json['topic_creator'] == null
|
topicCreator: json['topic_creator'] == null
|
||||||
? null
|
? null
|
||||||
: TopicCreator.fromJson(json['topic_creator'] as Map<String, dynamic>),
|
: TopicCreator.fromJson(json['topic_creator'] as Map<String, dynamic>),
|
||||||
hasCreateJurisdiction: json['has_create_jurisdiction'] as bool?,
|
|
||||||
wordColor: json['word_color'] as int?,
|
|
||||||
closePubLayerEntry: json['close_pub_layer_entry'] as bool?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,7 @@ class TopicItem {
|
|||||||
int discuss;
|
int discuss;
|
||||||
int fav;
|
int fav;
|
||||||
int like;
|
int like;
|
||||||
int? dynamics;
|
|
||||||
String? jumpUrl;
|
|
||||||
String? backColor;
|
|
||||||
String? description;
|
String? description;
|
||||||
String? sharePic;
|
|
||||||
String? shareUrl;
|
|
||||||
int? ctime;
|
|
||||||
bool? showInteractData;
|
|
||||||
bool? isFav;
|
bool? isFav;
|
||||||
bool? isLike;
|
bool? isLike;
|
||||||
|
|
||||||
@@ -23,14 +16,7 @@ class TopicItem {
|
|||||||
required this.discuss,
|
required this.discuss,
|
||||||
required this.fav,
|
required this.fav,
|
||||||
required this.like,
|
required this.like,
|
||||||
this.dynamics,
|
|
||||||
this.jumpUrl,
|
|
||||||
this.backColor,
|
|
||||||
this.description,
|
this.description,
|
||||||
this.sharePic,
|
|
||||||
this.shareUrl,
|
|
||||||
this.ctime,
|
|
||||||
this.showInteractData,
|
|
||||||
this.isFav,
|
this.isFav,
|
||||||
this.isLike,
|
this.isLike,
|
||||||
});
|
});
|
||||||
@@ -42,14 +28,7 @@ class TopicItem {
|
|||||||
discuss: json['discuss'] ?? 0,
|
discuss: json['discuss'] ?? 0,
|
||||||
fav: json['fav'] ?? 0,
|
fav: json['fav'] ?? 0,
|
||||||
like: json['like'] ?? 0,
|
like: json['like'] ?? 0,
|
||||||
dynamics: json['dynamics'] as int?,
|
|
||||||
jumpUrl: json['jump_url'] as String?,
|
|
||||||
backColor: json['back_color'] as String?,
|
|
||||||
description: json['description'] as String?,
|
description: json['description'] as String?,
|
||||||
sharePic: json['share_pic'] as String?,
|
|
||||||
shareUrl: json['share_url'] as String?,
|
|
||||||
ctime: json['ctime'] as int?,
|
|
||||||
showInteractData: json['show_interact_data'] as bool?,
|
|
||||||
isFav: json['is_fav'] as bool?,
|
isFav: json['is_fav'] as bool?,
|
||||||
isLike: json['is_like'] as bool?,
|
isLike: json['is_like'] as bool?,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
class Author {
|
class Author {
|
||||||
String? name;
|
String? name;
|
||||||
String? face;
|
|
||||||
String? mid;
|
|
||||||
|
|
||||||
Author({this.name, this.face, this.mid});
|
Author({this.name});
|
||||||
|
|
||||||
factory Author.fromJson(Map<String, dynamic> json) => Author(
|
factory Author.fromJson(Map<String, dynamic> json) => Author(
|
||||||
name: json['name'] as String?,
|
name: json['name'] as String?,
|
||||||
face: json['face'] as String?,
|
|
||||||
mid: json['mid'] as String?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
class Cover {
|
class Cover {
|
||||||
String? url;
|
String? url;
|
||||||
int? width;
|
|
||||||
int? height;
|
|
||||||
|
|
||||||
Cover({this.url, this.width, this.height});
|
Cover({this.url});
|
||||||
|
|
||||||
factory Cover.fromJson(Map<String, dynamic> json) => Cover(
|
factory Cover.fromJson(Map<String, dynamic> json) => Cover(
|
||||||
url: json['url'] as String?,
|
url: json['url'] as String?,
|
||||||
width: json['width'] as int?,
|
|
||||||
height: json['height'] as int?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,10 @@ import 'package:PiliPlus/models_new/fav/fav_article/item.dart';
|
|||||||
class FavArticleData {
|
class FavArticleData {
|
||||||
List<FavArticleItemModel>? items;
|
List<FavArticleItemModel>? items;
|
||||||
bool? hasMore;
|
bool? hasMore;
|
||||||
String? offset;
|
|
||||||
String? updateNum;
|
|
||||||
String? updateBaseline;
|
|
||||||
|
|
||||||
FavArticleData({
|
FavArticleData({
|
||||||
this.items,
|
this.items,
|
||||||
this.hasMore,
|
this.hasMore,
|
||||||
this.offset,
|
|
||||||
this.updateNum,
|
|
||||||
this.updateBaseline,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory FavArticleData.fromJson(Map<String, dynamic> json) => FavArticleData(
|
factory FavArticleData.fromJson(Map<String, dynamic> json) => FavArticleData(
|
||||||
@@ -20,8 +14,5 @@ class FavArticleData {
|
|||||||
?.map((e) => FavArticleItemModel.fromJson(e as Map<String, dynamic>))
|
?.map((e) => FavArticleItemModel.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
hasMore: json['has_more'] as bool?,
|
hasMore: json['has_more'] as bool?,
|
||||||
offset: json['offset'] as String?,
|
|
||||||
updateNum: json['update_num'] as String?,
|
|
||||||
updateBaseline: json['update_baseline'] as String?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,16 @@ import 'package:PiliPlus/models_new/fav/fav_article/cover.dart';
|
|||||||
import 'package:PiliPlus/models_new/fav/fav_article/stat.dart';
|
import 'package:PiliPlus/models_new/fav/fav_article/stat.dart';
|
||||||
|
|
||||||
class FavArticleItemModel {
|
class FavArticleItemModel {
|
||||||
String? jumpUrl;
|
|
||||||
String? opusId;
|
String? opusId;
|
||||||
String? content;
|
String? content;
|
||||||
dynamic badge;
|
|
||||||
Author? author;
|
Author? author;
|
||||||
Cover? cover;
|
Cover? cover;
|
||||||
Stat? stat;
|
Stat? stat;
|
||||||
String? pubTime;
|
String? pubTime;
|
||||||
|
|
||||||
FavArticleItemModel({
|
FavArticleItemModel({
|
||||||
this.jumpUrl,
|
|
||||||
this.opusId,
|
this.opusId,
|
||||||
this.content,
|
this.content,
|
||||||
this.badge,
|
|
||||||
this.author,
|
this.author,
|
||||||
this.cover,
|
this.cover,
|
||||||
this.stat,
|
this.stat,
|
||||||
@@ -25,10 +21,8 @@ class FavArticleItemModel {
|
|||||||
|
|
||||||
factory FavArticleItemModel.fromJson(Map<String, dynamic> json) =>
|
factory FavArticleItemModel.fromJson(Map<String, dynamic> json) =>
|
||||||
FavArticleItemModel(
|
FavArticleItemModel(
|
||||||
jumpUrl: json['jump_url'] as String?,
|
|
||||||
opusId: json['opus_id'] as String?,
|
opusId: json['opus_id'] as String?,
|
||||||
content: json['content'] as String?,
|
content: json['content'] as String?,
|
||||||
badge: json['badge'] as dynamic,
|
|
||||||
author: json['author'] == null
|
author: json['author'] == null
|
||||||
? null
|
? null
|
||||||
: Author.fromJson(json['author'] as Map<String, dynamic>),
|
: Author.fromJson(json['author'] as Map<String, dynamic>),
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
class Stat {
|
class Stat {
|
||||||
String? view;
|
|
||||||
String? like;
|
String? like;
|
||||||
|
|
||||||
Stat({this.view, this.like});
|
Stat({this.like});
|
||||||
|
|
||||||
factory Stat.fromJson(Map<String, dynamic> json) => Stat(
|
factory Stat.fromJson(Map<String, dynamic> json) => Stat(
|
||||||
view: json['view'] as String?,
|
|
||||||
like: json['like'] as String?,
|
like: json['like'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,15 @@
|
|||||||
class CntInfo {
|
class CntInfo {
|
||||||
int? collect;
|
|
||||||
int? play;
|
int? play;
|
||||||
int? thumbUp;
|
|
||||||
int? thumbDown;
|
|
||||||
int? share;
|
|
||||||
int? reply;
|
|
||||||
int? danmaku;
|
int? danmaku;
|
||||||
num? coin;
|
|
||||||
int? vt;
|
|
||||||
int? playSwitch;
|
|
||||||
String? viewText1;
|
|
||||||
|
|
||||||
CntInfo({
|
CntInfo({
|
||||||
this.collect,
|
|
||||||
this.play,
|
this.play,
|
||||||
this.thumbUp,
|
|
||||||
this.thumbDown,
|
|
||||||
this.share,
|
|
||||||
this.reply,
|
|
||||||
this.danmaku,
|
this.danmaku,
|
||||||
this.coin,
|
|
||||||
this.vt,
|
|
||||||
this.playSwitch,
|
|
||||||
this.viewText1,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory CntInfo.fromJson(Map<String, dynamic> json) => CntInfo(
|
factory CntInfo.fromJson(Map<String, dynamic> json) => CntInfo(
|
||||||
collect: json['collect'] as int?,
|
|
||||||
play: json['play'] as int?,
|
play: json['play'] as int?,
|
||||||
thumbUp: json['thumb_up'] as int?,
|
|
||||||
thumbDown: json['thumb_down'] as int?,
|
|
||||||
share: json['share'] as int?,
|
|
||||||
reply: json['reply'] as int?,
|
|
||||||
danmaku: json['danmaku'] as int?,
|
danmaku: json['danmaku'] as int?,
|
||||||
coin: json['coin'] as num?,
|
|
||||||
vt: json['vt'] as int?,
|
|
||||||
playSwitch: json['play_switch'] as int?,
|
|
||||||
viewText1: json['view_text_1'] as String?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ class FavDetailData {
|
|||||||
FavFolderInfo? info;
|
FavFolderInfo? info;
|
||||||
List<FavDetailItemModel>? medias;
|
List<FavDetailItemModel>? medias;
|
||||||
bool? hasMore;
|
bool? hasMore;
|
||||||
int? ttl;
|
|
||||||
|
|
||||||
FavDetailData({this.info, this.medias, this.hasMore, this.ttl});
|
FavDetailData({this.info, this.medias, this.hasMore});
|
||||||
|
|
||||||
factory FavDetailData.fromJson(Map<String, dynamic> json) => FavDetailData(
|
factory FavDetailData.fromJson(Map<String, dynamic> json) => FavDetailData(
|
||||||
info: json['info'] == null
|
info: json['info'] == null
|
||||||
@@ -17,6 +16,5 @@ class FavDetailData {
|
|||||||
?.map((e) => FavDetailItemModel.fromJson(e as Map<String, dynamic>))
|
?.map((e) => FavDetailItemModel.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
hasMore: json['has_more'] as bool?,
|
hasMore: json['has_more'] as bool?,
|
||||||
ttl: json['ttl'] as int?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
import 'package:PiliPlus/models/model_owner.dart';
|
|
||||||
import 'package:PiliPlus/models_new/fav/fav_detail/cnt_info.dart';
|
|
||||||
|
|
||||||
class FavDetailInfo {
|
|
||||||
int? id;
|
|
||||||
int? fid;
|
|
||||||
int? mid;
|
|
||||||
int? attr;
|
|
||||||
String? title;
|
|
||||||
String? cover;
|
|
||||||
Owner? upper;
|
|
||||||
int? coverType;
|
|
||||||
CntInfo? cntInfo;
|
|
||||||
int? type;
|
|
||||||
String? intro;
|
|
||||||
int? ctime;
|
|
||||||
int? mtime;
|
|
||||||
int? state;
|
|
||||||
int? favState;
|
|
||||||
int? likeState;
|
|
||||||
int? mediaCount;
|
|
||||||
bool? isTop;
|
|
||||||
|
|
||||||
FavDetailInfo({
|
|
||||||
this.id,
|
|
||||||
this.fid,
|
|
||||||
this.mid,
|
|
||||||
this.attr,
|
|
||||||
this.title,
|
|
||||||
this.cover,
|
|
||||||
this.upper,
|
|
||||||
this.coverType,
|
|
||||||
this.cntInfo,
|
|
||||||
this.type,
|
|
||||||
this.intro,
|
|
||||||
this.ctime,
|
|
||||||
this.mtime,
|
|
||||||
this.state,
|
|
||||||
this.favState,
|
|
||||||
this.likeState,
|
|
||||||
this.mediaCount,
|
|
||||||
this.isTop,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory FavDetailInfo.fromJson(Map<String, dynamic> json) => FavDetailInfo(
|
|
||||||
id: json['id'] as int?,
|
|
||||||
fid: json['fid'] as int?,
|
|
||||||
mid: json['mid'] as int?,
|
|
||||||
attr: json['attr'] as int?,
|
|
||||||
title: json['title'] as String?,
|
|
||||||
cover: json['cover'] as String?,
|
|
||||||
upper: json['upper'] == null
|
|
||||||
? null
|
|
||||||
: Owner.fromJson(json['upper'] as Map<String, dynamic>),
|
|
||||||
coverType: json['cover_type'] as int?,
|
|
||||||
cntInfo: json['cnt_info'] == null
|
|
||||||
? null
|
|
||||||
: CntInfo.fromJson(json['cnt_info'] as Map<String, dynamic>),
|
|
||||||
type: json['type'] as int?,
|
|
||||||
intro: json['intro'] as String?,
|
|
||||||
ctime: json['ctime'] as int?,
|
|
||||||
mtime: json['mtime'] as int?,
|
|
||||||
state: json['state'] as int?,
|
|
||||||
favState: json['fav_state'] as int?,
|
|
||||||
likeState: json['like_state'] as int?,
|
|
||||||
mediaCount: json['media_count'] as int?,
|
|
||||||
isTop: json['is_top'] as bool?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user