* opt: proxy

* opt: calcWindowPosition

* fix: height depend on svg

* bump

* fix

* ci: cache linux

* string systemProxyPort

---------

Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
My-Responsitories
2025-10-04 09:44:41 +08:00
committed by GitHub
parent a928e48159
commit a5715868b3
9 changed files with 315 additions and 173 deletions

View File

@@ -0,0 +1,226 @@
// code from cached_network_svg_image;
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CachedNetworkSVGImage extends StatefulWidget {
CachedNetworkSVGImage(
String url, {
Key? key,
String? cacheKey,
Widget? placeholder,
Widget? errorWidget,
double? width,
double? height,
Map<String, String>? headers,
BoxFit fit = BoxFit.contain,
AlignmentGeometry alignment = Alignment.center,
bool matchTextDirection = false,
bool allowDrawingOutsideViewBox = false,
String? semanticsLabel,
bool excludeFromSemantics = false,
SvgTheme theme = const SvgTheme(),
ColorFilter? colorFilter,
WidgetBuilder? placeholderBuilder,
BaseCacheManager? cacheManager,
}) : _url = url,
_cacheKey = cacheKey,
_placeholder = placeholder,
_errorWidget = errorWidget,
_width = width,
_height = height,
_headers = headers,
_fit = fit,
_alignment = alignment,
_matchTextDirection = matchTextDirection,
_allowDrawingOutsideViewBox = allowDrawingOutsideViewBox,
_semanticsLabel = semanticsLabel,
_excludeFromSemantics = excludeFromSemantics,
_theme = theme,
_colorFilter = colorFilter,
_placeholderBuilder = placeholderBuilder,
_cacheManager = cacheManager ?? DefaultCacheManager(),
super(key: key ?? ValueKey(cacheKey ?? url));
final String _url;
final String? _cacheKey;
final Widget? _placeholder;
final Widget? _errorWidget;
final double? _width;
final double? _height;
final Map<String, String>? _headers;
final BoxFit _fit;
final AlignmentGeometry _alignment;
final bool _matchTextDirection;
final bool _allowDrawingOutsideViewBox;
final String? _semanticsLabel;
final bool _excludeFromSemantics;
final SvgTheme _theme;
final ColorFilter? _colorFilter;
final WidgetBuilder? _placeholderBuilder;
final BaseCacheManager _cacheManager;
@override
State<CachedNetworkSVGImage> createState() => _CachedNetworkSVGImageState();
static Future<void> preCache(
String imageUrl, {
String? cacheKey,
BaseCacheManager? cacheManager,
}) {
final key = cacheKey ?? _generateKeyFromUrl(imageUrl);
cacheManager ??= DefaultCacheManager();
return cacheManager.downloadFile(key);
}
static Future<void> clearCacheForUrl(
String imageUrl, {
String? cacheKey,
BaseCacheManager? cacheManager,
}) {
final key = cacheKey ?? _generateKeyFromUrl(imageUrl);
cacheManager ??= DefaultCacheManager();
return cacheManager.removeFile(key);
}
static Future<void> clearCache({BaseCacheManager? cacheManager}) {
cacheManager ??= DefaultCacheManager();
return cacheManager.emptyCache();
}
static String _generateKeyFromUrl(String url) => url.split('?').first;
}
class _CachedNetworkSVGImageState extends State<CachedNetworkSVGImage> {
bool _isLoading = false;
bool _isError = false;
String? _svgString;
late final String _cacheKey;
double? height;
late TextScaler textScaler;
static final _sizeRegExp = RegExp(
r'height="([\d\.]+)([c-x]{2})?"',
);
@override
void initState() {
super.initState();
_cacheKey =
widget._cacheKey ??
CachedNetworkSVGImage._generateKeyFromUrl(widget._url);
_loadImage();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
textScaler = MediaQuery.textScalerOf(context);
}
Future<void> _loadImage() async {
try {
var file = (await widget._cacheManager.getFileFromMemory(
_cacheKey,
))?.file;
file ??= await widget._cacheManager.getSingleFile(
widget._url,
key: _cacheKey,
headers: widget._headers ?? {},
);
final svg = await file.readAsString();
_svgString = svg;
if (widget._width == null && widget._height == null) {
final match = _sizeRegExp.firstMatch(svg);
if (match != null) {
double h = double.parse(match.group(1)!);
final suffix = match.group(2);
if (suffix != null) {
h *= switch (suffix) {
'em' => textScaler.scale(widget._theme.fontSize),
'ex' => textScaler.scale(widget._theme.xHeight),
'pt' => 1.25,
'pc' => 15.0,
'mm' => 3.543307,
'cm' => 35.43307,
'in' => 90.0,
_ => 1.0,
};
}
height = h;
}
}
_isLoading = false;
_setState();
} catch (e) {
log('CachedNetworkSVGImage: $e');
_isError = true;
_isLoading = false;
_setState();
}
}
void _setState() {
if (mounted) {
setState(() {});
} else {
SchedulerBinding.instance.addPostFrameCallback((_) => setState(() {}));
}
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
width: widget._width,
height: widget._height,
child: _buildImage(),
);
}
Widget? _buildImage() {
if (_isLoading) return _buildPlaceholderWidget();
if (_isError) return _buildErrorWidget();
return _buildSVGImage();
}
Widget _buildPlaceholderWidget() => Center(child: widget._placeholder);
Widget _buildErrorWidget() => Center(child: widget._errorWidget);
Widget? _buildSVGImage() {
if (_svgString == null) {
return Center(child: widget._placeholderBuilder?.call(context));
}
return SvgPicture.string(
_svgString!,
fit: widget._fit,
width: widget._width,
height: widget._height ?? height,
alignment: widget._alignment,
matchTextDirection: widget._matchTextDirection,
allowDrawingOutsideViewBox: widget._allowDrawingOutsideViewBox,
semanticsLabel: widget._semanticsLabel,
excludeFromSemantics: widget._excludeFromSemantics,
colorFilter: widget._colorFilter,
placeholderBuilder: widget._placeholderBuilder,
theme: widget._theme,
);
}
}

View File

@@ -106,32 +106,31 @@ class Request {
persistentConnection: true,
);
bool enableSystemProxy = Pref.enableSystemProxy;
final bool enableSystemProxy;
late final String systemProxyHost;
late final int? systemProxyPort;
if (enableSystemProxy) {
if (Pref.enableSystemProxy) {
systemProxyHost = Pref.systemProxyHost;
systemProxyPort = int.tryParse(Pref.systemProxyPort);
enableSystemProxy = systemProxyPort != null && systemProxyHost.isNotEmpty;
} else {
enableSystemProxy = false;
}
final http11Adapter = IOHttpClientAdapter(
createHttpClient: () {
final client = HttpClient()
..idleTimeout = const Duration(seconds: 15)
..autoUncompress = false; // Http2Adapter没有自动解压, 统一行为
// 设置代理
if (enableSystemProxy) {
client
..findProxy = ((_) => 'PROXY $systemProxyHost:$systemProxyPort')
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
return client;
},
createHttpClient: enableSystemProxy
? () => HttpClient()
..idleTimeout = const Duration(seconds: 15)
..autoUncompress = false
..findProxy = ((_) => 'PROXY $systemProxyHost:$systemProxyPort')
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true
: () => HttpClient()
..idleTimeout = const Duration(seconds: 15)
..autoUncompress = false, // Http2Adapter没有自动解压, 统一行为
);
late Uri proxy;
late final Uri proxy;
if (enableSystemProxy) {
proxy = Uri(
scheme: 'http',

View File

@@ -1,5 +1,6 @@
import 'dart:math';
import 'package:PiliPlus/common/widgets/cached_network_svg_image.dart';
import 'package:PiliPlus/common/widgets/image/custom_grid_view.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/http/constants.dart';
@@ -15,7 +16,6 @@ import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_svg_image/cached_network_svg_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
@@ -88,7 +88,6 @@ class OpusContent extends StatelessWidget {
child: CachedNetworkSVGImage(
cacheKey: latex,
semanticsLabel: latex,
height: 65,
'${HttpString.apiBaseUrl}/x/web-frontend/mathjax/tex?formula=${Uri.encodeComponent(latex)}',
colorFilter: ColorFilter.mode(
colorScheme.onSurfaceVariant,
@@ -96,6 +95,7 @@ class OpusContent extends StatelessWidget {
),
alignment: Alignment.centerLeft,
placeholderBuilder: (_) => Text(latex),
errorWidget: Text(latex),
),
);
default:

View File

@@ -984,7 +984,7 @@ List<SettingsModel> get extraSettings => [
TextField(
decoration: InputDecoration(
isDense: true,
labelText: systemProxyHost != ''
labelText: systemProxyHost.isNotEmpty
? systemProxyHost
: '请输入Host使用 . 分割',
border: const OutlineInputBorder(
@@ -992,16 +992,14 @@ List<SettingsModel> get extraSettings => [
),
hintText: systemProxyHost,
),
onChanged: (e) {
systemProxyHost = e;
},
onChanged: (e) => systemProxyHost = e,
),
const SizedBox(height: 10),
TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
isDense: true,
labelText: systemProxyPort != ''
labelText: systemProxyPort.isNotEmpty
? systemProxyPort
: '请输入Port',
border: const OutlineInputBorder(
@@ -1009,9 +1007,8 @@ List<SettingsModel> get extraSettings => [
),
hintText: systemProxyPort,
),
onChanged: (e) {
systemProxyPort = e;
},
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onChanged: (e) => systemProxyPort = e,
),
],
),

View File

@@ -1,34 +1,37 @@
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:screen_retriever/screen_retriever.dart';
Future<Offset> calcWindowPosition(Size windowSize) async {
Display primaryDisplay = await screenRetriever.getPrimaryDisplay();
List<Display> allDisplays = await screenRetriever.getAllDisplays();
Offset cursorScreenPoint = await screenRetriever.getCursorScreenPoint();
final allDisplays = screenRetriever.getAllDisplays();
final cursorScreenPoint = await screenRetriever.getCursorScreenPoint();
Display currentDisplay = allDisplays.firstWhere(
(display) => Rect.fromLTWH(
display.visiblePosition!.dx,
display.visiblePosition!.dy,
display.size.width,
display.size.height,
).contains(cursorScreenPoint),
orElse: () => primaryDisplay,
);
final currentDisplay =
(await allDisplays).firstWhereOrNull(
(display) => (display.visiblePosition! & display.size).contains(
cursorScreenPoint,
),
) ??
await screenRetriever.getPrimaryDisplay();
num visibleWidth = currentDisplay.size.width;
num visibleHeight = currentDisplay.size.height;
num visibleStartX = 0;
num visibleStartY = 0;
if (currentDisplay.visibleSize != null) {
visibleWidth = currentDisplay.visibleSize!.width;
visibleHeight = currentDisplay.visibleSize!.height;
final double visibleWidth;
final double visibleHeight;
if (currentDisplay.visibleSize case final size?) {
visibleWidth = size.width;
visibleHeight = size.height;
} else {
visibleWidth = currentDisplay.size.width;
visibleHeight = currentDisplay.size.height;
}
if (currentDisplay.visiblePosition != null) {
visibleStartX = currentDisplay.visiblePosition!.dx;
visibleStartY = currentDisplay.visiblePosition!.dy;
final double visibleStartX;
final double visibleStartY;
if (currentDisplay.visiblePosition case final offset?) {
visibleStartX = offset.dx;
visibleStartY = offset.dy;
} else {
visibleStartX = visibleStartY = 0;
}
final windowPosition = Pref.windowPosition;