diff --git a/lib/common/widgets/progress_bar/segment_progress_bar.dart b/lib/common/widgets/progress_bar/segment_progress_bar.dart
index 76ffa0bb8..aec95d8a5 100644
--- a/lib/common/widgets/progress_bar/segment_progress_bar.dart
+++ b/lib/common/widgets/progress_bar/segment_progress_bar.dart
@@ -15,6 +15,8 @@
* along with PiliPlus. If not, see .
*/
+import 'dart:ui' as ui;
+
import 'package:flutter/foundation.dart' show listEquals, kDebugMode;
import 'package:flutter/gestures.dart' show TapGestureRecognizer;
import 'package:flutter/material.dart';
@@ -22,21 +24,20 @@ import 'package:flutter/rendering.dart' show BoxHitTestEntry;
@immutable
sealed class BaseSegment {
- final double start;
final double end;
const BaseSegment({
- required this.start,
required this.end,
});
}
@immutable
class Segment extends BaseSegment {
+ final double start;
final Color color;
const Segment({
- required super.start,
+ required this.start,
required super.end,
required this.color,
});
@@ -64,7 +65,6 @@ class ViewPointSegment extends BaseSegment {
final int? to;
const ViewPointSegment({
- required super.start,
required super.end,
this.title,
this.url,
@@ -78,8 +78,7 @@ class ViewPointSegment extends BaseSegment {
return true;
}
if (other is ViewPointSegment) {
- return start == other.start &&
- end == other.end &&
+ return end == other.end &&
title == other.title &&
url == other.url &&
from == other.from &&
@@ -89,13 +88,13 @@ class ViewPointSegment extends BaseSegment {
}
@override
- int get hashCode => Object.hash(start, end, title, url, from, to);
+ int get hashCode => Object.hash(end, title, url, from, to);
}
class SegmentProgressBar extends BaseSegmentProgressBar {
const SegmentProgressBar({
super.key,
- super.height = 3.5,
+ super.height,
required super.segments,
});
@@ -145,7 +144,7 @@ class ViewPointSegmentProgressBar
extends BaseSegmentProgressBar {
const ViewPointSegmentProgressBar({
super.key,
- super.height = 3.5,
+ super.height,
required super.segments,
this.onSeek,
});
@@ -192,6 +191,31 @@ class RenderViewPointProgressBar
}
static const double _barHeight = 15.0;
+ static const double _dividerWidth = 2.0;
+
+ static ui.Paragraph _getParagraph(String title, double size) {
+ final builder =
+ ui.ParagraphBuilder(
+ ui.ParagraphStyle(
+ textDirection: .ltr,
+ strutStyle: ui.StrutStyle(
+ leading: 0,
+ height: 1,
+ fontSize: size,
+ ),
+ ),
+ )
+ ..pushStyle(
+ ui.TextStyle(
+ color: Colors.white,
+ fontSize: size,
+ height: 1,
+ ),
+ )
+ ..addText(title);
+ return builder.build()
+ ..layout(const ui.ParagraphConstraints(width: double.infinity));
+ }
@override
void paint(PaintingContext context, Offset offset) {
@@ -206,61 +230,47 @@ class RenderViewPointProgressBar
paint.color = Colors.black.withValues(alpha: 0.5);
- for (int index = 0; index < segments.length; index++) {
- final isFirst = index == 0;
- final item = segments[index];
- final segmentStart = item.start * size.width;
- final segmentEnd = item.end * size.width;
+ double prevEnd = 0.0;
+ for (final segment in segments) {
+ final segmentEnd = segment.end * size.width;
+ canvas.drawRect(
+ Rect.fromLTRB(
+ segmentEnd,
+ 0,
+ segmentEnd + _dividerWidth,
+ _barHeight + height,
+ ),
+ paint,
+ );
+ final title = segment.title;
+ if (title != null && title.isNotEmpty) {
+ final segmentWidth = segmentEnd - prevEnd;
+ final paragraph = _getParagraph(title, 10);
+ final textWidth = paragraph.maxIntrinsicWidth;
+ final textHeight = paragraph.height;
- if (segmentEnd > segmentStart ||
- (segmentEnd == segmentStart && segmentStart > 0)) {
- double fontSize = 10;
-
- TextPainter getTextPainter() => TextPainter(
- text: TextSpan(
- text: item.title,
- style: TextStyle(
- color: Colors.white,
- fontSize: fontSize,
- height: 1,
- ),
- ),
- strutStyle: StrutStyle(leading: 0, height: 1, fontSize: fontSize),
- textDirection: TextDirection.ltr,
- )..layout();
-
- TextPainter textPainter = getTextPainter();
-
- late double prevStart;
- if (!isFirst) {
- prevStart = segments[index - 1].start * size.width;
+ final isOverflow = textWidth > segmentWidth;
+ final Offset offset;
+ if (isOverflow) {
+ final scale = segmentWidth / textWidth;
+ canvas
+ ..save()
+ ..translate(prevEnd, (_barHeight - textHeight * scale) / 2)
+ ..scale(scale);
+ offset = Offset.zero;
+ } else {
+ offset = Offset(
+ (segmentWidth - textWidth) / 2 + prevEnd,
+ (_barHeight - textHeight) / 2,
+ );
}
- final width = isFirst ? segmentStart : segmentStart - prevStart;
-
- while (textPainter.width > width - 2 && fontSize >= 2) {
- fontSize -= 0.5;
- textPainter.dispose();
- textPainter = getTextPainter();
+ canvas.drawParagraph(paragraph, offset);
+ paragraph.dispose();
+ if (isOverflow) {
+ canvas.restore();
}
-
- canvas.drawRect(
- Rect.fromLTRB(
- segmentStart,
- 0,
- segmentEnd == segmentStart ? segmentStart + 2 : segmentEnd,
- _barHeight + height,
- ),
- paint,
- );
-
- final textX = isFirst
- ? (segmentStart - textPainter.width) / 2
- : (segmentStart - prevStart - textPainter.width) / 2 +
- prevStart +
- 1;
- final textY = (_barHeight - textPainter.height) / 2;
- textPainter.paint(canvas, Offset(textX, textY));
}
+ prevEnd = segmentEnd + _dividerWidth;
}
}
@@ -299,8 +309,8 @@ class RenderViewPointProgressBar
try {
final seg = details.localPosition.dx / size.width;
final item = _segments
- .where((item) => item.start >= seg)
- .reduce((a, b) => a.start < b.start ? a : b);
+ .where((item) => item.end >= seg)
+ .reduce((a, b) => a.end < b.end ? a : b);
if (item.from case final from?) {
_onSeek?.call(Duration(seconds: from));
}
diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart
index f180d6e25..6bdb5c8c8 100644
--- a/lib/pages/video/controller.dart
+++ b/lib/pages/video/controller.dart
@@ -1585,13 +1585,9 @@ class VideoDetailController extends GetxController
response.viewPoints?.firstOrNull?.type == 2) {
try {
viewPointList.value = response.viewPoints!.map((item) {
- double start = (item.to! / (data.timeLength! / 1000)).clamp(
- 0.0,
- 1.0,
- );
+ final end = (item.to! / (data.timeLength! / 1000)).clamp(0.0, 1.0);
return ViewPointSegment(
- start: start,
- end: start,
+ end: end,
title: item.content,
url: item.imgUrl,
from: item.from,
diff --git a/lib/utils/permission_handler.dart b/lib/utils/permission_handler.dart
index 6a219b9ec..9e373df4e 100644
--- a/lib/utils/permission_handler.dart
+++ b/lib/utils/permission_handler.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';
@@ -24,57 +25,51 @@ Future openAppSettings() => _handler.openAppSettings();
/// Actions that can be executed on a permission.
extension PermissionActions on Permission {
/// Callback for when permission is denied.
- static Future? Function()? _onDenied;
+ static VoidCallback? _onDenied;
/// Callback for when permission is granted.
- static Future? Function()? _onGranted;
+ static VoidCallback? _onGranted;
/// Callback for when permission is permanently denied.
- static Future? Function()? _onPermanentlyDenied;
+ static VoidCallback? _onPermanentlyDenied;
/// Callback for when permission is restricted.
- static Future? Function()? _onRestricted;
+ static VoidCallback? _onRestricted;
/// Callback for when permission is limited.
- static Future? Function()? _onLimited;
+ static VoidCallback? _onLimited;
/// Callback for when permission is Provisional.
- static Future? Function()? _onProvisional;
+ static VoidCallback? _onProvisional;
/// Method to set a callback for when permission is denied.
- Permission onDeniedCallback(Future? Function()? callback) {
+ void onDeniedCallback(VoidCallback? callback) {
_onDenied = callback;
- return this;
}
/// Method to set a callback for when permission is granted.
- Permission onGrantedCallback(Future? Function()? callback) {
+ void onGrantedCallback(VoidCallback? callback) {
_onGranted = callback;
- return this;
}
/// Method to set a callback for when permission is permanently denied.
- Permission onPermanentlyDeniedCallback(Future? Function()? callback) {
+ void onPermanentlyDeniedCallback(VoidCallback? callback) {
_onPermanentlyDenied = callback;
- return this;
}
/// Method to set a callback for when permission is restricted.
- Permission onRestrictedCallback(Future? Function()? callback) {
+ void onRestrictedCallback(VoidCallback? callback) {
_onRestricted = callback;
- return this;
}
/// Method to set a callback for when permission is limited.
- Permission onLimitedCallback(Future? Function()? callback) {
+ void onLimitedCallback(VoidCallback? callback) {
_onLimited = callback;
- return this;
}
/// Method to set a callback for when permission is provisional.
- Permission onProvisionalCallback(Future? Function()? callback) {
+ void onProvisionalCallback(VoidCallback? callback) {
_onProvisional = callback;
- return this;
}
/// Checks the current status of the given [Permission].
@@ -92,8 +87,8 @@ extension PermissionActions on Permission {
///
/// This is only implemented on Android, calling this on iOS always returns
/// [false].
- Future get shouldShowRequestRationale async {
- if (defaultTargetPlatform != TargetPlatform.android) {
+ FutureOr get shouldShowRequestRationale {
+ if (!Platform.isAndroid) {
return false;
}
@@ -108,19 +103,14 @@ extension PermissionActions on Permission {
final permissionStatus =
(await [this].request())[this] ?? PermissionStatus.denied;
- if (permissionStatus.isDenied) {
- _onDenied?.call();
- } else if (permissionStatus.isGranted) {
- _onGranted?.call();
- } else if (permissionStatus.isPermanentlyDenied) {
- _onPermanentlyDenied?.call();
- } else if (permissionStatus.isRestricted) {
- _onRestricted?.call();
- } else if (permissionStatus.isLimited) {
- _onLimited?.call();
- } else if (permissionStatus.isProvisional) {
- _onProvisional?.call();
- }
+ (switch (permissionStatus) {
+ .denied => _onDenied,
+ .granted => _onGranted,
+ .restricted => _onRestricted,
+ .limited => _onLimited,
+ .permanentlyDenied => _onPermanentlyDenied,
+ .provisional => _onProvisional,
+ })?.call();
return permissionStatus;
}