haptic_morse 2.0.0
haptic_morse: ^2.0.0 copied to clipboard
Convert text to Morse code and haptic vibration patterns in Dart.
2.0.0 #
A breaking release. 1.x haptic patterns were played inverted, and fixing that required changing the output. See Migrating in the README for a table of every renamed member.
Fixed #
- Haptic patterns are no longer phase-inverted.
package:vibrationtreats index 0 ofpatternas an off delay and alternates off/on from there - the convention shared by Android'sVibrationEffect.createWaveformand the iOS implementation. 1.x emitted a vibration at index 0, so every dot and dash was played as silence and every gap as a buzz.toVibrationPattern()now emits the leading0. - Sequences are well formed at every boundary. Leading whitespace no longer emits a spurious word gap, a trailing unsupported character no longer emits a dangling letter gap, and consecutive spaces no longer emit adjacent gaps (which inverted the phase of everything after them). A word made entirely of unmapped characters no longer produces a second word gap. Gaps are now emitted only between two elements that both exist, so none of these can recur.
- Characters outside the Basic Multilingual Plane work. Text is segmented into grapheme clusters, so emoji built from surrogate pairs, variation selectors, or zero-width joiners count as one character. Previously a single non-BMP character was split into two surrogate halves and resolved as two separate letters.
- The core no longer depends on Flutter.
package:haptic_morse/haptic_morse.dartis pure Dart and runs underdart runanddart test; 1.x pulled indart:uithrough the barrel, so even the shipped example could not run.
Added #
HapticEvent, a sealed type withHapticDot,HapticDash,HapticSymbolGap,HapticLetterGap, andHapticWordGap. Each carries aduration, anisVibrationphase, value equality, and JSON support, so a sequence can be rendered or analysed instead of being an opaqueList<int>.List<HapticEvent>.toVibrationPattern()and.totalDuration.HapticVibration.vibrateTextand.vibrateEvents, which connect encoding to playback. Nothing in 1.x linked the two halves, so the inversion bug shipped silently.dashReference, alongsidesymbolReference, so custom patterns are unambiguous and can be validated.String.toVibrationPattern().- Argument validation on
HapticMorse.custom- see Changed. HapticVibration.hasVibrator,.hasCustomVibrationsSupport, and.hasAmplitudeControl, so an app can fall back to showing the Morse code on a device that cannot reproduce the timing. Nothing in 1.x exposed a capability check, so a haptic-only message was simply unreadable there.- Punctuation in the default table.
. , : ? ' - / ( ) " = + @from ITU-R M.1677-1, plus the conventional& ! ; _ $. These were previously skipped as unmapped characters. HapticMorse.accentedLetters, an opt-in map of À Å Ä Ç È É Ñ Ö Ü for the newadditionalSymbolsargument. Kept opt-in because they are regional convention rather than ITU-normative.additionalSymbolsonHapticMorse.customandHapticMorse.atSpeed, merging extra character-to-pattern entries on top of the resolved table.- Decoding:
decodeMorseStringanddecodeEvents.decodeEventsneeds no threshold guessing, since the events are already typed - symbol and word boundaries are exact. HapticMorse.atSpeed, expressing timing in words per minute (unit = 1200 / wpm), with Farnsworth timing viaeffectiveWordsPerMinute: symbols keep their character-speed shape while the letter and word gaps stretch, which is what makes Morse readable through skin without distorting each character.supportedCharacters, listing everything an encoder can represent.HapticModel.empty, the constant empty model. The main constructor is no longerconst, because it now copies itseventslist.HapticEvent.minimumPerceptibleMillisecondsplusList<HapticEvent>.imperceptibleEventsand.isLikelyPerceptible, an advisory check for timings too short to be felt. Deliberately advisory and not enforced: the real floor is device specific, and a sequence may be rendered or analysed rather than played.- A conformance suite checking the output against ITU-R M.1677-1: the
1/3/1/3/7 unit ratios, the standard
PARISword measuring exactly 50 units, the1200/dotwords-per-minute formula, the full ITU code table, and an encode/decode round trip using an independent table.
Changed #
- Library split.
HapticVibrationmoved topackage:haptic_morse/haptic_morse_vibration.dart.package:vibrationis no longer re-exported, so its releases are no longer implicitly breaking changes for this package. - Renames:
convertTextToHapticPattern->convertTextToHapticEvents,convertTextToMorseMap->convertTextToModel,String.toMorseMap->toMorseModel,String.toHapticPattern->toHapticEvents. HapticModel.hapticDurationsis replaced byevents, withtoVibrationPattern()andtotalDurationalongside it. The JSON shape changed accordingly:hapticDurations: [100, 300]becomesevents: [{"type": "dot", "duration": 100}, ...].HapticMorse()is now parameterless andconst; it is always valid, so it needs no validation. All customization moved toHapticMorse.custom, which throwsArgumentErrorwhen a map and its reference differ in length, a reference repeats a character, a pattern is empty or uses characters other than the configured dot and dash, or a duration is not positive. 1.x accepted all of these and silently dropped letters from the output.- Choosing custom dot/dash symbols now re-spells whichever built-in map you did
not override, so
HapticMorse.custom(symbolReference: '0')keeps the standard alphabet rather than rejecting it. - The string extensions take an optional
HapticMorseinstead of repeating eleven parameters on each method:'SOS'.toMorseString(HapticMorse.custom(dotDuration: 80)). convertTextToMorseStringreturnsnull- not''- when the input holds no mappable characters, making its contract consistent.- Character lookup uses a map built once at construction rather than scanning reference strings per character.
- Added
charactersas a dependency. - CI runs the core test suite on the plain Dart SDK
(
dart test --exclude-tags flutter), which fails if anything in the core starts importing Flutter. - Supplying
charMapwithoutcharReference(or either numeric counterpart) now throws instead of silently pairing the custom map against the default reference and encoding the wrong characters. HapticModelcopies theeventslist it is given, so later changes to the caller's list no longer reach the model. This is why the main constructor is no longerconst; useHapticModel.emptywhere a constant is needed.- Analysis moved to
very_good_analysis, withalways_use_package_importsdisabled and the reason documented inanalysis_options.yaml. vibrationbumped to^3.2.0. Its pattern convention was re-verified against 3.2.0's Android and (newly Swift-Package-Manager-based) iOS sources before the bump; index 0 is still an off delay.- Added
metaas a dependency; the value types are now@immutable. - The example is self-verifying. It reconstructs the message from the raw vibration pattern using only the platform off/on convention and none of this package's types, so it is independent evidence rather than a restatement of the encoder. It also demonstrates the 1.x inversion instead of describing it: the same durations without the leading zero decode to "UEED" rather than "SOS". Eight assertions in total; the program exits non-zero if any fails, and CI runs it on every push.
test/readme_test.dartchecks that the example output quoted in README.md is still what the example prints, in the same order, so the documentation cannot drift from the code.- Documentation and example output use plain ASCII: no emoji, no em dashes, no arrow or check-mark glyphs. Emoji remain only in tests, where they are the data under test for non-BMP grapheme handling.
- Line coverage is 100% and CI fails below it. The two lines previously uncovered were an assert's interpolated failure message, which is executable code that only runs when the assert fails and so can never be covered; making the message constant reaches 100% without excluding a line or dropping the check.
1.0.6 #
Correctness and tooling release. Haptic pattern output is unchanged - the pattern rework is deliberately deferred to 2.0.0 (see Known issues).
Fixed #
HapticModelnow implements==,hashCode, andtoString. Instances with equal fields previously compared unequal, which brokeexpect, set/map membership, andBlocBuilder/distinct()deduplication.HapticModel.fromMapaccepts durations encoded as anynuminstead of throwing aTypeErrorwhen JSON supplies doubles ([100.0, 300.0]).HapticModel.hapticDurationsreturns an unmodifiable view. Callers could previously mutate the model's internal list in place.- A custom
numericReferencecontaining a regex metacharacter (for example() no longer throws aFormatException. Character lookup no longer builds aRegExpat all. - Custom numeric lookups are now consistently case-insensitive. The old code
upper-cased the generated pattern but tested the raw character against it,
so a custom reference such as
'AB'never matched lowercase input. - CI now runs on the Flutter SDK. The previous
dart teststep could not load any test file, so every push since 1.0.3 was merged unverified. Formatting and--fatal-infosanalysis are enforced.
Changed #
platforms:now declares android and ios only.package:vibrationships plugin implementations for those two platforms, so the previous macos/linux/windows entries advertised support that could not work.- Character lookup no longer compiles a
RegExpper character. - README corrected: the default-usage and extension examples did not compile,
convertTextToMorseMapwas documented as returning aMapwith ahapticCountkey that has never existed, and the emoji-mapping section described behaviour the package does not have. - Generated
doc/apioutput is no longer tracked or published. It shipped in the tarball and documented a private member removed by this release; pub.dev builds its own API docs. example_flutter/is excluded from the published archive via.pubignore. pub.dev only rendersexample/, so the demo app shipped to every consumer without ever being displayed. It remains in the repository.- The published archive is now 14 KB, down from roughly 800 KB in 1.0.5.
coverage/is now git-ignored.
Known issues (fixed in 2.0.0) #
- Haptic patterns are phase-inverted.
vibrationtreats index0ofpatternas an off delay; generated patterns start with an on duration, so symbols and gaps play swapped. Workaround: prepend0. - Consecutive spaces emit adjacent gap values, breaking off/on alternation for the remainder of the pattern.
- A leading space emits a spurious word gap; a trailing unsupported character emits a dangling letter gap.
- Characters outside the Basic Multilingual Plane (most emoji) cannot be used
in
charReference. - The package cannot be used from plain Dart, because the top-level export
pulls in
package:vibrationand thereforedart:ui.
1.0.5 #
- Integrated HapticModel to facilitate interaction
1.0.4 #
- Updated dependencies.
1.0.3 #
- String extension class to facilitate accessibility and string manipulation directly.
1.0.2 #
- Integrated custom symbol reference.
1.0.1 #
- Custom numeric regex validation
1.0.0 #
- HapticMorse release.