Files
sepot/app/lib/widgets/pin_keypad.dart
T
Julius Joska 8081d98c67 Šepot — end-to-end encrypted messenger
Initial public release. Anonymous on-device identity (no phone number,
e-mail, or password), Signal-protocol cryptography (X3DH + PQXDH, Double
Ratchet, sealed sender) via libsignal, a metadata-minimizing relay,
group chats, disappearing messages, encrypted local storage, optional
Tor transport, and a UI localized into Czech, English, German, Russian,
and Italian.

Monorepo: Flutter client (app/), Rust relay + wire types (rust/),
protobuf definitions (proto/), self-host deploy (deploy/).

Licensed under AGPL-3.0 with an app-store distribution exception (§7).
2026-07-11 17:21:47 +02:00

113 lines
3.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// Numerická klávesnice pro PIN + řádek teček.
///
/// Vytaženo z `pin_setup_screen`, aby ji mohla použít i změna PINu.
/// Systémovou klávesnici záměrně nepoužíváme — nechceme, aby PIN prošel
/// IME (predikce, schránka, klávesnice třetích stran).
library;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sepot/core/theme/app_theme.dart';
class PinDots extends StatelessWidget {
const PinDots({super.key, required this.filled, this.length = 6});
final int filled;
final int length;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(length, (i) {
final on = i < filled;
return Container(
width: 16,
height: 16,
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: on ? SepotColors.ember : SepotColors.border,
border: Border.all(
color: on ? SepotColors.ember : SepotColors.border,
width: 2,
),
),
);
}),
);
}
}
class PinKeypad extends StatelessWidget {
const PinKeypad({super.key, required this.onKey, this.enabled = true});
/// Dostane číslici '0'–'9' nebo 'DEL'.
final void Function(String key) onKey;
final bool enabled;
@override
Widget build(BuildContext context) {
return Column(
children: [
for (final row in const [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
['', '0', 'DEL'],
])
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: row
.map((k) => k.isEmpty
? const SizedBox(width: 88, height: 64)
: _klavesa(k))
.toList(),
),
),
],
);
}
Widget _klavesa(String key) {
final delete = key == 'DEL';
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: InkWell(
onTap: enabled
? () {
HapticFeedback.lightImpact();
onKey(key);
}
: null,
borderRadius: BorderRadius.circular(32),
child: Container(
width: 64,
height: 64,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: delete ? Colors.transparent : SepotColors.surfaceVariant,
border: delete ? null : Border.all(color: SepotColors.border),
),
child: Center(
child: delete
? const Icon(Icons.backspace_outlined,
color: SepotColors.textSecondary, size: 24)
: Text(
key,
style: const TextStyle(
fontFamily: kFontSans,
fontSize: 24,
fontWeight: FontWeight.w500,
color: SepotColors.textPrimary,
),
),
),
),
),
);
}
}