Compare commits

...

8 Commits

Author SHA1 Message Date
dom
8ad130567e Release 2.0.2
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-31 18:25:39 +08:00
dom
7eb21bc5a2 build
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-31 18:24:02 +08:00
dom
ea4316a847 opt ui
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-31 16:57:12 +08:00
dom
2bbc97a950 fix macOS build
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-31 11:51:22 +08:00
dom
0178d105ba add Local Network permissions for iOS & macOS
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-31 11:17:32 +08:00
dom
771fa75f48 upgrade deps
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-31 11:17:09 +08:00
dom
82483b33fc opt live emote
Signed-off-by: dom <githubaccount56556@proton.me>
2026-03-30 00:02:58 +08:00
My-Responsitories
886c53c7d8 opt: m3e loading (#1877)
* opt: loading

* feat: refresh m3e

* restore refreshIndicator

---------

Co-authored-by: dom <githubaccount56556@proton.me>
2026-03-29 23:34:04 +08:00
15 changed files with 235 additions and 102 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -10,23 +10,21 @@ class CustomToast extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context); final colorScheme = ColorScheme.of(context);
return Container( return Container(
margin: EdgeInsets.only( margin: EdgeInsets.only(
bottom: MediaQuery.viewPaddingOf(context).bottom + 30, bottom: MediaQuery.viewPaddingOf(context).bottom + 30,
), ),
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10), padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.colorScheme.primaryContainer.withValues( color: colorScheme.primaryContainer.withValues(alpha: toastOpacity),
alpha: toastOpacity,
),
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
), ),
child: Text( child: Text(
msg, msg,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: theme.colorScheme.onPrimaryContainer, color: colorScheme.onPrimaryContainer,
), ),
), ),
); );
@@ -41,7 +39,7 @@ class LoadingWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context); final theme = Theme.of(context);
final onSurfaceVariant = theme.colorScheme.onSurfaceVariant; final onSurfaceVariant = theme.colorScheme.onSurfaceVariant;
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
@@ -58,7 +56,6 @@ class LoadingWidget extends StatelessWidget {
strokeWidth: 3, strokeWidth: 3,
valueColor: AlwaysStoppedAnimation(onSurfaceVariant), valueColor: AlwaysStoppedAnimation(onSurfaceVariant),
), ),
//msg //msg
Text(msg, style: TextStyle(color: onSurfaceVariant)), Text(msg, style: TextStyle(color: onSurfaceVariant)),
], ],

View File

@@ -217,8 +217,8 @@ class RefreshIndicatorState extends State<RefreshIndicator>
RefreshIndicatorStatus? _status; RefreshIndicatorStatus? _status;
late Future<void> _pendingRefreshFuture; late Future<void> _pendingRefreshFuture;
double? _dragOffset; double? _dragOffset;
late Color _effectiveValueColor = late Color _effectiveValueColor;
widget.color ?? Theme.of(context).colorScheme.primary; // late Color _backgroundColor;
static final Animatable<double> _threeQuarterTween = Tween<double>( static final Animatable<double> _threeQuarterTween = Tween<double>(
begin: 0.0, begin: 0.0,
@@ -274,9 +274,10 @@ class RefreshIndicatorState extends State<RefreshIndicator>
} }
void _setupColorTween() { void _setupColorTween() {
final colorScheme = ColorScheme.of(context);
// _backgroundColor = colorScheme.surfaceContainerHighest;
// Reset the current value color. // Reset the current value color.
_effectiveValueColor = _effectiveValueColor = widget.color ?? colorScheme.primary;
widget.color ?? Theme.of(context).colorScheme.primary;
final Color color = _effectiveValueColor; final Color color = _effectiveValueColor;
if (color.a == 0) { if (color.a == 0) {
// Set an always stopped animation instead of a driven tween. // Set an always stopped animation instead of a driven tween.
@@ -558,14 +559,52 @@ class RefreshIndicatorState extends State<RefreshIndicator>
} }
bool _onDrag(double offset, double viewportDimension) { bool _onDrag(double offset, double viewportDimension) {
if (_positionController.value > 0.0 && if (_positionController.value > 0.0 && _status == .drag) {
_status == RefreshIndicatorStatus.drag) {
_dragOffset = _dragOffset! + offset; _dragOffset = _dragOffset! + offset;
_checkDragOffset(viewportDimension); _checkDragOffset(viewportDimension);
return true; return true;
} }
return false; return false;
} }
// late final _refreshKey = GlobalKey();
// Widget _m3eRefreshProgressIndicator(bool showIndeterminateIndicator) {
// const indicatorMargin = EdgeInsets.all(4);
// const indicatorPadding = EdgeInsets.all(6);
// const indicatorSize = 41.0;
// final progress = _value.value;
// return Padding(
// padding: indicatorMargin,
// child: SizedBox(
// width: indicatorSize,
// height: indicatorSize,
// child: Material(
// type: MaterialType.circle,
// color: _backgroundColor,
// elevation: widget.elevation,
// child: Padding(
// padding: indicatorPadding,
// child: showIndeterminateIndicator
// ? M3ELoadingIndicator(
// childKey: _refreshKey,
// color: _effectiveValueColor,
// morphs: Morphs.refreshMorphs,
// size: null,
// )
// : RawM3ELoadingIndicator(
// key: _refreshKey,
// morph: Morphs.manualMorph,
// progress: progress,
// angle: -progress * math.pi,
// color: _valueColor.value!,
// size: null,
// ),
// ),
// ),
// ),
// );
// }
} }
// ignore: camel_case_types // ignore: camel_case_types

View File

@@ -18,6 +18,7 @@
import 'dart:math' show pi; import 'dart:math' show pi;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart' show SemanticsConfiguration;
/// ///
/// created by dom on 2026/02/14 /// created by dom on 2026/02/14
@@ -73,6 +74,7 @@ class RenderLoadingIndicator extends RenderBox {
if (_progress == value) return; if (_progress == value) return;
_progress = value; _progress = value;
markNeedsPaint(); markNeedsPaint();
markNeedsSemanticsUpdate();
} }
@override @override
@@ -119,6 +121,16 @@ class RenderLoadingIndicator extends RenderBox {
); );
} }
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
config
..role = .progressBar
..minValue = '0'
..maxValue = '100'
..value = (_progress * 100).round().toString();
}
@override @override
bool get isRepaintBoundary => true; bool get isRepaintBoundary => true;
} }

View File

@@ -4,8 +4,6 @@ import 'package:flutter/material.dart';
const Widget m3eLoading = Center(child: M3ELoadingIndicator()); const Widget m3eLoading = Center(child: M3ELoadingIndicator());
const Widget circularLoading = Center(child: CircularProgressIndicator());
const Widget linearLoading = SliverToBoxAdapter( const Widget linearLoading = SliverToBoxAdapter(
child: LinearProgressIndicator(), child: LinearProgressIndicator(),
); );

View File

@@ -17,14 +17,27 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:PiliPlus/common/widgets/loading_widget/morphs.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/physics.dart' show SpringSimulation; import 'package:flutter/physics.dart' show SpringSimulation;
import 'package:flutter/semantics.dart';
import 'package:material_new_shapes/material_new_shapes.dart'; import 'package:material_new_shapes/material_new_shapes.dart';
/// reimplement of https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/loading_indicator_m3e /// reimplement of https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/loading_indicator_m3e
class M3ELoadingIndicator extends StatefulWidget { class M3ELoadingIndicator extends StatefulWidget {
const M3ELoadingIndicator({super.key}); const M3ELoadingIndicator({
super.key,
// this.childKey,
this.morphs,
this.color,
this.size = const Size.square(40),
});
final List<Morph>? morphs;
final Color? color;
final Size size;
// final Key? childKey;
@override @override
State<M3ELoadingIndicator> createState() => _M3ELoadingIndicatorState(); State<M3ELoadingIndicator> createState() => _M3ELoadingIndicatorState();
@@ -32,42 +45,25 @@ class M3ELoadingIndicator extends StatefulWidget {
class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator> class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
static final List<Morph> _morphs = () {
final List<RoundedPolygon> shapes = [
MaterialShapes.softBurst,
MaterialShapes.cookie9Sided,
MaterialShapes.pentagon,
MaterialShapes.pill,
MaterialShapes.sunny,
MaterialShapes.cookie4Sided,
MaterialShapes.oval,
];
return [
for (var i = 0; i < shapes.length; i++)
Morph(
shapes[i],
shapes[(i + 1) % shapes.length],
),
];
}();
static const int _morphIntervalMs = 650; static const int _morphIntervalMs = 650;
static const double _fullRotation = 360.0; static const double _fullRotation = 2 * math.pi;
static const int _globalRotationDurationMs = 4666; static const int _globalRotationDurationMs = 4666;
static const double _quarterRotation = _fullRotation / 4; static const double _quarterRotation = _fullRotation / 4;
late final List<Morph> _morphs;
late final AnimationController _controller; late final AnimationController _controller;
int _morphIndex = 1; int _morphIndex = 1;
double _morphRotationTargetAngle = _quarterRotation; double _morphRotationTarget = _quarterRotation;
final _morphAnimationSpec = SpringSimulation( static final _morphAnimationSpec = SpringSimulation(
SpringDescription.withDampingRatio(ratio: 0.6, stiffness: 200.0, mass: 1.0), SpringDescription.withDampingRatio(ratio: 0.6, stiffness: 200.0, mass: 1.0),
0.0, 0.0,
1.0, 1.0,
5.0, 5.0,
snapToEnd: true, snapToEnd: true,
// tolerance: const Tolerance(velocity: 0.1, distance: 0.1),
); );
void _statusListener(AnimationStatus status) { void _statusListener(AnimationStatus status) {
@@ -78,23 +74,21 @@ class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
void _startAnimation() { void _startAnimation() {
_morphIndex++; _morphIndex++;
_morphRotationTargetAngle = _morphRotationTarget =
(_morphRotationTargetAngle + _quarterRotation) % _fullRotation; (_morphRotationTarget + _quarterRotation) % _fullRotation;
_controller _controller.animateWith(_morphAnimationSpec);
..value = 0.0
..animateWith(_morphAnimationSpec);
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_morphs = widget.morphs ?? Morphs.loadingMorphs;
_controller = _controller =
AnimationController( AnimationController(
vsync: this, vsync: this,
duration: const Duration(milliseconds: _morphIntervalMs), duration: const Duration(milliseconds: _morphIntervalMs),
) )
..addStatusListener(_statusListener) ..addStatusListener(_statusListener)
..value = 0.0
..animateWith(_morphAnimationSpec); ..animateWith(_morphAnimationSpec);
} }
@@ -110,82 +104,86 @@ class _M3ELoadingIndicatorState extends State<M3ELoadingIndicator>
final elapsedInMs = final elapsedInMs =
_morphIntervalMs * (_morphIndex - 1) + _morphIntervalMs * (_morphIndex - 1) +
(_controller.lastElapsedDuration?.inMilliseconds ?? 0); (_controller.lastElapsedDuration?.inMilliseconds ?? 0);
final globalRotationControllerValue = final globalRotation =
(elapsedInMs % _globalRotationDurationMs) / _globalRotationDurationMs; (elapsedInMs % _globalRotationDurationMs) /
final globalRotationDegrees = globalRotationControllerValue * _fullRotation; _globalRotationDurationMs *
final totalRotationDegrees = _fullRotation;
progress * _quarterRotation +
_morphRotationTargetAngle + return progress * _quarterRotation + _morphRotationTarget + globalRotation;
globalRotationDegrees;
return totalRotationDegrees * (math.pi / 180.0);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final color = Theme.of(context).colorScheme.secondaryFixedDim; final color = widget.color ?? ColorScheme.of(context).secondaryFixedDim;
return AnimatedBuilder( return AnimatedBuilder(
animation: _controller, animation: _controller,
builder: (context, child) { builder: (context, child) {
final progress = _controller.value; final progress = _controller.value;
return _M3ELoadingIndicator( return RawM3ELoadingIndicator(
// key: widget.childKey,
morph: _morphs[_morphIndex % _morphs.length], morph: _morphs[_morphIndex % _morphs.length],
progress: progress, progress: progress,
angle: _calcAngle(progress), angle: _calcAngle(progress),
color: color, color: color,
size: widget.size,
); );
}, },
); );
} }
} }
class _M3ELoadingIndicator extends LeafRenderObjectWidget { class RawM3ELoadingIndicator extends LeafRenderObjectWidget {
const _M3ELoadingIndicator({ const RawM3ELoadingIndicator({
super.key,
required this.morph, required this.morph,
required this.progress, required this.progress,
required this.angle, required this.angle,
required this.color, required this.color,
required this.size,
}); });
final Morph morph; final Morph morph;
final double progress; final double progress;
final double angle; final double angle;
final Color color; final Color color;
final Size size;
@override @override
RenderObject createRenderObject(BuildContext context) { RenderObject createRenderObject(BuildContext context) {
return _RenderM3ELoadingIndicator( return RenderM3ELoadingIndicator(
morph: morph, morph: morph,
progress: progress, progress: progress,
angle: angle, angle: angle,
color: color, color: color,
size: size,
); );
} }
@override @override
void updateRenderObject( void updateRenderObject(
BuildContext context, BuildContext context,
_RenderM3ELoadingIndicator renderObject, RenderM3ELoadingIndicator renderObject,
) { ) {
renderObject renderObject
..morph = morph ..morph = morph
..progress = progress ..progress = progress
..angle = angle ..angle = angle
..color = color; ..color = color
..preferredSize = size;
} }
} }
class _RenderM3ELoadingIndicator extends RenderBox { class RenderM3ELoadingIndicator extends RenderBox {
_RenderM3ELoadingIndicator({ RenderM3ELoadingIndicator({
required Morph morph, required Morph morph,
required double progress, required double progress,
required double angle, required double angle,
required Color color, required Color color,
required Size size,
}) : _morph = morph, }) : _morph = morph,
_progress = progress, _progress = progress,
_angle = angle, _angle = angle,
_preferredSize = size,
_color = color, _color = color,
_paint = Paint() _paint = Paint()
..style = PaintingStyle.fill ..style = PaintingStyle.fill
@@ -223,20 +221,38 @@ class _RenderM3ELoadingIndicator extends RenderBox {
markNeedsPaint(); markNeedsPaint();
} }
Size _preferredSize;
set preferredSize(Size value) {
if (_preferredSize == value) return;
_preferredSize = size;
markNeedsLayout();
}
@override
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.constrain(_preferredSize);
}
@override @override
void performLayout() { void performLayout() {
size = constraints.constrainDimensions(40, 40); size = computeDryLayout(constraints);
}
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
config.role = .loadingSpinner;
} }
@override @override
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
final width = size.width; final width = size.width;
final value = size.width / 2; final value = size.width / 2;
final matrix = Matrix4.identity() final matrix =
..translateByDouble(offset.dx + value, offset.dy + value, 0.0, 1.0) Matrix4.translationValues(offset.dx + value, offset.dy + value, 0.0)
..rotateZ(angle) ..rotateZ(angle)
..translateByDouble(-value, -value, 0.0, 1.0) ..translateByDouble(-value, -value, 0.0, 1.0)
..scaleByDouble(width, width, width, 1.0); ..scaleByDouble(width, width, width, 1.0);
final path = morph.toPath(progress: progress).transform(matrix.storage); final path = morph.toPath(progress: progress).transform(matrix.storage);
context.canvas.drawPath(path, _paint); context.canvas.drawPath(path, _paint);

View File

@@ -0,0 +1,41 @@
import 'package:material_new_shapes/material_new_shapes.dart';
abstract final class Morphs {
static List<Morph> buildMorph(
List<RoundedPolygon> shapes, {
bool loop = true,
}) {
assert(shapes.length >= 2);
return [
for (var i = 0; i < shapes.length - 1; i++)
Morph(shapes[i], shapes[i + 1]),
if (loop) Morph(shapes[shapes.length - 1], shapes[0]),
];
}
static final loadingMorphs = buildMorph([
MaterialShapes.softBurst,
MaterialShapes.cookie9Sided,
MaterialShapes.pentagon,
MaterialShapes.pill,
MaterialShapes.sunny,
MaterialShapes.cookie4Sided,
MaterialShapes.oval,
]);
// static final refreshMorphs = buildMorph([
// MaterialShapes.softBurst,
// MaterialShapes.cookie9Sided,
// MaterialShapes.gem,
// MaterialShapes.flower,
// MaterialShapes.sunny,
// MaterialShapes.cookie4Sided,
// MaterialShapes.oval,
// MaterialShapes.cookie12Sided,
// ]);
// static final manualMorph = Morph(
// MaterialShapes.circle,
// MaterialShapes.softBurst,
// );
}

View File

@@ -3,7 +3,7 @@ class BaseEmote {
late String emoticonUnique; late String emoticonUnique;
late double width; late double width;
late double height; late double height;
late final isUpower = emoticonUnique.startsWith('upower_'); late final isOfficial = emoticonUnique.startsWith('official_');
BaseEmote.fromJson(Map<String, dynamic> json) { BaseEmote.fromJson(Map<String, dynamic> json) {
url = json['url']; url = json['url'];

View File

@@ -181,21 +181,23 @@ class AuthorPanel extends StatelessWidget {
Positioned( Positioned(
top: 0, top: 0,
right: 0, right: 0,
height: height, bottom: 0,
child: CachedNetworkImage( child: Center(
height: height, child: CachedNetworkImage(
memCacheHeight: height.cacheSize(context), height: height,
imageUrl: ImageUtils.safeThumbnailUrl( memCacheHeight: height.cacheSize(context),
moduleAuthor.decorate!.cardUrl, imageUrl: ImageUtils.safeThumbnailUrl(
moduleAuthor.decorate!.cardUrl,
),
placeholder: (_, _) => const SizedBox.shrink(),
), ),
placeholder: (_, _) => const SizedBox.shrink(),
), ),
), ),
if (moduleAuthor.decorate!.fan?.numStr?.isNotEmpty == true) if (moduleAuthor.decorate!.fan?.numStr?.isNotEmpty == true)
Positioned( Positioned(
top: 0, top: 0,
bottom: 0,
right: height, right: height,
height: height,
child: Center( child: Center(
child: Text( child: Text(
moduleAuthor.decorate!.fan!.numStr!.toString(), moduleAuthor.decorate!.fan!.numStr!.toString(),

View File

@@ -2,7 +2,6 @@ import 'package:PiliPlus/common/widgets/flutter/popup_menu.dart';
import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/http/live.dart'; import 'package:PiliPlus/http/live.dart';
import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/models_new/live/live_danmaku/danmaku_msg.dart'; import 'package:PiliPlus/models_new/live/live_danmaku/danmaku_msg.dart';
import 'package:PiliPlus/models_new/live/live_superchat/item.dart'; import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
import 'package:PiliPlus/pages/live_room/controller.dart'; import 'package:PiliPlus/pages/live_room/controller.dart';
@@ -241,14 +240,20 @@ class LiveRoomChatPanel extends StatelessWidget {
InlineSpan _buildMsg(double devicePixelRatio, DanmakuMsg obj) { InlineSpan _buildMsg(double devicePixelRatio, DanmakuMsg obj) {
final uemote = obj.uemote; final uemote = obj.uemote;
if (uemote != null) { if (uemote != null) {
// "room_{{room_id}}_{{int}}" or "upower_[{{emote}}]" // "room_{{room_id}}_{{int}}" , "upower_[{{emote}}]" , "official_{{int}}"
final isUpower = uemote.isUpower; final double width, height;
if (uemote.isOfficial) {
width = uemote.width / devicePixelRatio;
height = uemote.height / devicePixelRatio;
} else {
width = height = 162.0 / devicePixelRatio;
}
return WidgetSpan( return WidgetSpan(
child: NetworkImgLayer( child: NetworkImgLayer(
src: uemote.url, src: uemote.url,
type: ImageType.emote, type: .emote,
width: isUpower ? uemote.width : uemote.width / devicePixelRatio, width: width,
height: isUpower ? uemote.height : uemote.height / devicePixelRatio, height: height,
), ),
); );
} }
@@ -265,7 +270,7 @@ class LiveRoomChatPanel extends StatelessWidget {
WidgetSpan( WidgetSpan(
child: NetworkImgLayer( child: NetworkImgLayer(
src: emote.url, src: emote.url,
type: ImageType.emote, type: .emote,
width: emote.width, width: emote.width,
height: emote.height, height: emote.height,
), ),

View File

@@ -73,3 +73,10 @@ foreach ($patch in $patches) {
Write-Host "$patch applied" Write-Host "$patch applied"
} }
} }
# TODO: remove
if ($platform.ToLower() -eq "android") {
"69e31205362b4e59b7eb89b24797e687b4b67afe" | Set-Content -Path .\bin\internal\engine.version
Remove-Item -Path ".\bin\cache" -Recurse -Force
flutter --version
}

View File

@@ -28,5 +28,13 @@
<string>MainMenu</string> <string>MainMenu</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string>NSApplication</string> <string>NSApplication</string>
<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>

View File

@@ -320,18 +320,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: connectivity_plus name: connectivity_plus
sha256: "33bae12a398f841c6cda09d1064212957265869104c478e5ad51e2fb26c3973c" sha256: b8fe52979ff12432ecf8f0abf6ff70410b1bb734be1c9e4f2f86807ad7166c79
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.1.0"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: connectivity_plus_platform_interface name: connectivity_plus_platform_interface
sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" sha256: "3c09627c536d22fd24691a905cdd8b14520de69da52c7a97499c8be5284a32ed"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.1.0"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@@ -400,10 +400,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: "4df8babf73058181227e18b08e6ea3520cf5fc5d796888d33b7cb0f33f984b7c" sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.3.0" version: "12.4.0"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -906,10 +906,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_cropper name: image_cropper
sha256: "2cd06f097b5bd18ff77d3f80fadef83e270ea23c82906bbf17febc3db8d68ec6" sha256: d2555be1ec4b7b12fc502ede481c846ad44578fbb0748debd4c648b25ca07cad
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.1.0" version: "12.1.1"
image_cropper_for_web: image_cropper_for_web:
dependency: transitive dependency: transitive
description: description:
@@ -1283,10 +1283,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.0" version: "9.0.1"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -1579,10 +1579,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840" sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.0.1" version: "12.0.2"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -1905,10 +1905,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics name: vector_graphics
sha256: "7076216a10d5c390315fbe536a30f1254c341e7543e6c4c8a815e591307772b1" sha256: "81da85e9ca8885ade47f9685b953cb098970d11be4821ac765580a6607ea4373"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.20" version: "1.1.21"
vector_graphics_codec: vector_graphics_codec:
dependency: transitive dependency: transitive
description: description:

View File

@@ -17,7 +17,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
# update when release # update when release
version: 2.0.1+1 version: 2.0.2+1
environment: environment:
sdk: ">=3.10.0" sdk: ">=3.10.0"