From 3017153098794f35d57e6b7422db30ca8bc34c29 Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Mon, 23 Mar 2026 12:28:37 -0300 Subject: [PATCH 01/12] consolidate versions --- pubspec.lock | 300 ++++++++++++++++++++++----------------------------- pubspec.yaml | 17 +-- 2 files changed, 139 insertions(+), 178 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index c160c4e..439045c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,42 +5,42 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e" + sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d url: "https://pub.dev" source: hosted - version: "92.0.0" + version: "91.0.0" analysis_server_plugin: dependency: transitive description: name: analysis_server_plugin - sha256: "44adba4d74a2541173bad4c11531d2a4d22810c29c5ddb458a38e9f4d0e5eac7" + sha256: "26844e7f977087567135d62532b67d5639fe206c5194c3f410ba75e1a04a2747" url: "https://pub.dev" source: hosted - version: "0.3.4" + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e" + sha256: a40a0cee526a7e1f387c6847bd8a5ccbf510a75952ef8a28338e989558072cb0 url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "8.4.0" analyzer_buffer: dependency: transitive description: name: analyzer_buffer - sha256: ff4bd291778c7417fe53fe24ee0d0a1f1ffe281a2d4ea887e7094f16e36eace7 + sha256: aba2f75e63b3135fd1efaa8b6abefe1aa6e41b6bd9806221620fa48f98156033 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.1.11" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "6645a029da947ffd823d98118f385d4bd26b54eb069c006b22e0b94e451814b5" + sha256: "08cfefa90b4f4dd3b447bda831cecf644029f9f8e22820f6ee310213ebe2dd53" url: "https://pub.dev" source: hosted - version: "0.13.11" + version: "0.13.10" archive: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: async - sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.13.1" + version: "2.13.0" boolean_selector: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: build - sha256: aadd943f4f8cc946882c954c187e6115a84c98c81ad1d9c6cbf0895a8c85da9c + sha256: "275bf6bb2a00a9852c28d4e0b410da1d833a734d57d39d44f94bfc895a484ec3" url: "https://pub.dev" source: hosted - version: "4.0.5" + version: "4.0.4" characters: dependency: transitive description: @@ -89,6 +89,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" cli_config: dependency: transitive description: @@ -97,22 +113,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" - clock: + cli_util: dependency: transitive description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "1.1.2" - code_assets: + version: "0.4.2" + clock: dependency: transitive description: - name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.2" collection: dependency: transitive description: @@ -161,6 +177,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + custom_lint: + dependency: "direct dev" + description: + name: custom_lint + sha256: "751ee9440920f808266c3ec2553420dea56d3c7837dd2d62af76b11be3fcece5" + url: "https://pub.dev" + source: hosted + version: "0.8.1" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: "85b339346154d5646952d44d682965dfe9e12cae5febd706f0db3aa5010d6423" + url: "https://pub.dev" + source: hosted + version: "0.8.1" + custom_lint_visitor: + dependency: transitive + description: + name: custom_lint_visitor + sha256: "91f2a81e9f0abb4b9f3bb529f78b6227ce6050300d1ae5b1e2c69c66c7a566d8" + url: "https://pub.dev" + source: hosted + version: "1.0.0+8.4.0" dart_style: dependency: transitive description: @@ -173,26 +213,26 @@ packages: dependency: "direct main" description: name: dio - sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c + sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25 url: "https://pub.dev" source: hosted - version: "5.9.2" + version: "5.9.1" dio_web_adapter: dependency: transitive description: name: dio_web_adapter - sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" + sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" download_assets: dependency: "direct main" description: name: download_assets - sha256: ab479ef705819783af9c2a53de9c033ac7f621677f250ad0d63728f260d16585 + sha256: ecc0e9f644f1c57e5ba8c723b05e69ace7fd6177f34eebcadc496b7d410e6c4d url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.0.0" fake_async: dependency: transitive description: @@ -209,14 +249,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" - ffi_leak_tracker: - dependency: transitive - description: - name: ffi_leak_tracker - sha256: "25a58eeab3f50c90b5c8ee734a816af8021777246e3272db296d1d724cc63188" - url: "https://pub.dev" - source: hosted - version: "0.1.1" file: dependency: "direct main" description: @@ -308,10 +340,10 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: "4e166be88e1dbbaa34a280bdb744aeae73b7ef25fdf8db7a3bb776760a3648e2" + sha256: "38ec6c303e2c83ee84512f5fc2a82ae311531021938e63d7137eccc107bf3c02" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -359,14 +391,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" - hooks: - dependency: transitive - description: - name: hooks - sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 - url: "https://pub.dev" - source: hosted - version: "1.0.2" html: dependency: "direct main" description: @@ -399,14 +423,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" - idb_shim: - dependency: transitive - description: - name: idb_shim - sha256: "6cd94b71a33f1223b01ea2b359c3a6fde5980872b23b31d176a64c74d4dede57" - url: "https://pub.dev" - source: hosted - version: "2.8.5+2" integration_test: dependency: "direct dev" description: flutter @@ -428,22 +444,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" - jni: - dependency: transitive - description: - name: jni - sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f - url: "https://pub.dev" - source: hosted - version: "1.0.0" - jni_flutter: - dependency: transitive - description: - name: jni_flutter - sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" json_annotation: dependency: transitive description: @@ -512,10 +512,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.18" material_color_utilities: dependency: transitive description: @@ -544,18 +544,10 @@ packages: dependency: "direct main" description: name: mocktail - sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" url: "https://pub.dev" source: hosted - version: "0.17.6" + version: "1.0.4" node_preamble: dependency: transitive description: @@ -564,14 +556,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" - source: hosted - version: "9.3.0" open_filex: dependency: "direct main" description: @@ -592,18 +576,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: c2a4a9404e578d7c69e3cf19f0b057d906bd0b073deedc8006db997a8bfe97ca + sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "9.0.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "063b21cce7a2e3d902897d6cefc3bd211bb8ea42190698be72219cd5017f1c65" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "3.2.1" path: dependency: "direct main" description: @@ -624,18 +608,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" + sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.2.22" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.5.1" path_provider_linux: dependency: transitive description: @@ -708,6 +692,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" quiver: dependency: transitive description: @@ -720,66 +712,66 @@ packages: dependency: "direct main" description: name: riverpod - sha256: "8c22216be8ad3ef2b44af3a329693558c98eca7b8bd4ef495c92db0bba279f83" + sha256: "16ff608d21e8ea64364f2b7c049c94a02ab81668f78845862b6e88b71dd4935a" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.1.0" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: e55bc08c084a424e1bbdc303fe8ea75daafe4269b68fd0e0f6f1678413715b66 + sha256: "947b05d04c52a546a2ac6b19ef2a54b08520ff6bdf9f23d67957a4c8df1c3bc0" url: "https://pub.dev" source: hosted - version: "1.0.0-dev.9" + version: "1.0.0-dev.8" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: "64e8debf5b719a37d48b9785dd595d34133fdcd84b8fd07157a621c54ab2156f" + sha256: "4d2eb0d19bbe7e3323bd0ce4553b2e6170d161a13914bfdd85a3612329edcb43" url: "https://pub.dev" source: hosted - version: "3.1.3" - sembast: + version: "3.1.0" + rxdart: dependency: transitive description: - name: sembast - sha256: "139cf71496105de32e7a08a4e3a1ead0f81c4a616ec9703ed07e8f0d10cdd505" + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" url: "https://pub.dev" source: hosted - version: "3.8.6" + version: "0.28.0" share_plus: dependency: "direct main" description: name: share_plus - sha256: ad3e91cabb7dc3c7687e0f4bdaf24fb192141d11bfbf9ddea7c26f3d4e8bfb5d + sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "12.0.1" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: ccf360f79b95993b083259d8f37baf20a47bcf8e2551ccebdc4f781b4d15e734 + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "6.1.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf + sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" url: "https://pub.dev" source: hosted - version: "2.5.5" + version: "2.5.4" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f url: "https://pub.dev" source: hosted - version: "2.4.23" + version: "2.4.20" shared_preferences_foundation: dependency: transitive description: @@ -800,10 +792,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.1" shared_preferences_web: dependency: transitive description: @@ -861,10 +853,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "732792cfd197d2161a65bb029606a46e0a18ff30ef9e141a7a82172b05ea8ecd" + sha256: "1d562a3c1f713904ebbed50d2760217fd8a51ca170ac4b05b0db490699dbac17" url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.2.0" source_map_stack_trace: dependency: transitive description: @@ -929,14 +921,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 - url: "https://pub.dev" - source: hosted - version: "3.4.0" term_glyph: dependency: transitive description: @@ -949,26 +933,26 @@ packages: dependency: "direct main" description: name: test - sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" + sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" url: "https://pub.dev" source: hosted - version: "1.30.0" + version: "1.29.0" test_api: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.9" test_core: dependency: transitive description: name: test_core - sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" + sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" url: "https://pub.dev" source: hosted - version: "0.6.16" + version: "0.6.15" typed_data: dependency: transitive description: @@ -989,18 +973,18 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "3bb000251e55d4a209aa0e2e563309dc9bb2befea2295fd0cec1f51760aac572" + sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" url: "https://pub.dev" source: hosted - version: "6.3.29" + version: "6.3.28" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.3.6" url_launcher_linux: dependency: transitive description: @@ -1029,10 +1013,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.1" url_launcher_windows: dependency: transitive description: @@ -1117,42 +1101,18 @@ packages: dependency: transitive description: name: win32 - sha256: e7489db51886360dad710b3bc177108267f0554644dd04102dcb35f23b71c738 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "5.15.0" workmanager: dependency: "direct main" description: name: workmanager - sha256: "065673b2a465865183093806925419d311a9a5e0995aa74ccf8920fd695e2d10" - url: "https://pub.dev" - source: hosted - version: "0.9.0+3" - workmanager_android: - dependency: transitive - description: - name: workmanager_android - sha256: "9ae744db4ef891f5fcd2fb8671fccc712f4f96489a487a1411e0c8675e5e8cb7" - url: "https://pub.dev" - source: hosted - version: "0.9.0+2" - workmanager_apple: - dependency: transitive - description: - name: workmanager_apple - sha256: "1cc12ae3cbf5535e72f7ba4fde0c12dd11b757caf493a28e22d684052701f2ca" - url: "https://pub.dev" - source: hosted - version: "0.9.1+2" - workmanager_platform_interface: - dependency: transitive - description: - name: workmanager_platform_interface - sha256: f40422f10b970c67abb84230b44da22b075147637532ac501729256fcea10a47 + sha256: "746a50c535af15b6dc225abbd9b52ab272bcd292c535a104c54b5bc02609c38a" url: "https://pub.dev" source: hosted - version: "0.9.1+1" + version: "0.7.0" xdg_directories: dependency: transitive description: @@ -1178,5 +1138,5 @@ packages: source: hosted version: "2.2.4" sdks: - dart: ">=3.11.0 <4.0.0" - flutter: ">=3.41.0" + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.38.0" diff --git a/pubspec.yaml b/pubspec.yaml index 72e83ae..53d6cdd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 0.8.7+10 environment: - sdk: ^3.10.0 + sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -41,19 +41,19 @@ dependencies: flutter_localizations: sdk: flutter intl: any - test: ^1.29.0 + test: ^1.26.0 mocktail: ^1.0.3 file: ^7.0.0 shared_preferences: ^2.2.0 - flutter_riverpod: ^3.3.1 - riverpod: ^3.2.1 + flutter_riverpod: ^3.1.0 + riverpod: ^3.1.0 html: ^0.15.4 flex_color_scheme: ^8.4.0 url_launcher: ^6.3.2 flutter_linkify: ^6.0.0 - package_info_plus: ^10.0.0 - workmanager: ^0.9.0+3 - share_plus: ^13.0.0 + package_info_plus: ^9.0.0 + workmanager: ^0.7.0 + share_plus: ^12.0.1 open_filex: ^4.4.0 @@ -68,7 +68,8 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^6.0.0 full_coverage: ^1.0.0 - riverpod_lint: ^3.1.3 + custom_lint: ^0.8.1 + riverpod_lint: ^3.1.0 integration_test: sdk: flutter From 4426827598c3b164b2748316f58717c792961703 Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Mon, 23 Mar 2026 12:29:58 -0300 Subject: [PATCH 02/12] consolidate tests --- test/languages_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/languages_test.dart b/test/languages_test.dart index d28fd0e..1c4f786 100644 --- a/test/languages_test.dart +++ b/test/languages_test.dart @@ -55,7 +55,7 @@ class FakeDownloadAssetsController extends Fake bool? checkSize, List uncompressDelegates = const [UnzipDelegate()], Function(double p1)? onProgress, - Function()? onStartUnzipping, + Function()? onStartUnziping, Function()? onCancel, Function()? onDone, Map? requestQueryParams, @@ -73,7 +73,7 @@ class ThrowingDownloadAssetsController extends FakeDownloadAssetsController { bool? checkSize, List uncompressDelegates = const [UnzipDelegate()], Function(double p1)? onProgress, - Function()? onStartUnzipping, + Function()? onStartUnziping, Function()? onCancel, Function()? onDone, Map? requestQueryParams, @@ -327,7 +327,7 @@ void main() { 'Schritte der Vergebung', 'MissingTest' ])); - expect(deTest.state.sizeInKB, 147); + expect(deTest.state.sizeInKB, 148); expect(deTest.state.path, equals('assets-de/html-de-main')); // Test some error handling From 4e6d073710549f26c1ca3fb872bf18bc5bcf6bdf Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Mon, 23 Mar 2026 12:30:40 -0300 Subject: [PATCH 03/12] dev: add `fvmrc` to lock flutter version for development --- .fvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.fvmrc b/.fvmrc index 19e8577..d166963 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.41.6" + "flutter": "3.38.0" } \ No newline at end of file From 91d217c8d64a2acd00727445ddd3bfc04ed9e8b6 Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Mon, 23 Mar 2026 12:50:34 -0300 Subject: [PATCH 04/12] test: update test to reflect code changes --- test/languages_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/languages_test.dart b/test/languages_test.dart index 1c4f786..b46d007 100644 --- a/test/languages_test.dart +++ b/test/languages_test.dart @@ -327,7 +327,7 @@ void main() { 'Schritte der Vergebung', 'MissingTest' ])); - expect(deTest.state.sizeInKB, 148); + expect(deTest.state.sizeInKB, 147); expect(deTest.state.path, equals('assets-de/html-de-main')); // Test some error handling From f742b15eb86d80444a2799991f9f3c776c7c921e Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 17:55:07 -0300 Subject: [PATCH 05/12] build: update package versions --- pubspec.lock | 30 +++++++++++++++++++++++++++--- pubspec.yaml | 4 ++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 439045c..5bd9d49 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -229,10 +229,10 @@ packages: dependency: "direct main" description: name: download_assets - sha256: ecc0e9f644f1c57e5ba8c723b05e69ace7fd6177f34eebcadc496b7d410e6c4d + sha256: ab479ef705819783af9c2a53de9c033ac7f621677f250ad0d63728f260d16585 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" fake_async: dependency: transitive description: @@ -423,6 +423,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + idb_shim: + dependency: transitive + description: + name: idb_shim + sha256: "6cd94b71a33f1223b01ea2b359c3a6fde5980872b23b31d176a64c74d4dede57" + url: "https://pub.dev" + source: hosted + version: "2.8.5+2" integration_test: dependency: "direct dev" description: flutter @@ -740,6 +748,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + sembast: + dependency: transitive + description: + name: sembast + sha256: "139cf71496105de32e7a08a4e3a1ead0f81c4a616ec9703ed07e8f0d10cdd505" + url: "https://pub.dev" + source: hosted + version: "3.8.6" share_plus: dependency: "direct main" description: @@ -921,6 +937,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" term_glyph: dependency: transitive description: @@ -1138,5 +1162,5 @@ packages: source: hosted version: "2.2.4" sdks: - dart: ">=3.9.0 <4.0.0" + dart: ">=3.10.0 <4.0.0" flutter: ">=3.38.0" diff --git a/pubspec.yaml b/pubspec.yaml index 53d6cdd..8ffb87d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,8 +31,8 @@ environment: dependencies: flutter: sdk: flutter - flutter_html: ^3.0.0-beta.2 - flutter_html_table: ^3.0.0-beta.2 + flutter_html: ^3.0.0 + flutter_html_table: ^3.0.0 path_provider: ^2.0.11 download_assets: ^4.0.0 path: ^1.8.2 From 4d2360b41bea1cb83fc715a01eb12d53abe96f41 Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 18:30:40 -0300 Subject: [PATCH 06/12] feat: improve `flutter_html` - Fix layout rendering errors - Improve layout - Improve components --- lib/widgets/html_view.dart | 195 ++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 56 deletions(-) diff --git a/lib/widgets/html_view.dart b/lib/widgets/html_view.dart index 7763718..232cf03 100644 --- a/lib/widgets/html_view.dart +++ b/lib/widgets/html_view.dart @@ -12,69 +12,139 @@ class HtmlView extends StatelessWidget { /// left-to-right or right-to-left (LTR / RTL)? final TextDirection direction; + const HtmlView(this.content, this.direction, {super.key}); @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8), - child: SingleChildScrollView( - child: Column( + padding: const EdgeInsets.all(8), + child: SingleChildScrollView( + child: Column( children: [ SelectionArea( - child: Directionality( - textDirection: direction, -// child: Html( -// data: content, - child: Html.fromDom( - document: sanitize( - content, - MediaQuery.of(context).platformBrightness == - Brightness.dark), - extensions: const [TableHtmlExtension()], - style: { - "body": Style(fontSize: FontSize(15)), - "table": Style( - // set table width, otherwise they're broken - width: Width( - MediaQuery.of(context).size.width - 50)), - "td": Style( - padding: const EdgeInsets.fromLTRB(5, 3, 5, 3) - .htmlPadding), - "th": Style( - textAlign: TextAlign.center, - verticalAlign: VerticalAlign.top), - "h1": Style( - margin: - Margins(top: Margin(0), bottom: Margin(0))), - "h2": Style( - margin: - Margins(top: Margin(12), bottom: Margin(5))), - "h3": Style( - margin: - Margins(top: Margin(10), bottom: Margin(3))), - "li": Style( - margin: - Margins(top: Margin(3), bottom: Margin(3))), - "p": Style( - margin: - Margins(top: Margin(3), bottom: Margin(3))), - "ul": Style( - margin: - Margins(top: Margin(0), bottom: Margin(0))), -// TODO: reduce left padding/margin of
  • items -// But this doesn't seem to work in flutter_html-3.0.0-beta2 -/* "li": Style( - padding: HtmlPaddings.zero, margin: Margins.zero) */ - }, - onAnchorTap: (url, _, __) { - debugPrint("Link tapped: $url"); - if (url != null) { - Navigator.pushNamed(context, '/view$url'); - } - }))) + child: Directionality( + textDirection: direction, + // child: Html( + // data: content, + child: Html.fromDom( + document: sanitize( + content, + MediaQuery.of(context).platformBrightness == + Brightness.dark, + ), + extensions: [ + // Order matters: TagWrapExtension must come BEFORE + // TableHtmlExtension so it matches first + // during the preparing step. It then delegates the + // inner build to TableHtmlExtension via + // prepareFromExtension(extensionsToIgnore: {this}) + // and wraps the resulting table widget in a + // horizontal scroll view. Without this ordering, + // TableHtmlExtension wins the match and the wrap + // is never applied — leaving wide tables to + // overflow or hit "RenderBox was not laid out". + // + // Known remaining issue: on real devices the + // semantics pass logs a non-fatal per-frame + // "RenderBox was not laid out: RenderParagraph" + // assertion during PipelineOwner.flushSemantics, + // originating deep inside the + // LayoutGrid/LayoutBuilder cell tree built by + // TableHtmlExtension. Wrapping the table in + // SelectionContainer.disabled was tried as a + // workaround (mirroring raw_tooltip.dart:813-815) + // but did NOT fix the assertion and broke text + // selection across the whole page, so it was + // reverted. Page still renders fine; the spam is + // cosmetic in logs. + TagWrapExtension( + tagsToWrap: const {'table'}, + builder: (child) => _HorizontalTableScroll(child: child), + ), + const TableHtmlExtension(), + ], + style: { + "body": Style(fontSize: FontSize(15)), + "td": Style( + padding: + const EdgeInsets.fromLTRB(5, 3, 5, 3).htmlPadding, + ), + "th": Style( + textAlign: TextAlign.center, + verticalAlign: VerticalAlign.top, + ), + "h1": Style( + margin: Margins(top: Margin(0), bottom: Margin(0)), + ), + "h2": Style( + margin: Margins(top: Margin(12), bottom: Margin(5)), + ), + "h3": Style( + margin: Margins(top: Margin(10), bottom: Margin(3)), + ), + "li": Style( + margin: Margins(top: Margin(3), bottom: Margin(3)), + padding: HtmlPaddings.zero, + ), + "p": Style( + margin: Margins(top: Margin(3), bottom: Margin(3)), + ), + "ul": Style( + margin: Margins(top: Margin(0), bottom: Margin(0)), + ), + }, + onAnchorTap: (url, _, __) { + debugPrint("Link tapped: $url"); + if (url != null) { + Navigator.pushNamed(context, '/view$url'); + } + }, + ), + ), + ), ], - ))); + ), + ), + ); + } +} + +/// Wraps a rendered `
    ` in a horizontal scroll view with an +/// always-visible scrollbar. An explicit [ScrollController] is needed +/// because the scroll view sits inside a `WidgetSpan` (via +/// [TagWrapExtension]) where [PrimaryScrollController] does not apply. +/// [Scrollbar.thumbVisibility] is forced on so users can see at a glance +/// when a table extends beyond the screen and needs to be scrolled. +class _HorizontalTableScroll extends StatefulWidget { + const _HorizontalTableScroll({required this.child}); + + final Widget child; + + @override + State<_HorizontalTableScroll> createState() => _HorizontalTableScrollState(); +} + +class _HorizontalTableScrollState extends State<_HorizontalTableScroll> { + final ScrollController _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scrollbar( + controller: _controller, + thumbVisibility: true, + child: SingleChildScrollView( + controller: _controller, + scrollDirection: Axis.horizontal, + child: widget.child, + ), + ); } } @@ -142,6 +212,19 @@ htmldom.Document sanitize(String inputHtml, bool isDarkMode) { for (var element in dom.querySelectorAll('th')) { element.attributes.remove('style'); } + // e.g. Time_with_God has
    . flutter_html 3.0.0 + // does NOT resolve percent widths against the containing block (see + // CssBoxWidget._computeSize and Normalize.normalize in + // flutter_html-3.0.0/lib/src/css_box_widget.dart): it uses the raw + // numeric value regardless of unit, so `width: 100%` is interpreted as + // literally 100 px and the table overflows by hundreds of pixels. + // Strip style and width attributes from
    so it falls back to + // Width.auto() and our horizontal-scroll wrapper can size the table + // to its intrinsic content width. + for (var element in dom.querySelectorAll('table')) { + element.attributes.remove('style'); + element.attributes.remove('width'); + } // For all worksheets with subtitles (e.g. "Overcoming Colored Lenses"): // Replace

    ...

    @@ -157,7 +240,7 @@ htmldom.Document sanitize(String inputHtml, bool isDarkMode) { // For God's Story (five fingers): // Remove
    Date: Sat, 11 Apr 2026 18:32:06 -0300 Subject: [PATCH 07/12] chore: install global FlutterError.onError to catch framework error --- lib/main.dart | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index 3b9d988..4c267de 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:app4training/l10n/generated/app_localizations.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:app4training/routes/routes.dart'; @@ -8,8 +9,121 @@ import 'data/app_language.dart'; import 'data/globals.dart'; import 'design/theme.dart'; +/// Installs a global [FlutterError.onError] wrapper that suppresses the +/// known non-fatal framework assertions produced by `flutter_html` / +/// `flutter_html_table` when rendering pages that contain tables, and +/// forwards everything else unchanged to the previously-installed +/// handler (typically [FlutterError.presentError]). +/// +/// Four assertion variants have been observed in the wild, all +/// originating from the `LayoutBuilder` / `LayoutGrid` / `WidgetSpan` +/// composition that `TableHtmlExtension.build` constructs for `
    ` +/// rendering: +/// +/// 1. Paint-time `RenderBox was not laid out` — fires from +/// `PipelineOwner.flushPaint` → `RenderCSSBox.paint` → +/// `RenderDecoratedBox.paint` → `RenderBox.size`. Stack contains +/// `flutter_html/` and `flutter_layout_grid/` frames. +/// +/// 2. Semantics-pass `RenderBox was not laid out` — fires from +/// `PipelineOwner.flushSemantics` → +/// `_SemanticsGeometry.computeChildGeometry` → +/// `RenderBox.semanticBounds` → `RenderBox.size`. Reported via +/// `SchedulerBinding._invokeFrameCallback` with +/// `library: 'scheduler library'`. The stack is **pure framework +/// code** with no package frames, because the semantics walk +/// traverses the `_RenderObjectSemantics` tree directly without +/// going through widget code — so matching on package paths alone +/// would miss this variant. +/// +/// 3. Layout-time `RenderBox.size accessed in ...computeDryBaseline` +/// — fires from `RenderParagraph.performLayout` → +/// `layoutInlineChildren` → child `performLayout` reading `.size` +/// during a dry-baseline computation. Stack contains +/// `flutter_html/src/css_box_widget.dart` frames. +/// +/// 4. Layout-time `'child!.hasSize' is not true` — fires from +/// `RenderAligningShiftedBox.alignChild` while laying out a +/// `Container` constructed in `flutter_html_table.dart:261`. +/// Stack contains `flutter_html/` and `flutter_layout_grid/` +/// frames. +/// +/// All four are non-fatal: the page renders, users can interact +/// normally, selection still works outside tables. They flood logs +/// (hundreds per page load) which drowns out any real errors, which is +/// why we filter them. +/// +/// Why this lives here and not in the widget layer: +/// 1. The assertions are not reproducible in `flutter_test`, even +/// with `tester.ensureSemantics()` + a phone-sized surface, so we +/// cannot regression-test a widget-level fix; +/// 2. The root cause is inside third-party package code +/// (`flutter_html_table` 3.0.0). Wrapping tables in +/// `SelectionContainer.disabled` (mirroring Flutter's own +/// `raw_tooltip.dart:813-815` pattern) did not help and also +/// broke text selection across the whole page; +/// 3. The real fix is a newer upstream release. Until then this +/// filter keeps the logs usable. +/// +/// Matching strategy — an error is suppressed only if BOTH: +/// (a) the exception message contains one of the four known +/// signatures (`"RenderBox was not laid out"`, `"computeDryBaseline"`, +/// `"renderBoxDoingDryBaseline"`, or `"'child!.hasSize'"`), AND +/// (b) the stack either passes through `flutter_html/` or +/// `flutter_layout_grid/` package code (covers variants 1, 3, 4) +/// OR contains `"flushSemantics"` (covers variant 2, whose stack +/// is entirely framework code). +/// +/// Any error that doesn't satisfy BOTH conditions is forwarded to the +/// previous handler unchanged, so unrelated regressions are not masked. +/// +/// On the first suppression per app run we emit a single breadcrumb via +/// [debugPrint] so developers inspecting logs can see that the filter +/// is active. Subsequent suppressions are silent to avoid log spam. +/// +/// See also: `Task Progress.md` §5 for the full investigation history, +/// including the diagnostic logging session that identified all four +/// variants. +void _installHtmlTableSemanticsFilter() { + final FlutterExceptionHandler? previousHandler = FlutterError.onError; + var suppressedBreadcrumbEmitted = false; + FlutterError.onError = (FlutterErrorDetails details) { + final String exceptionText = details.exception.toString(); + final String stackText = details.stack?.toString() ?? ''; + final bool exceptionMatchesKnownSignature = + exceptionText.contains('RenderBox was not laid out') || + exceptionText.contains('computeDryBaseline') || + exceptionText.contains('renderBoxDoingDryBaseline') || + exceptionText.contains("'child!.hasSize'"); + final bool stackMatchesHtmlOrSemanticsPath = + stackText.contains('flutter_html/') || + stackText.contains('flutter_layout_grid/') || + stackText.contains('flushSemantics'); + final bool isKnownHtmlTableAssertion = + exceptionMatchesKnownSignature && stackMatchesHtmlOrSemanticsPath; + if (isKnownHtmlTableAssertion) { + if (!suppressedBreadcrumbEmitted) { + suppressedBreadcrumbEmitted = true; + debugPrint( + 'Suppressing known flutter_html_table non-fatal framework ' + 'assertions (see Task Progress.md §5 and main.dart ' + '_installHtmlTableSemanticsFilter for details). Subsequent ' + 'suppressions are silent.', + ); + } + return; + } + if (previousHandler != null) { + previousHandler(details); + } else { + FlutterError.presentError(details); + } + }; +} + void main() async { WidgetsFlutterBinding.ensureInitialized(); + _installHtmlTableSemanticsFilter(); final prefs = await SharedPreferences.getInstance(); final packageInfo = await PackageInfo.fromPlatform(); From 60133a9d89a1e9692d7f88be7673bdc996c9d8b0 Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 18:32:46 -0300 Subject: [PATCH 08/12] test: add test for rendering html tables with assets --- .../assets-en/html-en-main/Time_with_God.html | 87 +++++++ test/html_view_table_test.dart | 221 ++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 test/assets-en/html-en-main/Time_with_God.html create mode 100644 test/html_view_table_test.dart diff --git a/test/assets-en/html-en-main/Time_with_God.html b/test/assets-en/html-en-main/Time_with_God.html new file mode 100644 index 0000000..17c8316 --- /dev/null +++ b/test/assets-en/html-en-main/Time_with_God.html @@ -0,0 +1,87 @@ +

    Time with God

    +

    If we want to know a person, we need to have regular contact with them. It’s the same in our relationship with God: To get to know Him better, we need to make the time to spend with Him. +

    +

    The purpose of our time with God

    +
    • To worship God: God is worthy of our praise and deserves our time.
    • +
    • To talk with God: In prayer, we share with Him what is on our hearts. We listen to Him so that He can speak to us and lead us.
    • +
    • To learn from God: God wants to teach us through His Word, the Bible, and His Spirit. This is like spiritual food for us so that we can grow.
    +

    Examples from the Bible

    +

    Look up the following Bible verses and fill out the table: Which person is it talking about? When, where and how exactly does this person spend time with God? +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Verse +Person +Time +Place +What exactly? +
    Psalms 5:3 +David +in the morning +? +praying and waiting for answer +
    Daniel 6:11 +
    Mark 1:35 +
    Luke 6:12 +
    Acts 10:9 +
    Acts 16:25 +
    +

    Tools and suggestions for our time with God

    +
    • Bible: Read a passage from the Bible and then think and pray about it. You can use the head-heart-hands questions for this:
      Head-32.pngHead: What do I learn here?
      Heart-32.pngHeart: What touches my heart?
      Hands-32.pngHands: How can I apply this?
    • +
    • Place: Choose a place where you can meet with God without being distracted.
    • +
    • Time: Find the best time when you can consistently meet with God.
    • +
    • Plan: Choose a Bible book to read through. For the beginning, read Luke and Acts (in the New Testament).
    • +
    • Making notes and sharing: Write down or share with your friends your thoughts, what you feel God is saying to you, your questions, the prayer requests of you or your friends, how God answered prayer, encouraging verses, …
    +

    My commitment for my time with God

    +

    Time: +

    +
    +

    Place: +

    +
    +

    Plan: +

    +
    +


    +


    +

    \ No newline at end of file diff --git a/test/html_view_table_test.dart b/test/html_view_table_test.dart new file mode 100644 index 0000000..bb00a9c --- /dev/null +++ b/test/html_view_table_test.dart @@ -0,0 +1,221 @@ +import 'dart:io'; + +import 'package:app4training/widgets/html_view.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Reproduces the "RenderBox was not laid out" crashes reported on pages +/// like Essentials > Time With God that contain tables. Only goal here: +/// make sure HtmlView can render common table shapes without throwing. +void main() { + Future pump(WidgetTester tester, String body) async { + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: HtmlView( + '$body', + TextDirection.ltr, + ), + ), + )); + await tester.pumpAndSettle(); + } + + testWidgets('renders a simple 2x2 table', (tester) async { + await pump(tester, ''' + + + +
    AB
    12
    +'''); + expect(tester.takeException(), isNull); + }); + + testWidgets('wraps each in a visible horizontal Scrollbar', + (tester) async { + // Guards the UX affordance: users need a visible scroll thumb to + // discover that wide tables are horizontally scrollable. + await pump(tester, ''' +
    + + +
    H1H2
    12
    + + + +
    Other
    x
    +'''); + expect(tester.takeException(), isNull); + // Expect one Scrollbar per table. The outer page scroll is a + // SingleChildScrollView without a Scrollbar, so every Scrollbar found + // here belongs to a _HorizontalTableScroll wrapper. + expect(find.byType(Scrollbar), findsNWidgets(2)); + // And the scroll direction inside each wrapper must be horizontal. + final horizontalScrolls = tester + .widgetList(find.byType(SingleChildScrollView)) + .where((w) => w.scrollDirection == Axis.horizontal) + .toList(); + expect(horizontalScrolls.length, 2); + }); + + testWidgets('renders a table with long non-breaking cell content', (tester) async { + // Long single token that cannot wrap — this is the kind of content that + // causes layout problems on some translations of Time With God. + await pump(tester, ''' + + + + + + +
    HeadingAnother heading
    Supercalifragilisticexpialidocious_long_word_that_cannot_wrap_naturallyShort
    +'''); + expect(tester.takeException(), isNull); + }); + + testWidgets('renders a wide many-column table', (tester) async { + await pump(tester, ''' + + + + + + + + + + + + + + + +
    Col1Col2Col3Col4Col5Col6Col7Col8
    row 1 cell 1 with some textrow 1 cell 2 with some textrow 1 cell 3 with some textrow 1 cell 4 with some textrow 1 cell 5 with some textrow 1 cell 6 with some textrow 1 cell 7 with some textrow 1 cell 8 with some text
    +'''); + expect(tester.takeException(), isNull); + }); + + testWidgets('renders a table with th[style] (stripped by sanitize)', + (tester) async { + await pump(tester, ''' + + + + + + + + + + + +
    OneTwoThree
    Short cellMedium length cell content that wrapsSome other content here that is longer than the others
    +'''); + expect(tester.takeException(), isNull); + }); + + testWidgets('renders a table with empty cells (fill-in-the-blank)', + (tester) async { + // Real Time_with_God table shape: lots of empty cells for users to fill in. + await pump(tester, ''' + + + + + + + + + + + + + + + + + + + + + + +
    VersePersonTimePlaceWhat exactly?
    Psalms 5:3Davidin the morning?praying and waiting for answer
    Daniel 6:11
    Mark 1:35
    Luke 6:12
    Acts 10:9
    Acts 16:25
    +'''); + expect(tester.takeException(), isNull); + }); + + testWidgets('renders a nested inside a
  • (Time_with_God shape)', + (tester) async { + // This is the exact shape from Time_with_God line 70: a table inside a + // list item inside a ul. It uses a
    before the nested table. + await pump(tester, ''' +
      +
    • Bible: Read a passage and think about it. Use the head-heart-hands questions:
      +
  • + + + + + + + + + + + + + + +
    Head-32.pngHead: What do I learn here?
    Heart-32.pngHeart: What touches my heart?
    Hands-32.pngHands: How can I apply this?
    +
  • +
  • Place: Choose a quiet place.
  • +
  • Time: Find the best time.
  • + +'''); + expect(tester.takeException(), isNull); + }); + + testWidgets('renders the real Time_with_God fixture end-to-end', + (tester) async { + // Pumping the exact page content that was crashing in production. + // Critically: + // 1. enable semantics — on a real device the semantics pass walks the + // render tree and trips `RenderBox.size` assertions on any unlaid + // RenderParagraph; without this handle flutter_test skips + // flushSemantics and hides the bug; + // 2. use a phone-sized surface — the default 800x600 flutter_test + // surface is wide enough that the Time_with_God table fits without + // horizontal overflow, so the horizontal-scroll / LayoutGrid path + // that triggers the assertion on real devices never runs. + final semantics = tester.ensureSemantics(); + try { + await tester.binding.setSurfaceSize(const Size(390, 844)); + final html = File('test/assets-en/html-en-main/Time_with_God.html') + .readAsStringSync(); + await pump(tester, html); + expect(tester.takeException(), isNull); + } finally { + await tester.binding.setSurfaceSize(null); + semantics.dispose(); + } + }); + + testWidgets('renders a table wrapped in the standard page chrome', + (tester) async { + // Mimics the structure of a real Time With God page: headings, + // paragraphs, and a table together. + await pump(tester, ''' +

    Time with God

    +

    Introduction paragraph describing the topic.

    +

    Three different voices

    + + + + + +
    VoiceSourceEffect
    YourselfYour own thoughtsSelf-centered
    EnemyThe enemyAccusing, fearful
    GodHoly SpiritLoving, convicting
    +

    Follow-up text after the table.

    +'''); + expect(tester.takeException(), isNull); + }); +} From 59a2021347ab0541b73ba2b92740e5872703d84f Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 19:21:23 -0300 Subject: [PATCH 09/12] test: fix broken test for `languages_test` --- test/languages_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/languages_test.dart b/test/languages_test.dart index b46d007..d28fd0e 100644 --- a/test/languages_test.dart +++ b/test/languages_test.dart @@ -55,7 +55,7 @@ class FakeDownloadAssetsController extends Fake bool? checkSize, List uncompressDelegates = const [UnzipDelegate()], Function(double p1)? onProgress, - Function()? onStartUnziping, + Function()? onStartUnzipping, Function()? onCancel, Function()? onDone, Map? requestQueryParams, @@ -73,7 +73,7 @@ class ThrowingDownloadAssetsController extends FakeDownloadAssetsController { bool? checkSize, List uncompressDelegates = const [UnzipDelegate()], Function(double p1)? onProgress, - Function()? onStartUnziping, + Function()? onStartUnzipping, Function()? onCancel, Function()? onDone, Map? requestQueryParams, From 9a8f6571ebb8c3f676231743a2f5d13c819d01b1 Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 19:34:48 -0300 Subject: [PATCH 10/12] dev: correct version saved for `fvm` tool in `.fvmrc` --- .fvmrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.fvmrc b/.fvmrc index d166963..049b27d 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.38.0" -} \ No newline at end of file + "flutter": "3.41.6" +} From b0db7fe55a9a6259ab32fb5edb77317e749599cc Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 19:48:24 -0300 Subject: [PATCH 11/12] bump: upgrade more dependencies --- pubspec.lock | 188 ++++++++++++++++++++++++--------------------------- pubspec.yaml | 21 +++--- 2 files changed, 102 insertions(+), 107 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 5bd9d49..169781a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,42 +5,42 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d + sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e" url: "https://pub.dev" source: hosted - version: "91.0.0" + version: "92.0.0" analysis_server_plugin: dependency: transitive description: name: analysis_server_plugin - sha256: "26844e7f977087567135d62532b67d5639fe206c5194c3f410ba75e1a04a2747" + sha256: "44adba4d74a2541173bad4c11531d2a4d22810c29c5ddb458a38e9f4d0e5eac7" url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.3.4" analyzer: dependency: transitive description: name: analyzer - sha256: a40a0cee526a7e1f387c6847bd8a5ccbf510a75952ef8a28338e989558072cb0 + sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e" url: "https://pub.dev" source: hosted - version: "8.4.0" + version: "9.0.0" analyzer_buffer: dependency: transitive description: name: analyzer_buffer - sha256: aba2f75e63b3135fd1efaa8b6abefe1aa6e41b6bd9806221620fa48f98156033 + sha256: ff4bd291778c7417fe53fe24ee0d0a1f1ffe281a2d4ea887e7094f16e36eace7 url: "https://pub.dev" source: hosted - version: "0.1.11" + version: "0.3.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "08cfefa90b4f4dd3b447bda831cecf644029f9f8e22820f6ee310213ebe2dd53" + sha256: "6645a029da947ffd823d98118f385d4bd26b54eb069c006b22e0b94e451814b5" url: "https://pub.dev" source: hosted - version: "0.13.10" + version: "0.13.11" archive: dependency: transitive description: @@ -89,22 +89,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.dev" - source: hosted - version: "2.0.4" - ci: - dependency: transitive - description: - name: ci - sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" - url: "https://pub.dev" - source: hosted - version: "0.1.0" cli_config: dependency: transitive description: @@ -113,14 +97,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" clock: dependency: transitive description: @@ -129,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" collection: dependency: transitive description: @@ -177,30 +161,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" - custom_lint: - dependency: "direct dev" - description: - name: custom_lint - sha256: "751ee9440920f808266c3ec2553420dea56d3c7837dd2d62af76b11be3fcece5" - url: "https://pub.dev" - source: hosted - version: "0.8.1" - custom_lint_core: - dependency: transitive - description: - name: custom_lint_core - sha256: "85b339346154d5646952d44d682965dfe9e12cae5febd706f0db3aa5010d6423" - url: "https://pub.dev" - source: hosted - version: "0.8.1" - custom_lint_visitor: - dependency: transitive - description: - name: custom_lint_visitor - sha256: "91f2a81e9f0abb4b9f3bb529f78b6227ce6050300d1ae5b1e2c69c66c7a566d8" - url: "https://pub.dev" - source: hosted - version: "1.0.0+8.4.0" dart_style: dependency: transitive description: @@ -249,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + ffi_leak_tracker: + dependency: transitive + description: + name: ffi_leak_tracker + sha256: "4093d4ef9ca06ffe2786e73bfb25e22aa92112b9bb4ec941f11e3e6b61489a97" + url: "https://pub.dev" + source: hosted + version: "0.1.2" file: dependency: "direct main" description: @@ -340,10 +308,10 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: "38ec6c303e2c83ee84512f5fc2a82ae311531021938e63d7137eccc107bf3c02" + sha256: "4e166be88e1dbbaa34a280bdb744aeae73b7ef25fdf8db7a3bb776760a3648e2" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.3.1" flutter_test: dependency: "direct dev" description: flutter @@ -391,6 +359,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 + url: "https://pub.dev" + source: hosted + version: "1.0.2" html: dependency: "direct main" description: @@ -556,6 +532,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + url: "https://pub.dev" + source: hosted + version: "0.17.6" node_preamble: dependency: transitive description: @@ -584,18 +568,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d + sha256: c2a4a9404e578d7c69e3cf19f0b057d906bd0b073deedc8006db997a8bfe97ca url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "10.0.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" + sha256: "063b21cce7a2e3d902897d6cefc3bd211bb8ea42190698be72219cd5017f1c65" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "4.0.0" path: dependency: "direct main" description: @@ -700,14 +684,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" - url: "https://pub.dev" - source: hosted - version: "1.5.0" quiver: dependency: transitive description: @@ -720,34 +696,26 @@ packages: dependency: "direct main" description: name: riverpod - sha256: "16ff608d21e8ea64364f2b7c049c94a02ab81668f78845862b6e88b71dd4935a" + sha256: "8c22216be8ad3ef2b44af3a329693558c98eca7b8bd4ef495c92db0bba279f83" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.1" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "947b05d04c52a546a2ac6b19ef2a54b08520ff6bdf9f23d67957a4c8df1c3bc0" + sha256: e55bc08c084a424e1bbdc303fe8ea75daafe4269b68fd0e0f6f1678413715b66 url: "https://pub.dev" source: hosted - version: "1.0.0-dev.8" + version: "1.0.0-dev.9" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: "4d2eb0d19bbe7e3323bd0ce4553b2e6170d161a13914bfdd85a3612329edcb43" + sha256: "64e8debf5b719a37d48b9785dd595d34133fdcd84b8fd07157a621c54ab2156f" url: "https://pub.dev" source: hosted - version: "3.1.0" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" + version: "3.1.3" sembast: dependency: transitive description: @@ -760,18 +728,18 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840" + sha256: ad3e91cabb7dc3c7687e0f4bdaf24fb192141d11bfbf9ddea7c26f3d4e8bfb5d url: "https://pub.dev" source: hosted - version: "12.0.1" + version: "13.0.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + sha256: ccf360f79b95993b083259d8f37baf20a47bcf8e2551ccebdc4f781b4d15e734 url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "7.0.0" shared_preferences: dependency: "direct main" description: @@ -1037,10 +1005,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" url_launcher_windows: dependency: transitive description: @@ -1125,18 +1093,42 @@ packages: dependency: transitive description: name: win32 - sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + sha256: "316d813e24518851c2682b1a57bc7e2e54e9c7b81493d48bef502fea0c17f841" url: "https://pub.dev" source: hosted - version: "5.15.0" + version: "6.0.1" workmanager: dependency: "direct main" description: name: workmanager - sha256: "746a50c535af15b6dc225abbd9b52ab272bcd292c535a104c54b5bc02609c38a" + sha256: "065673b2a465865183093806925419d311a9a5e0995aa74ccf8920fd695e2d10" + url: "https://pub.dev" + source: hosted + version: "0.9.0+3" + workmanager_android: + dependency: transitive + description: + name: workmanager_android + sha256: "9ae744db4ef891f5fcd2fb8671fccc712f4f96489a487a1411e0c8675e5e8cb7" + url: "https://pub.dev" + source: hosted + version: "0.9.0+2" + workmanager_apple: + dependency: transitive + description: + name: workmanager_apple + sha256: "1cc12ae3cbf5535e72f7ba4fde0c12dd11b757caf493a28e22d684052701f2ca" + url: "https://pub.dev" + source: hosted + version: "0.9.1+2" + workmanager_platform_interface: + dependency: transitive + description: + name: workmanager_platform_interface + sha256: f40422f10b970c67abb84230b44da22b075147637532ac501729256fcea10a47 url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.9.1+1" xdg_directories: dependency: transitive description: @@ -1162,5 +1154,5 @@ packages: source: hosted version: "2.2.4" sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.38.0" + dart: ">=3.11.0 <4.0.0" + flutter: ">=3.41.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8ffb87d..16d7bc7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,26 +34,26 @@ dependencies: flutter_html: ^3.0.0 flutter_html_table: ^3.0.0 path_provider: ^2.0.11 - download_assets: ^4.0.0 + download_assets: ^4.1.0 path: ^1.8.2 http: ^1.0.0 dio: ^5.0.0 flutter_localizations: sdk: flutter intl: any - test: ^1.26.0 + test: ^1.29.0 # 1.30+ needs test_api >0.7.9, but flutter_test pins test_api 0.7.9 mocktail: ^1.0.3 file: ^7.0.0 shared_preferences: ^2.2.0 - flutter_riverpod: ^3.1.0 - riverpod: ^3.1.0 + flutter_riverpod: ^3.3.1 + riverpod: ^3.2.1 html: ^0.15.4 flex_color_scheme: ^8.4.0 url_launcher: ^6.3.2 flutter_linkify: ^6.0.0 - package_info_plus: ^9.0.0 - workmanager: ^0.7.0 - share_plus: ^12.0.1 + package_info_plus: ^10.0.0 + workmanager: ^0.9.0+3 + share_plus: ^13.0.0 open_filex: ^4.4.0 @@ -68,8 +68,11 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^6.0.0 full_coverage: ^1.0.0 - custom_lint: ^0.8.1 - riverpod_lint: ^3.1.0 + # custom_lint removed: custom_lint 0.8.1 requires analyzer ^8, but + # riverpod_lint >=3.1.1 requires analyzer ^9. riverpod_lint 3.1.3 + # migrated from custom_lint to analysis_server_plugin, so custom_lint + # is no longer needed here. + riverpod_lint: ^3.1.3 integration_test: sdk: flutter From fe560ee5108a1030731f842245daa7fcfdab3a2e Mon Sep 17 00:00:00 2001 From: Gabriel Sousa Date: Sat, 11 Apr 2026 19:48:41 -0300 Subject: [PATCH 12/12] ci: upgrade workflow to remove unused linter --- .github/workflows/main.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2c2ffa6..baea198 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -44,7 +44,6 @@ jobs: # TODO clean up the dart analyzer info stuff # dart analyze --fatal-infos dart analyze - dart run custom_lint - name: Run all tests and generate coverage information in coverage/lcov.info run: flutter test --coverage