opt: binary search fontsize (#1818)

* opt: permission

* opt: opt: binary search fontsize

* use transform

Signed-off-by: dom <githubaccount56556@proton.me>

* fix

Signed-off-by: dom <githubaccount56556@proton.me>

* opt: matrix

* opt [skip ci]

* tweaks [skip ci]

Signed-off-by: dom <githubaccount56556@proton.me>

---------

Co-authored-by: dom <githubaccount56556@proton.me>
This commit is contained in:
My-Responsitories
2026-02-01 00:01:34 +08:00
committed by GitHub
parent 8964197b73
commit 77fff92939
3 changed files with 97 additions and 101 deletions

View File

@@ -15,6 +15,8 @@
* along with PiliPlus. If not, see <https://www.gnu.org/licenses/>.
*/
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<Segment> {
const SegmentProgressBar({
super.key,
super.height = 3.5,
super.height,
required super.segments,
});
@@ -145,7 +144,7 @@ class ViewPointSegmentProgressBar
extends BaseSegmentProgressBar<ViewPointSegment> {
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));
}