scan_tally 0.1.1
scan_tally: ^0.1.1 copied to clipboard
Continuous barcode scanning for stock counts: duplicate filtering, tally sessions with undo, keyboard wedge scanners, GS1 parsing, check digits and feedback.
scan_tally #
Continuous barcode scanning for stock counts, goods receiving and shipping. During a count the user scans dozens of items in a row. scan_tally turns the raw reads of any scanner into counts:
- it filters duplicates;
- it gives feedback that works without looking at the screen;
- it handles hardware scanners that type like a keyboard;
- it keeps quantities with undo;
- it parses GS1 data.
The core has no camera dependency. The camera adapter is a separate package, scan_tally_mobile_scanner.
Features #
-
Duplicate filtering (
DedupePolicy):leaveAndReturn: a code counts again only after it has left the view. This is the natural way to count several items of the same product with a camera.cooldown: the same code within X ms is a duplicate.FrameConfirmation: a code must be read in N consecutive frames, so a single misread from a blurry image never counts.- EAN-13, EAN-8, UPC-A and UPC-E check digit validation (
CheckDigit).
-
Counting session (
ScanSession):- quantity per code; increment, decrement, set by hand, remove, clear;
undoLast()for any of these, scans included;- your own validator (e.g. "product not found"), synchronous or async;
toJson()/loadJson(); you choose where to store it;- an event stream:
ScanAccepted,ScanDuplicate,ScanRejected.
-
Feedback:
- separate sound and vibration patterns for accepted, duplicate and rejected;
- a short colored screen flash (
ScanFlash); - silent mode.
The beeps are generated by this package (see Sounds).
-
One API, any source (
ScanSource):- camera via
scan_tally_mobile_scanner; - keyboard wedge scanners (Zebra, Honeywell, USB/Bluetooth HID) via
KeyboardWedgeSource. Typed text never becomes a scan.
- camera via
-
GS1 parsing (
Gs1Parser):- GS1-128, GS1 DataMatrix, GS1 QR and DataBar element strings, and the
(01)…(17)…human readable form; - GTIN (01), lot (10), expiry (17), best before (15), serial (21), count (30/37), SSCC (00), measures (310n…) and more than 150 other AIs;
- FNC1/GS separators, variable-length fields, the day
00rule and the century rule for dates.
- GS1-128, GS1 DataMatrix, GS1 QR and DataBar element strings, and the
How it differs from existing packages #
| Need | Camera scanner plugins (mobile_scanner, barcode_scan2, simple_barcode_scanner) |
Wedge listeners (flutter_barcode_listener, barcode_keyboard_listener) |
flutter_datawedge |
gs1_barcode_parser |
scan_tally |
|---|---|---|---|---|---|
| Decode barcodes from the camera | yes | – | – | – | via adapter |
| Count once per item / per cooldown | – (mobile_scanner has noDuplicates, which never counts the same product twice in a row) |
– | – | – | yes |
| N-frame confirmation, check digits | – | – | – | – | yes |
| Counting session with undo and JSON | – | – | – | – | yes |
| Keyboard wedge without vendor SDK | – | yes (last releases 2023 and 2019) | Zebra intents only | – | yes, with prefix, suffix, custom terminator, TextField safety and an injectable clock |
| GS1 AI parsing | – | – | – | yes | yes (integrated with counting) |
| Feedback patterns, flash, silent mode | – | – | – | – | yes |
The other packages are good at what they do. scan_tally sits on top of a decoder and solves what every inventory app writes again: what counts, and how does the user know?
Installation #
dependencies:
scan_tally: ^0.1.0
scan_tally_mobile_scanner: ^0.1.0 # only if you use the camera
Usage #
import 'package:scan_tally/scan_tally_flutter.dart';
final session = ScanSession(
dedupe: const DedupePolicy.cooldown(Duration(milliseconds: 1500)),
confirmation: const FrameConfirmation(frames: 2),
feedback: const ScanFeedback(sound: true, vibrate: true),
feedbackPlayer: const FlutterScanFeedbackPlayer(),
validate: (code) => products.containsKey(code.value)
? ScanVerdict.accept
: const ScanVerdict.reject('Product not found'),
);
session.events.listen((event) {
switch (event) {
case ScanAccepted(:final entry):
print('${entry.key}: ${entry.quantity}');
case ScanDuplicate():
print('already counted');
case ScanRejected(:final message):
print('rejected: $message');
}
});
session.counts; // {'4006381333931': 3, ...}
session.undoLast(); // reverts the last scan or manual change
session.setQuantity('4006381333931', 12);
final json = session.toJson(); // store it where you like
Each read goes through four steps, in this order:
- Check digit. A wrong one from a keyboard scanner is a
ScanRejected. From a camera it is dropped silently as a misread, because the next frame usually reads it correctly. - Frame confirmation (cameras only).
- Duplicate filter. The result is either silent or a
ScanDuplicate. - Your validator. The result is a
ScanRejectedor aScanAccepted.
Frames are processed one at a time in arrival order, also with an async validator.
Camera #
import 'package:scan_tally_mobile_scanner/scan_tally_mobile_scanner.dart';
final controller = MobileScannerSource.createController(); // DetectionSpeed.normal, 150 ms
session.attach(MobileScannerSource(controller));
// in build: ScanFlash(session: session, child: MobileScanner(controller: controller))
Keyboard wedge (handheld terminal) #
final wedge = KeyboardWedgeSource(
config: const WedgeConfig(
maxKeyInterval: Duration(milliseconds: 50),
terminators: {WedgeTerminator.enter},
prefix: '', // optional
suffix: '', // optional
terminatorCharacters: {}, // e.g. {'#'} for a custom end character
),
);
session.attach(wedge);
// Around the counting screen; starts and stops the listener with the widget.
KeyboardWedgeListener(source: wedge, child: const CountScreen());
Counting GS1 cartons under their GTIN #
validate: (code) {
final gs1 = code.gs1; // null for non-GS1 codes
if (gs1?.gtin == null) return ScanVerdict.accept;
return ScanVerdict.acceptWith(key: gs1!.gtin, quantity: gs1.count ?? 1);
},
final data = Gs1Parser.parse(']C10109501101530003172612001' '0LOT42\u001D3712');
data.gtin; // 09501101530003
data.expiry; // 2026-12-31 (day 00 = end of month), dayUnspecified: true
data.batch; // LOT42
data.count; // 12
Design decisions and risks #
1. Camera dependency: core plus adapter #
Decision: one repository with two packages in a Dart pub workspace (no melos):
| Package | Contains | Dependencies |
|---|---|---|
scan_tally |
dedupe, session, GS1, check digits, wedge assembler, tones, feedback | Flutter SDK only |
scan_tally_mobile_scanner |
MobileScannerSource (≈ 100 lines) |
scan_tally, mobile_scanner |
package:scan_tally/scan_tally.dartis pure Dart: it imports nothing from Flutter. Use it in isolates, on a server or in plain unit tests.package:scan_tally/scan_tally_flutter.dartadds the Flutter layer: wedge listener, feedback player, flash and builder.
Why:
- Camera plugins change often (
mobile_scannerchanged its API several times). Apps that only use hardware scanners should not ship a camera plugin, ML Kit and camera permissions. - A source is just a stream of
ScanFrames (abstract interface class ScanSource), so another decoder takes a few lines to connect. SeeScanSourceControlleror the adapter's source.
Considered: a third package for the Flutter layer, so the core would not depend on the Flutter SDK. It was rejected for 0.1: the Flutter layer is small, uses no plugins, and a separate entry point already keeps the logic Flutter-free. It can be split later without breaking the pure library.
2. Keyboard wedge: tested without a real device #
Decision: the wedge logic is a pure state machine (WedgeAssembler) whose time is passed in, so tests control the clock.
How a scan is told apart from typing:
- A scan is a burst of keys, each at most
maxKeyIntervalapart (default 50 ms), that ends with a terminator (Enter, Tab or a custom character) within the same interval. - A person types at 100 ms or more per key. Enter pressed after slow typing therefore drops the burst.
- With a prefix or suffix configured, bursts without them are not scans.
idleTimeoutsupports scanners that send no terminator.
Interplay with the app:
KeyboardWedgeSourcelistens toHardwareKeyboard.- The first character of a burst cannot be told apart from typing, so it passes through. The rest of the burst is consumed.
- The terminator is consumed too.
KeyboardWedgeListeneralso stops it at the focus system, so the scanner's Enter does not press a focused button or move focus.
TextField safety:
- While an
EditableText(TextField) has focus, the listener stands aside (ignoreWhenEditing: true, the default). - Typed text is never taken for a scan, and a scan made into a focused field lands there, as users of hardware scanners expect.
- Set
ignoreWhenEditing: falseto capture scans everywhere.
Timing:
- Key event timestamps are used when the platform provides them, so a busy UI thread does not split a scan.
- Otherwise a monotonic
Stopwatch(injectable) is used.
Tests:
- unit tests: fast and slow typing, inclusive gap limit, Enter, Tab, custom and control terminators, prefix and suffix, min and max length, cut-off scans, idle timeout, GS characters;
- widget tests that send real key events through
HardwareKeyboard: Shift + capitals, Enter not pressing a focused button, a focusedTextFieldreceiving the text instead, enable/disable, idle timer, flow into aScanSession.
Not verified on a real Zebra or Honeywell device. The behavior is verified with simulated key events in tests, and with Android key events injected by
adb shell input keyeventon an emulator: they were joined into one scan at the default 50 ms limit. Please report results with your device model.
Recommended device settings:
| Zebra DataWedge | Honeywell (Scanner settings / Data Processing) | |
|---|---|---|
| Output | Profile for your app → Keystroke output: on, Intent output: off | Wedge method: Keyboard (also "Data Intent" off) |
| Terminator | Keystroke output → Basic data formatting → Send ENTER key (or Send TAB) | Suffix: Enter (\r / 0D), or Tab (09) |
| Speed | Keep the default inter-character delay (0 ms); if you add a delay, raise maxKeyInterval above it |
Keep the default wedge speed (fast) |
| Prefix/suffix (optional) | Basic data formatting → prefix/suffix to data | Prefix / Suffix fields |
| GS1 | Send FNC1 as GS (\u001D); Advanced data formatting can replace it |
"Transmit GS / FNC1" or a replacement character (use Gs1Parser.parse(..., separators: {'~'})) |
Both brands can also deliver scans as an Android broadcast intent (DataWedge Intent output, Honeywell Data Intent). This is more robust than keystrokes, and some packages such as flutter_datawedge use it. Intent support is planned for a later version as another ScanSource.
3. Sounds without license issues #
Decision: the beeps are synthesized by this package.
ScanTonesdefines sine tones:- accepted: one 2 kHz beep, 110 ms;
- duplicate: two 1.2 kHz beeps;
- rejected: a falling 620 → 440 Hz buzz.
ScanTones.renderWav()writes 16-bit mono PCM WAV with short fades.tool/generate_sounds.dartwritesassets/sounds/*.wavfrom these definitions, and a test checks that the committed files match the generator byte for byte. The sounds are therefore this package's own work under its MIT license.- You can also call
ScanTones.wavOf(kind)at runtime.
cd packages/scan_tally && dart run tool/generate_sounds.dart
Playing sound:
- The core has no audio dependency. Sound is behind the
ScanSoundPlayerinterface (andScanFeedbackPlayerfor everything). - The dependency-free default is
SystemScanSoundPlayer. It uses system click/alert sounds; on Android only the click exists, and only when touch sounds are on. - For real beeps, play the bundled WAVs with an audio plugin.
audioplayersin low latency mode (Android SoundPool) is light, maintained and suits short sounds:
class AudioplayersScanSoundPlayer implements ScanSoundPlayer {
final _players = {
for (final k in ScanFeedbackKind.values)
k: AudioPlayer()
..audioCache = AudioCache(prefix: '')
..setPlayerMode(PlayerMode.lowLatency),
};
@override
Future<void> play(ScanFeedbackKind kind) async {
final p = _players[kind]!;
await p.stop();
await p.play(AssetSource(ScanTones.assetKeyOf(kind)));
}
}
// FlutterScanFeedbackPlayer(sound: AudioplayersScanSoundPlayer())
Vibration:
- Flutter's built-in
HapticFeedbackis used (FlutterScanHaptics). It needs no plugin and no permission. - Default patterns:
- accepted: one medium pulse;
- duplicate: two light pulses;
- rejected: three long vibrations.
- It follows the system "touch feedback" setting. For stronger patterns felt through gloves, implement
ScanHapticswith a vibration plugin.
Silent mode (ScanFeedback.silent) mutes sound but keeps vibration and flash, like a phone's silent switch.
Example #
example/ is an Android app in English and Turkish, built with Material 3. It has four parts:
- Camera tab.
- Handheld tab:
- simulated scanner buttons that send real key events;
- a keyboard demo mode that accepts slow typing, for trying it on an emulator;
- a manual entry field that shows typed text is never a scan.
- Count list: +/−, set quantity, swipe to remove, clear, export JSON.
- Undo and GS1: undo in the app bar, and a breakdown of GS1 data for the last scan.
Limitations #
- Keyboard wedge is not tested on real Zebra or Honeywell devices (see above). Android intent output is not supported yet.
- The camera adapter has been compiled and unit tested, but not tried on a device in this release.
- The duplicate filter state is not saved by
toJson(). After a restore, the first read of a code counts as new.
Other packages #
More packages by the same author:
google_maps_polyline: Google Directions routes and polyline encode/decode (pure Dart)marker_crafter: Custom Google Maps markers drawn with Canvasanimated_route_marker: Smoothly animated map marker along a route or live GPSadvanced_background_locator: Background location tracking plugin (Android/iOS)advanced_geofence: Pure Dart geofencing engine: enter, exit and dwell eventsroute_simulator: Realistic fake GPS streams for testing and demosbackground_doctor: Diagnoses why background work stops on Android and why the app was killedscan_tally_mobile_scanner: mobile_scanner camera adapter for scan_tallyturkish_kit: Turkish validators, money in words, casing, provinces, holidays (pure Dart)turkish_kit_flutter: Flutter widgets for turkish_kit: Turkish money field and input formattersflutter_toastify: Animated toast notifications
License #
MIT. The bundled sounds are generated by tool/generate_sounds.dart and are covered by the same license.
Türkçe #
Stok sayımı, mal kabul ve sevkiyat için sürekli barkod okutma paketi. Sayımda kullanıcı art arda onlarca ürün okutur. scan_tally herhangi bir tarayıcının ham okumalarını adede çevirir:
- tekrarları ayıklar;
- ekrana bakmadan anlaşılan geri bildirim verir;
- klavye gibi çalışan el terminallerini destekler;
- adetleri geri alınabilir biçimde tutar;
- GS1 verisini çözer.
Çekirdeğin kamera bağımlılığı yoktur. Kamera adaptörü ayrı bir pakettir: scan_tally_mobile_scanner.
Özellikler #
-
Tekrar ayıklama (
DedupePolicy):leaveAndReturn: kod ancak görüntüden çıkıp geri gelince yeniden sayılır. Kamerayla aynı üründen birden fazla saymanın doğal yolu budur.cooldown: aynı kod X ms içinde tekrar gelirse tekrar sayılır.FrameConfirmation: kod art arda N karede görülmelidir. Böylece bulanık görüntüden gelen tek bir yanlış okuma asla sayılmaz.- EAN-13, EAN-8, UPC-A ve UPC-E kontrol hanesi doğrulaması (
CheckDigit).
-
Sayım oturumu (
ScanSession):- kod başına adet; artır, azalt, elle gir, sil, temizle;
- bunların hepsi için
undoLast(); okutmalar da geri alınabilir; - uygulamanın kendi doğrulama fonksiyonu (ör. "Ürün bulunamadı"), senkron ya da asenkron;
toJson()/loadJson(); nerede saklanacağına siz karar verirsiniz;- olay akışı:
ScanAccepted,ScanDuplicate,ScanRejected.
-
Geri bildirim:
- kabul, tekrar ve red için ayrı ses ve titreşim desenleri;
- kısa renkli ekran parlaması (
ScanFlash); - sessiz mod.
Bip sesleri paketin kendisi tarafından üretilir.
-
Tek API, her kaynak (
ScanSource):- kamera:
scan_tally_mobile_scanner; - el terminali:
KeyboardWedgeSource(Zebra, Honeywell, USB/Bluetooth HID). Elle yazılan metin hiçbir zaman tarama sayılmaz.
- kamera:
-
GS1 ayrıştırma (
Gs1Parser):- GS1-128, GS1 DataMatrix, GS1 QR ve DataBar verisi ile
(01)…(17)…okunur biçim; - GTIN (01), lot (10), son kullanma (17), tavsiye edilen tüketim (15), seri (21), adet (30/37), SSCC (00), ölçüler (310n…) ve 150'den fazla başka AI;
- FNC1/GS ayırıcısı, değişken uzunluklu alanlar, tarihte gün=00 kuralı ve yüzyıl kuralı.
- GS1-128, GS1 DataMatrix, GS1 QR ve DataBar verisi ile
Mevcut paketlerden farkı #
- Kamera tarayıcı eklentileri (
mobile_scanner,barcode_scan2,simple_barcode_scanner) yalnızca "barkod görüldü" bilgisini verir.mobile_scanner'ınnoDuplicatesmodu aynı ürünü art arda ikinci kez hiç saymaz.
- Klavye dinleyicileri (
flutter_barcode_listener,barcode_keyboard_listener):- son sürümleri 2023 ve 2019'dan;
- ön ek, son ek, özel bitiş karakteri ve TextField çakışması gibi konuları ele almaz.
flutter_datawedgeyalnızca Zebra'ya ve intent yoluna özeldir.gs1_barcode_parseryalnızca ayrıştırıcıdır.
scan_tally bir okuyucunun üstüne oturur ve her stok uygulamasının yeniden yazdığı soruyu çözer: Ne sayılır ve kullanıcı bunu nasıl anlar?
Kurulum ve kullanım #
Kurulum ve kod örnekleri için yukarıdaki İngilizce Installation ve Usage bölümlerine bakın. API aynıdır.
Her okuma şu dört adımdan sırayla geçer:
- Kontrol hanesi. El terminalinden gelen hatalı kontrol hanesi
ScanRejectedolur. Kameradan gelen ise yanlış okuma sayılıp sessizce atlanır, çünkü bir sonraki kare çoğunlukla doğru okur. - Kare teyidi (yalnızca kamera).
- Tekrar filtresi. Sonuç ya sessizdir ya da
ScanDuplicate. - Sizin doğrulama fonksiyonunuz. Sonuç
ScanRejectedya daScanAcceptedolur.
Tasarım kararları ve riskler #
1. Kamera bağımlılığı
Karar: bir depoda iki paket, Dart pub workspace ile (melos gerekmez).
scan_tally: ayıklama, oturum, GS1, kontrol hanesi, wedge birleştirici, ses üretimi ve geri bildirim. Kamera bağımlılığı yoktur.package:scan_tally/scan_tally.dartsaf Dart'tır, Flutter'dan hiçbir şey içe aktarmaz. İsolate'ta, sunucuda ve düz birim testlerinde kullanılabilir.- Flutter katmanı ayrı bir giriş noktasındadır:
scan_tally_flutter.dart.
scan_tally_mobile_scanner: yaklaşık 100 satırlık ince bir adaptör.
Neden:
- Kamera eklentileri sık değişir. Yalnızca el terminali kullanan bir uygulama kamera eklentisi, ML Kit ve kamera izni taşımamalıdır.
- Kaynak,
ScanFrameakışı veren soyut bir arayüzdür (ScanSource). Başka bir tarayıcı paketi birkaç satırla bağlanır.
Değerlendirilen alternatif: Flutter katmanı için üçüncü bir paket. 0.1 için gerekli görülmedi: Flutter katmanı küçüktür, eklenti kullanmaz ve ayrı giriş noktası mantığı zaten Flutter'dan bağımsız tutar.
2. El terminali testi
Karar: birleştirici (WedgeAssembler), zamanı dışarıdan verilen saf bir durum makinesidir.
Taramanın yazmadan ayrılması:
- Tarama, tuşları en fazla
maxKeyInterval(varsayılan 50 ms) arayla gelen ve aynı süre içinde bitiş karakteriyle (Enter, Tab ya da özel karakter) biten bir tuş dizisidir. - İnsan tuş başına 100 ms ve üzeri sürede yazar. Yavaş yazmanın ardından basılan Enter diziyi düşürür.
- Ön ek ya da son ek ayarlanmışsa, bunları taşımayan diziler tarama sayılmaz.
- Bitiş karakteri göndermeyen cihazlar için
idleTimeoutvardır.
Uygulamayla etkileşim:
- Dizinin ilk karakteri yazmadan ayırt edilemediği için geçer. Dizinin geri kalanı yutulur.
- Bitiş tuşu da yutulur.
KeyboardWedgeListeneronu odak sisteminde de durdurur; böylece tarayıcının Enter'ı odaktaki butona basmaz, Tab odağı kaydırmaz.
TextField çakışması:
- Bir
TextFieldodaktayken dinleyici devreden çıkar (ignoreWhenEditing: true, varsayılan). - Elle yazılan metin hiçbir zaman tarama sayılmaz. Odaktaki alana yapılan okutma, el terminali kullanıcılarının beklediği gibi alana yazılır.
Zamanlama: platform tuş olaylarına zaman damgası veriyorsa o kullanılır; böylece meşgul bir UI iş parçacığı taramayı bölmez. Vermiyorsa enjekte edilebilir monoton bir saat kullanılır.
Testler:
- birim testleri: hızlı ve yavaş yazma, Enter, Tab, özel ve kontrol karakteri ile bitiş, ön ek ve son ek, uzunluk sınırları, kesilen tarama, boşta kalma süresi, GS karakteri;
HardwareKeyboardüzerinden gerçek tuş olayları gönderen widget testleri: Shift ile büyük harf, odaktaki butona basılmaması, odaktakiTextField'ın metni alması, açma/kapama,ScanSession'a akış.
Gerçek bir Zebra ya da Honeywell cihazında doğrulanmadı. Davranış testlerde benzetilmiş tuş olaylarıyla, emülatörde de
adb shell input keyeventile gönderilen Android tuş olaylarıyla doğrulandı; bu olaylar varsayılan 50 ms sınırında tek bir taramaya birleşti. Cihaz modelinizle sonuç bildirirseniz seviniriz.
Önerilen cihaz ayarları:
- Zebra DataWedge: uygulamanıza özel profilde
- Keystroke output açık, Intent output kapalı;
- Basic data formatting → Send ENTER key (ya da TAB);
- karakterler arası gecikme varsayılan (0 ms) kalsın. Gecikme eklerseniz
maxKeyInterval'ı ondan büyük yapın.
- Honeywell:
- Wedge method: Keyboard, Data Intent kapalı;
- Suffix: Enter (
0D) ya da Tab (09); - wedge hızı varsayılan (hızlı) kalsın.
- GS1: FNC1'i GS (
\u001D) olarak gönderin. Başka bir karakterle değiştirildiyseGs1Parser.parse(..., separators: {'~'})kullanın.
Her iki marka okumaları Android broadcast intent ile de gönderebilir. Bu yol tuş vuruşundan daha sağlamdır; desteği ileriki bir sürümde ayrı bir ScanSource olarak planlanmaktadır.
3. Ses dosyaları
Karar: bip sesleri paketin kendisi tarafından üretilir.
ScanTonessinüs tonlarını tanımlar:- kabul: 2 kHz, 110 ms tek bip;
- tekrar: 1,2 kHz iki kısa bip;
- red: 620 → 440 Hz inen uğultu.
tool/generate_sounds.dartbu tanımlardanassets/sounds/*.wavdosyalarını üretir. Bir test, depodaki dosyaların betiğin çıktısıyla bayt bayt aynı olduğunu denetler. Sesler paketin kendi eseridir ve MIT kapsamındadır.- Sesi çalışma anında üretmek için
ScanTones.wavOf(kind)de kullanılabilir.
Ses çalma:
- Çekirdeğin ses bağımlılığı yoktur; çalma
ScanSoundPlayerarayüzünün arkasındadır. - Bağımlılıksız varsayılan
SystemScanSoundPlayer'dır ve sistem seslerini kullanır. Android'de yalnızca "tık" sesi vardır ve dokunma sesleri açıksa çalar. - Gerçek bip için paketle gelen WAV'ları bir ses eklentisiyle çalın. Örnek uygulama
audioplayers'ı düşük gecikme modunda (Android SoundPool) kullanır. Bu eklenti hafif ve bakımlıdır, kısa seslere uygundur. Örnek kod yukarıdaki İngilizce bölümde.
Titreşim:
- Flutter'ın yerleşik
HapticFeedbacközelliği kullanılır (FlutterScanHaptics). Eklenti ve izin gerekmez. - Desenler:
- kabul: bir orta darbe;
- tekrar: iki hafif darbe;
- red: üç uzun titreşim.
- Sistemdeki "dokunma geri bildirimi" ayarına uyar. Eldivenle hissedilecek güçlü desenler için
ScanHapticsarayüzünü bir titreşim eklentisiyle uygulayın.
Sessiz mod sesi kapatır, titreşim ve parlamayı korur.
Örnek uygulama #
example/, Türkçe ve İngilizce bir Android uygulamasıdır (Material 3). Dört bölümü vardır:
- Kamera sekmesi.
- El terminali sekmesi:
- gerçek tuş olayları gönderen taklit tarama düğmeleri;
- emülatörde klavyeyle denemek için yavaş yazmayı kabul eden "klavye deneme modu";
- elle yazılan metnin tarama sayılmadığını gösteren giriş alanı.
- Sayım listesi: +/−, adedi elle girme, kaydırarak silme, temizleme, JSON dışa aktarma.
- Geri alma ve GS1: uygulama çubuğunda geri alma ve son okutmanın GS1 dökümü.
Sınırlamalar #
- El terminali desteği gerçek Zebra veya Honeywell cihazında denenmedi. Android intent çıkışı henüz desteklenmiyor.
- Kamera adaptörü derlendi ve birim testlerinden geçti, ancak bu sürümde cihazda denenmedi.
- Tekrar filtresinin durumu
toJson()ile kaydedilmez. Geri yüklemeden sonra bir kodun ilk okuması yeni sayılır.
Diğer paketler #
Aynı geliştiricinin diğer paketleri:
google_maps_polyline: Google Directions rotası ve polyline kodlama/çözme (saf Dart)marker_crafter: Canvas ile çizilen özel Google Maps işaretçilerianimated_route_marker: Rota ya da canlı GPS üzerinde akıcı hareket eden harita işaretçisiadvanced_background_locator: Arka planda konum takibi eklentisi (Android/iOS)advanced_geofence: Saf Dart geofence motoru: giriş, çıkış ve bekleme olaylarıroute_simulator: Test ve demo için gerçekçi sahte GPS akışıbackground_doctor: Android'de arka plan işinin neden durduğunu ve uygulamanın neden kapandığını teşhis ederscan_tally_mobile_scanner: scan_tally için mobile_scanner kamera adaptörüturkish_kit: Türkçe doğrulayıcılar, tutarı yazıyla yazma, harf dönüşümü, il/ilçe, tatiller (saf Dart)turkish_kit_flutter: turkish_kit için Flutter bileşenleri: Türk biçimli para alanı ve girdi biçimleyicileriflutter_toastify: Animasyonlu toast bildirimleri
Lisans #
MIT. Paketle gelen sesler tool/generate_sounds.dart ile üretilir ve aynı lisans kapsamındadır.