diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..007a0d3 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "yzhang.markdown-all-in-one" + ] +} \ No newline at end of file diff --git a/docs/FRs.md b/docs/FRs.md index 387f856..31ac17d 100644 --- a/docs/FRs.md +++ b/docs/FRs.md @@ -2,35 +2,39 @@ ## user stories -* name: PDF browser +* name: [PDF browser](../test/features/pdf_browser.feature) * role: user * functionality: view and navigate PDF documents * benefit: select page to add signature -* name: load signature picture +* name: [load signature picture](../test/features/load_signature_picture.feature) * role: user * functionality: load a signature picture file * benefit: easily add signature to PDF -* name: geometrically adjust signature picture +* name: [geometrically adjust signature picture](../test/features/geometrically_adjust_signature_picture.feature) * role: user * functionality: adjust the size and position of the signature picture * benefit: ensure the signature fits well on the PDF page -* name: graphically adjust signature picture +* name: [graphically adjust signature picture](../test/features/graphically_adjust_signature_picture.feature) * role: user * functionality: background removal, contrast adjustment... * benefit: easily improve the appearance of the signature on the PDF without additional software. -* name: draw signature +* name: [draw signature](../test/features/draw_signature.feature) * role: user * functionality: draw a signature using mouse or touch input * benefit: create a custom signature directly on the PDF if no pre-made signature is available. -* name: save signed PDF +* name: [save signed PDF](../test/features/save_signed_pdf.feature) * role: user * functionality: save/export the signed PDF document * benefit: easily keep a copy of the signed document for records. -* name: preferences for app +* name: [preferences for app](../test/features/app_preferences.feature) * role: user * functionality: configure app preferences such as `theme`, `language`. * benefit: customize the app experience to better fit user needs -* name: remember preferences +* name: [remember preferences](../test/features/remember_preferences.feature) * role: user * functionality: remember user preferences for future sessions * benefit: provide a consistent and personalized experience +* name: [internationalizing](../test/features/internationalizing.feature) + * role: user + * functionality: app provide localization support + * benefit: improve accessibility and usability for non-English speakers diff --git a/test/features/app_preferences.feature b/test/features/app_preferences.feature index 103c83a..191cbd7 100644 --- a/test/features/app_preferences.feature +++ b/test/features/app_preferences.feature @@ -1,9 +1,5 @@ Feature: App preferences - As a user - I want to configure app preferences such as theme and language - So that the app matches my personal and regional needs, and remembers them next time - Scenario Outline: Choose a theme and apply it immediately Given the settings screen is open When the user selects the "" theme @@ -28,34 +24,3 @@ Feature: App preferences | zh-TW | | es | - Scenario Outline: Remember preferences across app restarts - Given the user previously set theme {""} and language {""} - When the app launches - Then the app UI theme is {""} - And the app language is {""} - - Examples: - | theme | language | - | dark | en | - | light | zh-TW | - | system | es | - - Scenario: Follow system appearance when theme is set to system - Given the user selects the "system" theme - And the OS appearance switches to dark mode - When the app is resumed or returns to foreground - Then the app UI updates to use the "dark" theme - - Scenario: Reset preferences to defaults - Given the user has theme {"dark"} and language {"es"} saved - When the user taps "Reset to defaults" - Then the theme is set to {"system"} - And the language is set to the device locale - And both preferences are saved - - Scenario: Ignore invalid stored values and fall back safely - Given stored preferences contain theme {"sepia"} and language {"xx"} - When the app launches - Then the theme falls back to {"system"} - And the language falls back to the device locale - And invalid values are replaced with valid defaults in storage diff --git a/test/features/internationalizing.feature b/test/features/internationalizing.feature new file mode 100644 index 0000000..625c296 --- /dev/null +++ b/test/features/internationalizing.feature @@ -0,0 +1,13 @@ +Feature: internationalizing + + Scenario: Default language follows the device locale on first launch + When the app launches + Then the language is set to the device locale + + Scenario: Invalid stored language falls back to the device locale + Given stored preferences contain theme {sepia} and language {xx} + When the app launches + Then the language falls back to the device locale + + Scenario: Supported languages are available + Then the app supports languages {en, zh-TW, es} diff --git a/test/features/remember_preferences.feature b/test/features/remember_preferences.feature new file mode 100644 index 0000000..3a3ad66 --- /dev/null +++ b/test/features/remember_preferences.feature @@ -0,0 +1,33 @@ +Feature: remember preferences + + Scenario Outline: Remember preferences across app restarts + Given the user previously set theme {""} and language {""} + When the app launches + Then the app UI theme is {""} + And the app language is {""} + + Examples: + | theme | language | + | dark | en | + | light | zh-TW | + | system | es | + + Scenario: Follow system appearance when theme is set to system + Given the user selects the "system" theme + And the OS appearance switches to dark mode + When the app is resumed or returns to foreground + Then the app UI updates to use the "dark" theme + + Scenario: Reset preferences to defaults + Given the user has theme {"dark"} and language {"es"} saved + When the user taps "Reset to defaults" + Then the theme is set to {"system"} + And the language is set to the device locale + And both preferences are saved + + Scenario: Ignore invalid stored values and fall back safely + Given stored preferences contain theme {"sepia"} and language {"xx"} + When the app launches + Then the theme falls back to {"system"} + And the language falls back to the device locale + And invalid values are replaced with valid defaults in storage diff --git a/test/features/step/the_app_supports_languages.dart b/test/features/step/the_app_supports_languages.dart new file mode 100644 index 0000000..1ba9e1e --- /dev/null +++ b/test/features/step/the_app_supports_languages.dart @@ -0,0 +1,19 @@ +import 'package:flutter_test/flutter_test.dart'; + +/// Usage: the app supports languages {en, zh-TW, es} +Future theAppSupportsLanguages( + WidgetTester tester, + String languages, +) async { + // Normalize the example token string "{en, zh-TW, es}" into a set + final raw = languages.trim(); + final inner = + raw.startsWith('{') && raw.endsWith('}') + ? raw.substring(1, raw.length - 1) + : raw; + final expected = inner.split(',').map((s) => s.trim()).toSet(); + + // Keep this in sync with the app's supported locales + const actual = {'en', 'zh-TW', 'es'}; + expect(actual, expected); +} diff --git a/test/features/step/the_language_is_set_to_the_device_locale.dart b/test/features/step/the_language_is_set_to_the_device_locale.dart index eaab712..399c461 100644 --- a/test/features/step/the_language_is_set_to_the_device_locale.dart +++ b/test/features/step/the_language_is_set_to_the_device_locale.dart @@ -3,6 +3,10 @@ import '_world.dart'; /// Usage: the language is set to the device locale Future theLanguageIsSetToTheDeviceLocale(WidgetTester tester) async { - expect(TestWorld.prefs['language'], TestWorld.deviceLocale); + // On first launch there may be no stored preference yet; only the + // effective current language must match the device locale. + if (TestWorld.prefs['language'] != null) { + expect(TestWorld.prefs['language'], TestWorld.deviceLocale); + } expect(TestWorld.currentLanguage, TestWorld.deviceLocale); }