Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ PullRead 本体以 [MIT](../LICENSE) 发布。本文件列出随应用一起分
| [`flutter_highlight`](https://pub.dev/packages/flutter_highlight) | 0.7.0 | MIT | highlight.js 代码高亮绑定 |
| [`flutter_svg`](https://pub.dev/packages/flutter_svg) | 2.3.2 | MIT | SVG 图片渲染 |
| [`archive`](https://pub.dev/packages/archive) | 4.5.2 | MIT | 压缩包/归档处理 |
| [`app_settings`](https://pub.dev/packages/app_settings) | 9.0.1 | MIT | 权限被拒后跳转系统设置 |
| [`fast_gbk`](https://pub.dev/packages/fast_gbk) | 1.0.0 | BSD-3-Clause | GBK 文本解码 |
| [`http`](https://pub.dev/packages/http) | 1.6.0 | BSD-3-Clause | 图片缓存与条件请求 |
| [`path_provider`](https://pub.dev/packages/path_provider) | 2.1.6 | BSD-3-Clause | 应用文档/缓存目录 |
Expand Down Expand Up @@ -53,12 +54,13 @@ libgit2 采用 GPL-2.0 + linking exception:把**未修改的** libgit2 链接

## 3. 完整依赖清单

下表包含 `pubspec.lock` 中全部 124 个 hosted 包(不含 Flutter/Dart SDK 自带包)。
下表包含 `pubspec.lock` 中全部 125 个 hosted 包(不含 Flutter/Dart SDK 自带包)。
「传递」表示由直接依赖间接引入,实际同样随应用打包;「开发」仅用于构建、图标生成
和测试,不进入应用包。

| 包 | 版本 | 许可证 | 使用 |
| --- | --- | --- | --- |
| [`app_settings`](https://pub.dev/packages/app_settings) | 9.0.1 | MIT | 运行时 |
| [`archive`](https://pub.dev/packages/archive) | 4.5.2 | MIT | 运行时 |
| [`fast_gbk`](https://pub.dev/packages/fast_gbk) | 1.0.0 | BSD-3-Clause | 运行时 |
| [`file_selector`](https://pub.dev/packages/file_selector) | 1.1.0 | BSD-3-Clause | 运行时 |
Expand Down
8 changes: 8 additions & 0 deletions lib/src/ui/image_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:app_settings/app_settings.dart';
import 'package:gal/gal.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
Expand Down Expand Up @@ -102,6 +103,13 @@ Future<void> showImageActions(
GallerySaveOutcome.unsupported => '该图片格式无法存入相册,请使用分享',
GallerySaveOutcome.failed => '保存失败,请稍后重试',
}),
// iOS/Android 权限被拒后 SnackBar 里给一条直接出路,避免死胡同
action: outcome == GallerySaveOutcome.denied
? SnackBarAction(
label: '去设置',
onPressed: () => AppSettings.openAppSettings(),
)
: null,
),
);
return;
Expand Down
45 changes: 41 additions & 4 deletions lib/src/ui/markdown_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_highlight/flutter_highlight.dart';
import 'package:flutter_highlight/themes/atom-one-dark.dart';
import 'package:flutter_highlight/themes/github.dart';
import 'package:app_settings/app_settings.dart';
import 'package:markdown/markdown.dart' as m;
import 'package:markdown_widget/markdown_widget.dart';
import 'package:mermaid_flutter/mermaid_flutter.dart';
Expand Down Expand Up @@ -824,7 +825,15 @@ class _MarkdownViewerPageState extends State<MarkdownViewerPage> {
if (outcome == GallerySaveOutcome.saved) {
messenger.showSnackBar(const SnackBar(content: Text('已保存到相册「PullRead」')));
} else if (outcome == GallerySaveOutcome.denied) {
messenger.showSnackBar(const SnackBar(content: Text('未获得相册权限,仅生成分享文件')));
messenger.showSnackBar(
SnackBar(
content: const Text('未获得相册权限,仅生成分享文件'),
action: SnackBarAction(
label: '去设置',
onPressed: () => AppSettings.openAppSettings(),
),
),
);
}
await shareImageBytes(png, name: name, text: _title, extension: '.png');
}
Expand Down Expand Up @@ -1744,15 +1753,37 @@ class _MarkdownViewerPageState extends State<MarkdownViewerPage> {
);
}

/// 链接打不开时的轻提示(挂在当前 Scaffold 上,忽略已挂起的路由)。
void _showLinkHint(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}

/// 链接点击:外部链接浏览器打开;#锚点页内跳转;
/// 相对路径链接解析为仓库内文件(笔记进阅读页,其余进代码查看器)。
/// mailto:/tel: 走系统处理;打不开时给出提示而不是静默不动。
Future<void> _onLinkTap(String href) async {
final url = href.trim();
if (url.isEmpty) return;
if (url.startsWith('http://') || url.startsWith('https://')) {
final scheme = url.indexOf('://');
final isExternal = url.startsWith('http://') || url.startsWith('https://');
final isSystemScheme = !isExternal &&
scheme > 0 &&
const ['mailto', 'tel', 'sms'].contains(
url.substring(0, scheme).toLowerCase(),
);
if (isExternal || isSystemScheme) {
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
try {
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
} else {
_showLinkHint('当前设备没有能打开此链接的应用');
}
} on Object {
_showLinkHint('打开链接失败');
}
return;
}
Expand Down Expand Up @@ -2828,6 +2859,12 @@ Future<void> _showMermaidExport(
GallerySaveOutcome.unsupported => '该图片格式无法存入相册,请使用分享',
GallerySaveOutcome.failed => '保存失败,请稍后重试',
}),
action: outcome == GallerySaveOutcome.denied
? SnackBarAction(
label: '去设置',
onPressed: () => AppSettings.openAppSettings(),
)
: null,
),
);
return;
Expand Down
20 changes: 12 additions & 8 deletions lib/src/ui/settings/about_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
Expand Down Expand Up @@ -136,14 +138,16 @@ class _AboutPageState extends State<AboutPage> {
trailing: const Icon(Icons.open_in_new, size: 18),
onTap: () => _open(Uri.parse(_repoUrl)),
),
ListTile(
contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.system_update_outlined),
title: const Text('获取最新版本'),
subtitle: const Text('前往 GitHub Releases 下载最新 APK'),
trailing: const Icon(Icons.open_in_new, size: 18),
onTap: () => _open(Uri.parse(kReleaseUrl)),
),
// 「下载最新 APK」只对 Android 有意义:iOS 拿到的是装不了的文件
if (Platform.isAndroid)
ListTile(
contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.system_update_outlined),
title: const Text('获取最新版本'),
subtitle: const Text('前往 GitHub Releases 下载最新 APK'),
trailing: const Icon(Icons.open_in_new, size: 18),
onTap: () => _open(Uri.parse(kReleaseUrl)),
),
const SizedBox(height: 24),
Center(
child: Text(
Expand Down
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
app_settings:
dependency: "direct main"
description:
name: app_settings
sha256: "59752c97a49aa35ba0020b52df616a8db2ee13e50edc1647516659f01c198d86"
url: "https://pub.dev"
source: hosted
version: "9.0.1"
archive:
dependency: "direct main"
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dependencies:
saf: ^2.1.2
file_selector: ^1.1.0
fast_gbk: ^1.0.0
app_settings: ^9.0.1

dev_dependencies:
flutter_test:
Expand Down
Loading