Rework the visa-free calculator - #7
Merged
Merged
Conversation
The screen assumed everyone gets 30 days from a single entry date, and its remaining-days maths truncated: at 10:00 on the day before the deadline it reported zero days left when two were still available. Rules ----- The guide's own calculator article describes three regimes, and the screen now asks which one applies: 30 days per entry Russia, Belarus, China, Kazakhstan 90 days in any 180 EU, USA, Ukraine and most others 30 days in any 365 Bahamas, Barbados, Colombia and five more A rolling window cannot be answered from one date — it counts every day spent in the country over the last half year — so the screen keeps a list of trips instead. The single date the old screen stored is carried over on first run, so nobody loses what they had entered. Arithmetic ---------- `lib/data/visa_rule.dart` holds the calculation on its own, with 15 tests. Both the entry day and the exit day count, as the guide states. Calendar days are anchored to UTC midnight: `Duration(days: 1)` is exactly 24 hours, so adding days across the March clock change used to lose one. Screen ------ A day counter with a progress ring, the must-leave-by date, an overstay warning, and the trips list. The deadline can be turned into a reminder, which reuses the existing deadlines feature rather than adding a second list of dates, or exported to the calendar. Six localization keys the old dialog owned are gone; the new strings are in both languages. Layout ------ Buttons placed directly in a Row now sit in Expanded. The app's button theme asks for a full-width minimum size, and a Row hands its children an unbounded width — together they assert, and the bottom sheet was rendering with no height at all. Noted in the theme where the minimum size is set.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The visa run calculator assumed every user gets 30 days from a single entry
date, and it counted the remaining days wrongly.
The counting bug
Remaining days were computed by subtracting two
DateTimes and reading.inDays, which truncates. Entering on 1 January with a 30-day allowance:The last three days of a stay all read as "0 days left" — the days when the
number matters most.
Not everyone is on the same rule
The guide's own calculator article sets out three regimes, and the screen now
asks which one applies:
This matters because a visa run only resets the counter under the first rule.
Under a rolling window, leaving and coming back buys nothing — and the screen
now says so instead of implying otherwise.
A rolling window also cannot be answered from one date: it counts every day
spent in the country across the window, however many trips that took. So the
screen keeps a list of trips. The single date the old screen stored is
carried over on first run, so nobody loses what they had entered.
The arithmetic is its own file, and tested
lib/data/visa_rule.dartholds the calculation with no Flutter in it, under15 unit tests. Two things it gets right that are easy to get wrong:
days of stay, as the guide states.
Duration(days: 1)isexactly 24 hours, so adding days to a local date across the last Sunday in
March gains an hour and can drop a whole day from a difference. A test
covers the boundary.
The screen
A day counter with a progress ring, the must-leave-by date, and an overstay
warning when the allowance is gone. The deadline can be turned into a real
reminder — that reuses the existing deadlines feature rather than adding a
second list of dates to the app — or exported to the calendar as an all-day
event.
The old screen's animated GIF icons rendered as flat black shapes, its empty
state claimed "29 days left" next to a blank date, and it formatted every
date with a hardcoded Russian
y г.suffix regardless of language. All gone.Six localization keys the old dialog owned are removed; the new strings are
in both languages.
One layout fix worth knowing about
Buttons placed directly in a
Rownow sit inExpanded. The app's buttontheme asks for a full-width minimum size, and a
Rowhands its children anunbounded width — together they assert, and the bottom sheet was rendering
with no height at all: visible as a dimmed screen with nothing on it. It is
noted in the theme next to the minimum size that causes it.
Verification
dart format,flutter analyze(0 issues), 59 tests — 15 for the rules,6 driving the screen itself, including one that asserts the sheet has a
non-zero size so the invisible-sheet bug cannot come back
rules and watching the count change, creating the reminder, and the trips
list