Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -53,3 +53,9 @@ repos:
|
|||||||
entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && nix develop --command task check-ci-images'
|
entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && nix develop --command task check-ci-images'
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
files: ^(ci/main\.go|\.fvmrc)$
|
files: ^(ci/main\.go|\.fvmrc)$
|
||||||
|
- id: dagger-versions-aligned
|
||||||
|
name: verify Dagger version is consistent across dagger.json, flake.nix, Dockerfile and DAGGER.md
|
||||||
|
language: system
|
||||||
|
entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && scripts/check_dagger_versions.sh'
|
||||||
|
pass_filenames: false
|
||||||
|
files: ^(ci/dagger\.json|flake\.nix|\.forgejo/Dockerfile|DAGGER\.md)$
|
||||||
|
|||||||
@@ -712,6 +712,11 @@ tasks:
|
|||||||
cmds:
|
cmds:
|
||||||
- scripts/check_ci_images.sh
|
- scripts/check_ci_images.sh
|
||||||
|
|
||||||
|
check-dagger-versions:
|
||||||
|
desc: Verify ci/dagger.json, flake.nix, .forgejo/Dockerfile and DAGGER.md pin the same Dagger version
|
||||||
|
cmds:
|
||||||
|
- scripts/check_dagger_versions.sh
|
||||||
|
|
||||||
_integrations:
|
_integrations:
|
||||||
internal: true
|
internal: true
|
||||||
run: once
|
run: once
|
||||||
|
|||||||
@@ -49,14 +49,16 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# The dagger/nix flake pins 0.20.8, whose Nix wrapper is a broken self-exec
|
# The dagger/nix flake's Nix wrapper is a broken self-exec loop, so we
|
||||||
# loop. Fetch 0.21.4 directly so the pre-commit dart-check hook can run.
|
# fetch the CLI binary directly. Keep this version in lockstep with
|
||||||
dagger021 = pkgs.stdenv.mkDerivation {
|
# ci/dagger.json (engineVersion) and .forgejo/Dockerfile (DAGGER_VERSION) —
|
||||||
|
# scripts/check_dagger_versions.sh enforces this.
|
||||||
|
daggerCli = pkgs.stdenv.mkDerivation {
|
||||||
pname = "dagger";
|
pname = "dagger";
|
||||||
version = "0.21.4";
|
version = "0.20.8";
|
||||||
src = pkgs.fetchurl {
|
src = pkgs.fetchurl {
|
||||||
url = "https://dl.dagger.io/dagger/releases/0.21.4/dagger_v0.21.4_linux_amd64.tar.gz";
|
url = "https://dl.dagger.io/dagger/releases/0.20.8/dagger_v0.20.8_linux_amd64.tar.gz";
|
||||||
sha256 = "0wlnbr4g5069755131yjp2a6alacn64f1c8b27xn0cbynq3zicjd";
|
sha256 = "1ns6wq2z1skd2fq9lbrcali0s8kn24p3haamnjjgchg6zlv6b960";
|
||||||
};
|
};
|
||||||
sourceRoot = ".";
|
sourceRoot = ".";
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
@@ -69,7 +71,7 @@
|
|||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
# Dagger CLI
|
# Dagger CLI
|
||||||
dagger021
|
daggerCli
|
||||||
|
|
||||||
# Go compiler — for Dagger development
|
# Go compiler — for Dagger development
|
||||||
go
|
go
|
||||||
|
|||||||
@@ -74,10 +74,6 @@ class _EmailDetailScreenState extends ConsumerState<EmailDetailScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: !isMobile,
|
automaticallyImplyLeading: !isMobile,
|
||||||
title: Text(
|
|
||||||
header?.subject ?? '(loading…)',
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.reply),
|
icon: const Icon(Icons.reply),
|
||||||
@@ -133,12 +129,20 @@ class _EmailDetailScreenState extends ConsumerState<EmailDetailScreen> {
|
|||||||
if (mounted) setState(() => _isFlagged = next);
|
if (mounted) setState(() => _isFlagged = next);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.report_outlined),
|
||||||
|
tooltip: 'Mark as spam',
|
||||||
|
onPressed: header == null
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
unawaited(_markAsSpam(context, header));
|
||||||
|
},
|
||||||
|
),
|
||||||
PopupMenuButton<String>(
|
PopupMenuButton<String>(
|
||||||
itemBuilder: (ctx) => [
|
itemBuilder: (ctx) => [
|
||||||
const PopupMenuItem(value: 'forward', child: Text('Forward')),
|
const PopupMenuItem(value: 'forward', child: Text('Forward')),
|
||||||
const PopupMenuItem(value: 'move', child: Text('Move to folder')),
|
const PopupMenuItem(value: 'move', child: Text('Move to folder')),
|
||||||
const PopupMenuItem(value: 'snooze', child: Text('Snooze')),
|
const PopupMenuItem(value: 'snooze', child: Text('Snooze')),
|
||||||
const PopupMenuItem(value: 'spam', child: Text('Mark as spam')),
|
|
||||||
const PopupMenuItem(
|
const PopupMenuItem(
|
||||||
value: 'mark_unread',
|
value: 'mark_unread',
|
||||||
child: Text('Mark as unread'),
|
child: Text('Mark as unread'),
|
||||||
@@ -166,8 +170,6 @@ class _EmailDetailScreenState extends ConsumerState<EmailDetailScreen> {
|
|||||||
unawaited(_moveTo(context, header));
|
unawaited(_moveTo(context, header));
|
||||||
} else if (value == 'snooze' && header != null) {
|
} else if (value == 'snooze' && header != null) {
|
||||||
unawaited(_snooze(context, header));
|
unawaited(_snooze(context, header));
|
||||||
} else if (value == 'spam' && header != null) {
|
|
||||||
unawaited(_markAsSpam(context, header));
|
|
||||||
} else if (value == 'mark_unread') {
|
} else if (value == 'mark_unread') {
|
||||||
final nextEmailId = await _getNextEmailIdIfNeeded(header);
|
final nextEmailId = await _getNextEmailIdIfNeeded(header);
|
||||||
await repo.setFlag(widget.emailId, seen: false);
|
await repo.setFlag(widget.emailId, seen: false);
|
||||||
|
|||||||
+59
-51
@@ -5,18 +5,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
|
sha256: a49d6cf99e8d8e7a8e93668d09ced0bbdb954d0b4fccc2f5f9241c6b87fad95c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "93.0.0"
|
version: "99.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
|
sha256: "663efa951fb8a45e06f491223a604c93820598f20e6a99c25617a1576065e8b7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.1"
|
version: "12.1.0"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -165,10 +165,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_assets
|
name: code_assets
|
||||||
sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687"
|
sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.2.1"
|
||||||
code_builder:
|
code_builder:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -237,18 +237,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2"
|
sha256: a4c1ccfee44c7e75ed80484071a5c142a385345e658fd8bd7c4b5c97e7198f98
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.7"
|
version: "3.1.8"
|
||||||
dbus:
|
dbus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dbus
|
name: dbus
|
||||||
sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270
|
sha256: "0ce9b0a839e6dee59a37a623d2fc26a35bbbe6404213e419b0d6411023d62645"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.12"
|
version: "0.7.14"
|
||||||
device_info_plus:
|
device_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -349,10 +349,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "0204695694b687b167fd497da5252e9f4aaa162e8d274d6fa1e757380f2a5f46"
|
sha256: fc83774ce5bd7ce08168333b5e53dbe9090ec04eb21e7aa7cd7bac921032c934
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "12.0.0-beta.4"
|
version: "12.0.0-beta.5"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -391,34 +391,42 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications
|
name: flutter_local_notifications
|
||||||
sha256: "0d9035862236fe38250fe1644d7ed3b8254e34a21b2c837c9f539fbb3bba5ef1"
|
sha256: be38e3854d2baabcda8e16966a5fe8748cebb655bb94701494da0f052c2fc352
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "21.0.0"
|
version: "22.0.0"
|
||||||
flutter_local_notifications_linux:
|
flutter_local_notifications_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications_linux
|
name: flutter_local_notifications_linux
|
||||||
sha256: e0f25e243c6c44c825bbbc6b2b2e76f7d9222362adcfe9fd780bf01923c840bd
|
sha256: "9ca97e63776f29ab1b955725c09999fc2c150523269db150c39274f2a43c5a8b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.0"
|
version: "8.0.1"
|
||||||
flutter_local_notifications_platform_interface:
|
flutter_local_notifications_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications_platform_interface
|
name: flutter_local_notifications_platform_interface
|
||||||
sha256: e7db3d5b49c2b7ecc68deba4aaaa67a348f92ee0fef34c8e4b4459dbef0d7307
|
sha256: ff0013eae795e8dc8fad4a8992a209e64d3ba2fbd8bf5e43c36bf448f95bd814
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.0"
|
version: "12.0.0"
|
||||||
|
flutter_local_notifications_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_web
|
||||||
|
sha256: "516afaf97a2d1e67a036c6617321b00d205d72f7a67b6eccf936cd565f985878"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
flutter_local_notifications_windows:
|
flutter_local_notifications_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications_windows
|
name: flutter_local_notifications_windows
|
||||||
sha256: "3a2654ba104fbb52c618ebed9def24ef270228470718c43b3a6afcd5c81bef0c"
|
sha256: "5aeed973a0c1480706784fad05c5c3a911335ebb561b2274b47fe80b375201e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.1.0"
|
||||||
flutter_markdown_plus:
|
flutter_markdown_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -431,10 +439,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0"
|
sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.34"
|
version: "2.0.35"
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -447,10 +455,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage
|
name: flutter_secure_storage
|
||||||
sha256: d2a6ac2df7353f5ca47eb159a5407c1dba7ec48ca0e02dc38c9ff4d29447b261
|
sha256: "7686b1d6a29985dcbb808c59518226e603e3bfa7c0ddfd1a0d00e4cda77c868e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.3.0"
|
version: "10.3.1"
|
||||||
flutter_secure_storage_darwin:
|
flutter_secure_storage_darwin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -526,10 +534,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: "92d8cee7c57dff0a6c409c05597b460002434eccf7424a712283225b3962d03f"
|
sha256: "5922b2861e2235a3504896f0d6fa07d84141b480cf52eecd2f42cd25585a9e8a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "17.2.3"
|
version: "17.3.0"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -542,10 +550,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hooks
|
name: hooks
|
||||||
sha256: "025f060e86d2d4c3c47b56e33caf7f93bf9283340f26d23424ebcfccf34f621e"
|
sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.3"
|
version: "2.0.2"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -675,10 +683,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -707,10 +715,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: native_toolchain_c
|
name: native_toolchain_c
|
||||||
sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572"
|
sha256: f59351d28f49520cd3a74eb1f41c5f19ae15e53c65a3231d14af672e46510a96
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.17.6"
|
version: "0.19.1"
|
||||||
node_preamble:
|
node_preamble:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -723,10 +731,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: objective_c
|
name: objective_c
|
||||||
sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52"
|
sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.3.0"
|
version: "9.4.1"
|
||||||
open_filex:
|
open_filex:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1013,13 +1021,13 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.2"
|
version: "1.10.2"
|
||||||
sqlite3:
|
sqlite3:
|
||||||
dependency: "direct dev"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
sha256: "56da3e13ed7d28a66f930aa2b2b29db6736a233f08283326e96321dd812030f5"
|
sha256: "9488c7d2cdb1091c91cacf7e207cff81b28bff8e366f042bad3afe7d34afe189"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.1"
|
version: "3.3.2"
|
||||||
sqlite3_flutter_libs:
|
sqlite3_flutter_libs:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1088,10 +1096,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: synchronized
|
name: synchronized
|
||||||
sha256: "63896c27e81b28f8cb4e69ead0d3e8f03f1d1e5fc531a3e579cabed6a2c7c9e5"
|
sha256: "93b153dcb6a26dcddee6ca087dd634b53e38c10b5aa163e8e49501a776456153"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.0+1"
|
version: "3.4.1"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1104,26 +1112,26 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
|
sha256: "8d9ceddbab833f180fbefed08afa76d7c03513dfdba87ffcec2718b02bbcbf20"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.30.0"
|
version: "1.31.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
|
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.16"
|
version: "0.6.17"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1288,10 +1296,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_android
|
name: webview_flutter_android
|
||||||
sha256: ad5182eff9a550925330cb9f0cb038eddfdd5712aba8b77aa0f0400e50f6e688
|
sha256: a97db7a44f8e71af2f3971c45550a08cce1fb60059c1b8e534251e6cfb753490
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.12.0"
|
version: "4.13.0"
|
||||||
webview_flutter_platform_interface:
|
webview_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1304,10 +1312,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: "82648217f537573e1ca9ae9952d3eacedca6ab5aee69dc84445fc763766dcea2"
|
sha256: c879dd64b87c452aa84381b244d5469da57ba7e8cca6884c7b1e0d406372c12d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.25.1"
|
version: "3.26.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1381,5 +1389,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.11.0 <4.0.0"
|
dart: ">=3.12.0 <4.0.0"
|
||||||
flutter: ">=3.38.4"
|
flutter: ">=3.44.0"
|
||||||
|
|||||||
+3
-3
@@ -28,7 +28,7 @@ dependencies:
|
|||||||
flutter_riverpod: ^3.0.0
|
flutter_riverpod: ^3.0.0
|
||||||
|
|
||||||
# Navigation
|
# Navigation
|
||||||
go_router: ^17.2.3
|
go_router: ^17.3.0
|
||||||
|
|
||||||
# Secure credential storage (passwords)
|
# Secure credential storage (passwords)
|
||||||
flutter_secure_storage: ^10.0.0
|
flutter_secure_storage: ^10.0.0
|
||||||
@@ -37,7 +37,7 @@ dependencies:
|
|||||||
intl: ^0.20.2
|
intl: ^0.20.2
|
||||||
|
|
||||||
# File picking (compose attachments) and opening downloaded attachments
|
# File picking (compose attachments) and opening downloaded attachments
|
||||||
file_picker: ^12.0.0-beta.4
|
file_picker: ^12.0.0-beta.5
|
||||||
open_filex: ^4.6.0
|
open_filex: ^4.6.0
|
||||||
mime: ^2.0.0
|
mime: ^2.0.0
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ dependencies:
|
|||||||
flutter_markdown_plus: ^1.0.7
|
flutter_markdown_plus: ^1.0.7
|
||||||
|
|
||||||
# Background sync and local notifications
|
# Background sync and local notifications
|
||||||
flutter_local_notifications: ^21.0.0
|
flutter_local_notifications: ^22.0.0
|
||||||
workmanager: ^0.9.0
|
workmanager: ^0.9.0
|
||||||
|
|
||||||
# Stack trace chain-to-VM conversion for FlutterError.demangleStackTrace
|
# Stack trace chain-to-VM conversion for FlutterError.demangleStackTrace
|
||||||
|
|||||||
Executable
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Verify that the Dagger version is consistent across the project.
|
||||||
|
#
|
||||||
|
# The Dagger CLI must speak the same protocol as the engine it talks to. We
|
||||||
|
# pin the version in four places (engine image in DAGGER.md, the CLI in
|
||||||
|
# flake.nix, the CLI in the Forgejo runner Dockerfile, and the module
|
||||||
|
# engineVersion in ci/dagger.json). This script fails if any of them drift.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(git rev-parse --show-toplevel)
|
||||||
|
|
||||||
|
# ci/dagger.json — strip leading "v" for comparison.
|
||||||
|
dagger_json=$(grep -oE '"engineVersion"[[:space:]]*:[[:space:]]*"[^"]+"' "$ROOT/ci/dagger.json" \
|
||||||
|
| sed -E 's/.*"v?([^"]+)"$/\1/')
|
||||||
|
|
||||||
|
# flake.nix — the dagger021 derivation's CLI download URL.
|
||||||
|
flake_nix=$(grep -oE 'dagger_v[0-9]+\.[0-9]+\.[0-9]+_linux' "$ROOT/flake.nix" \
|
||||||
|
| head -n1 \
|
||||||
|
| sed -E 's/dagger_v([0-9.]+)_linux/\1/')
|
||||||
|
|
||||||
|
# .forgejo/Dockerfile — DAGGER_VERSION env on the install line.
|
||||||
|
dockerfile=$(grep -oE 'DAGGER_VERSION=[0-9]+\.[0-9]+\.[0-9]+' "$ROOT/.forgejo/Dockerfile" \
|
||||||
|
| head -n1 \
|
||||||
|
| cut -d= -f2)
|
||||||
|
|
||||||
|
# DAGGER.md — engine image tag in the example systemd unit.
|
||||||
|
dagger_md=$(grep -oE 'dagger/nix/v[0-9]+\.[0-9]+\.[0-9]+' "$ROOT/DAGGER.md" \
|
||||||
|
| head -n1 \
|
||||||
|
| sed -E 's@.*/v@@')
|
||||||
|
|
||||||
|
printf 'ci/dagger.json engineVersion = v%s\n' "$dagger_json"
|
||||||
|
printf 'flake.nix dagger021 = %s\n' "$flake_nix"
|
||||||
|
printf '.forgejo/Dockerf. DAGGER_VERSION= %s\n' "$dockerfile"
|
||||||
|
printf 'DAGGER.md engine tag = v%s\n' "$dagger_md"
|
||||||
|
|
||||||
|
for v in "$flake_nix" "$dockerfile" "$dagger_md"; do
|
||||||
|
if [ -z "$v" ]; then
|
||||||
|
echo "ERROR: failed to parse a Dagger version reference." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$v" != "$dagger_json" ]; then
|
||||||
|
echo "" >&2
|
||||||
|
echo "ERROR: Dagger versions are out of sync." >&2
|
||||||
|
echo " Align ci/dagger.json, flake.nix, .forgejo/Dockerfile and DAGGER.md to the same version." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Dagger versions aligned (v$dagger_json)."
|
||||||
@@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:http/testing.dart';
|
import 'package:http/testing.dart';
|
||||||
|
|
||||||
|
import 'package:sharedinbox/core/filter/filter_expression.dart';
|
||||||
import 'package:sharedinbox/core/models/account.dart';
|
import 'package:sharedinbox/core/models/account.dart';
|
||||||
import 'package:sharedinbox/core/models/email.dart';
|
import 'package:sharedinbox/core/models/email.dart';
|
||||||
import 'package:sharedinbox/data/db/database.dart' hide Account;
|
import 'package:sharedinbox/data/db/database.dart' hide Account;
|
||||||
@@ -682,6 +683,91 @@ void main() {
|
|||||||
expect(results[1].subject, 'Older meeting');
|
expect(results[1].subject, 'Older meeting');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'searchEmailsStructured returns results sorted by receivedAt descending',
|
||||||
|
() async {
|
||||||
|
final r = _makeRepos();
|
||||||
|
await r.accounts.addAccount(_account, 'pw');
|
||||||
|
|
||||||
|
await r.db.into(r.db.emails).insert(
|
||||||
|
EmailsCompanion.insert(
|
||||||
|
id: 'acc-1:1',
|
||||||
|
accountId: 'acc-1',
|
||||||
|
mailboxPath: 'INBOX',
|
||||||
|
uid: 1,
|
||||||
|
subject: const Value('Older invoice'),
|
||||||
|
receivedAt: DateTime(2024),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await r.db.into(r.db.emails).insert(
|
||||||
|
EmailsCompanion.insert(
|
||||||
|
id: 'acc-1:2',
|
||||||
|
accountId: 'acc-1',
|
||||||
|
mailboxPath: 'INBOX',
|
||||||
|
uid: 2,
|
||||||
|
subject: const Value('Newer invoice'),
|
||||||
|
receivedAt: DateTime(2024, 6),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final filter = FilterGroup(
|
||||||
|
operator: FilterOperator.and_,
|
||||||
|
children: [
|
||||||
|
FilterLeaf(
|
||||||
|
field: FilterField.subject,
|
||||||
|
comparison: FilterComparison.contains,
|
||||||
|
value: 'invoice',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final results = await r.emails.searchEmailsStructured(null, filter);
|
||||||
|
expect(results, hasLength(2));
|
||||||
|
expect(results[0].subject, 'Newer invoice');
|
||||||
|
expect(results[1].subject, 'Older invoice');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'getEmailsByAddress returns results sorted by receivedAt descending',
|
||||||
|
() async {
|
||||||
|
final r = _makeRepos();
|
||||||
|
await r.accounts.addAccount(_account, 'pw');
|
||||||
|
|
||||||
|
await r.db.into(r.db.emails).insert(
|
||||||
|
EmailsCompanion.insert(
|
||||||
|
id: 'acc-1:1',
|
||||||
|
accountId: 'acc-1',
|
||||||
|
mailboxPath: 'INBOX',
|
||||||
|
uid: 1,
|
||||||
|
subject: const Value('Older hello'),
|
||||||
|
receivedAt: DateTime(2024),
|
||||||
|
fromJson: const Value(
|
||||||
|
'[{"name":"Bob","email":"bob@example.com"}]',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await r.db.into(r.db.emails).insert(
|
||||||
|
EmailsCompanion.insert(
|
||||||
|
id: 'acc-1:2',
|
||||||
|
accountId: 'acc-1',
|
||||||
|
mailboxPath: 'INBOX',
|
||||||
|
uid: 2,
|
||||||
|
subject: const Value('Newer hello'),
|
||||||
|
receivedAt: DateTime(2024, 6),
|
||||||
|
fromJson: const Value(
|
||||||
|
'[{"name":"Bob","email":"bob@example.com"}]',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final results =
|
||||||
|
await r.emails.getEmailsByAddress(null, 'bob@example.com');
|
||||||
|
expect(results, hasLength(2));
|
||||||
|
expect(results[0].subject, 'Newer hello');
|
||||||
|
expect(results[1].subject, 'Older hello');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'searchAddresses returns results sorted by most recently used',
|
'searchAddresses returns results sorted by most recently used',
|
||||||
() async {
|
() async {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ void main() {
|
|||||||
expect(find.byType(CircularProgressIndicator), findsOneWidget);
|
expect(find.byType(CircularProgressIndicator), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('shows subject in app bar after data loads', (tester) async {
|
testWidgets('shows subject in email header section', (tester) async {
|
||||||
final email = testEmail(subject: 'Project update');
|
final email = testEmail(subject: 'Project update');
|
||||||
const body = EmailBody(
|
const body = EmailBody(
|
||||||
emailId: 'acc-1:42',
|
emailId: 'acc-1:42',
|
||||||
@@ -106,8 +106,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// Subject appears in both the app bar and the email header section.
|
// Subject appears only in the email header section, not in the app bar.
|
||||||
expect(find.text('Project update'), findsAtLeastNWidgets(1));
|
expect(find.text('Project update'), findsOneWidget);
|
||||||
expect(find.text('See attached slides.'), findsOneWidget);
|
expect(find.text('See attached slides.'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ void main() {
|
|||||||
expect(find.textContaining('carol@example.com'), findsAtLeastNWidgets(1));
|
expect(find.textContaining('carol@example.com'), findsAtLeastNWidgets(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Mark as spam is in popup menu, not a standalone button', (
|
testWidgets('Mark as spam is a standalone button, not in popup menu', (
|
||||||
tester,
|
tester,
|
||||||
) async {
|
) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@@ -279,19 +279,19 @@ void main() {
|
|||||||
);
|
);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// No standalone icon button for mark as spam.
|
// Standalone icon button for mark as spam is in the app bar.
|
||||||
expect(
|
expect(
|
||||||
find.byWidgetPredicate(
|
find.byWidgetPredicate(
|
||||||
(w) => w is Tooltip && w.message == 'Mark as spam',
|
(w) => w is Tooltip && w.message == 'Mark as spam',
|
||||||
),
|
),
|
||||||
findsNothing,
|
findsOneWidget,
|
||||||
);
|
);
|
||||||
|
|
||||||
// It appears in the popup menu.
|
// It does NOT appear in the popup menu.
|
||||||
await tester.tap(find.byType(PopupMenuButton<String>));
|
await tester.tap(find.byType(PopupMenuButton<String>));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.text('Mark as spam'), findsOneWidget);
|
expect(find.text('Mark as spam'), findsNothing);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Mark as spam shows dialog when no junk folder', (
|
testWidgets('Mark as spam shows dialog when no junk folder', (
|
||||||
@@ -309,11 +309,11 @@ void main() {
|
|||||||
);
|
);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// Open the popup menu first, then tap Mark as spam.
|
await tester.tap(
|
||||||
await tester.tap(find.byType(PopupMenuButton<String>));
|
find.byWidgetPredicate(
|
||||||
await tester.pumpAndSettle();
|
(w) => w is Tooltip && w.message == 'Mark as spam',
|
||||||
|
),
|
||||||
await tester.tap(find.text('Mark as spam'));
|
);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.text('No spam folder found'), findsOneWidget);
|
expect(find.text('No spam folder found'), findsOneWidget);
|
||||||
|
|||||||
@@ -446,10 +446,10 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(EmailDetailScreen), findsOneWidget);
|
expect(find.byType(EmailDetailScreen), findsOneWidget);
|
||||||
// The detail AppBar title shows the first email's subject.
|
// The detail body header shows the first email's subject.
|
||||||
expect(
|
expect(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
of: find.byType(AppBar),
|
of: find.byType(EmailDetailScreen),
|
||||||
matching: find.text('Alpha Match'),
|
matching: find.text('Alpha Match'),
|
||||||
),
|
),
|
||||||
findsOneWidget,
|
findsOneWidget,
|
||||||
|
|||||||
Reference in New Issue
Block a user