mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 19:27:01 +01:00
Desktop: no stray browser window from extensions; keyboard stays down after backing out of a note
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file-length / file length <= 250 lines (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file-length / file length <= 250 lines (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
341a943277
commit
c71b98c08b
@ -29,8 +29,10 @@ echo "==> Compiling the desktop wrapper..."
|
|||||||
# `dart build cli`, not `dart compile exe`: the package pulls in dependencies
|
# `dart build cli`, not `dart compile exe`: the package pulls in dependencies
|
||||||
# with native build hooks (sqlite3, objective_c), which `dart compile` refuses
|
# with native build hooks (sqlite3, objective_c), which `dart compile` refuses
|
||||||
# to handle even though the wrapper itself uses none of them.
|
# to handle even though the wrapper itself uses none of them.
|
||||||
|
# --target is required since bin/ also holds the todo_note CLI: with two
|
||||||
|
# entry points `dart build cli` refuses to guess and the install aborts.
|
||||||
rm -rf "$SCRIPT_DIR/build/cli"
|
rm -rf "$SCRIPT_DIR/build/cli"
|
||||||
dart build cli -o "$SCRIPT_DIR/build/cli"
|
dart build cli -t "$SCRIPT_DIR/bin/todo_desktop.dart" -o "$SCRIPT_DIR/build/cli"
|
||||||
|
|
||||||
echo "==> Generating PKGBUILD..."
|
echo "==> Generating PKGBUILD..."
|
||||||
# pkgname is 'todo-flutter', NOT 'todo': the AUR already ships an unrelated
|
# pkgname is 'todo-flutter', NOT 'todo': the AUR already ships an unrelated
|
||||||
|
|||||||
@ -59,6 +59,11 @@ List<String> browserArgs(String home) => [
|
|||||||
// blank grey. Nothing in this profile needs OS-level encryption (the
|
// blank grey. Nothing in this profile needs OS-level encryption (the
|
||||||
// GitHub token is in localStorage, not the password store).
|
// GitHub token is in localStorage, not the password store).
|
||||||
'--password-store=basic',
|
'--password-store=basic',
|
||||||
|
// The distro wrapper appends ~/.config/chromium-flags.conf to every launch,
|
||||||
|
// which here carries `--load-extension` for Claude in Chrome. Logged out in
|
||||||
|
// this profile, it opened a claude.ai login tab in a second, normal browser
|
||||||
|
// window on every start. This flag also drops command-line extensions.
|
||||||
|
'--disable-extensions',
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Launches the app in a Chrome-family browser with a **stable** profile
|
/// Launches the app in a Chrome-family browser with a **stable** profile
|
||||||
|
|||||||
@ -20,6 +20,9 @@ Future<void> openNote(
|
|||||||
NoteRepository repository,
|
NoteRepository repository,
|
||||||
ValueNotifier<AppSettings> appSettings,
|
ValueNotifier<AppSettings> appSettings,
|
||||||
) async {
|
) async {
|
||||||
|
// Drop the search box's focus first: a route remembers its focused field and
|
||||||
|
// re-focuses it on return, so backing out of a note would pop the keyboard.
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
await Navigator.of(context).push<void>(
|
await Navigator.of(context).push<void>(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => NoteDetailScreen(
|
builder: (_) => NoteDetailScreen(
|
||||||
|
|||||||
@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.45+1
|
version: 1.0.46+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.12.2
|
sdk: ^3.12.2
|
||||||
|
|||||||
@ -19,6 +19,10 @@ void main() {
|
|||||||
test('keeps Chrome off the keyring, whose lock blanks the window', () {
|
test('keeps Chrome off the keyring, whose lock blanks the window', () {
|
||||||
expect(args, contains('--password-store=basic'));
|
expect(args, contains('--password-store=basic'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('loads no extension, so none can open a second browser window', () {
|
||||||
|
expect(args, contains('--disable-extensions'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('findBrowser', () {
|
group('findBrowser', () {
|
||||||
|
|||||||
54
test/notes_list_focus_test.dart
Normal file
54
test/notes_list_focus_test.dart
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:todo/ui/note_detail_screen.dart';
|
||||||
|
|
||||||
|
import 'notes_list_harness.dart';
|
||||||
|
|
||||||
|
/// Whether any text field holds focus, i.e. Android would show the keyboard.
|
||||||
|
bool textFieldFocused() =>
|
||||||
|
FocusManager.instance.primaryFocus?.context
|
||||||
|
?.findAncestorWidgetOfExactType<EditableText>() !=
|
||||||
|
null;
|
||||||
|
|
||||||
|
/// Opens the first note, types into its editor, then backs out the way the
|
||||||
|
/// Android back swipe does (a system pop, not the app-bar arrow).
|
||||||
|
Future<void> editNoteAndSwipeBack(WidgetTester tester) async {
|
||||||
|
await tester.tap(find.text('Buy milk'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500));
|
||||||
|
await tester.tap(
|
||||||
|
find
|
||||||
|
.descendant(
|
||||||
|
of: find.byType(NoteDetailScreen),
|
||||||
|
matching: find.byType(EditableText),
|
||||||
|
)
|
||||||
|
.first,
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
expect(textFieldFocused(), isTrue);
|
||||||
|
await tester.binding.handlePopRoute();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('backing out of a note leaves no text field focused', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
await pumpList(tester, seed: [note('a', 'Buy milk')]);
|
||||||
|
await editNoteAndSwipeBack(tester);
|
||||||
|
expect(find.text('Search notes…'), findsOneWidget);
|
||||||
|
expect(textFieldFocused(), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('backing out does not re-focus a search box used earlier', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
await pumpList(tester, seed: [note('a', 'Buy milk')]);
|
||||||
|
await tester.tap(find.byType(TextField).first);
|
||||||
|
await tester.pump();
|
||||||
|
await editNoteAndSwipeBack(tester);
|
||||||
|
expect(find.text('Search notes…'), findsOneWidget);
|
||||||
|
expect(textFieldFocused(), isFalse);
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user