feat: secure home credentials

This commit is contained in:
Artem Kokos
2026-04-22 23:25:48 +07:00
parent 6a961209cc
commit 7c0a2675c6
22 changed files with 1782 additions and 397 deletions

View File

@@ -23,8 +23,7 @@ class _GroupCardState extends ConsumerState<GroupCard> {
double? _localBrightness;
double? _localTemp;
int _channelValue(double channel) =>
(channel * 255.0).round().clamp(0, 255);
int _channelValue(double channel) => (channel * 255.0).round().clamp(0, 255);
@override
Widget build(BuildContext context) {
@@ -45,8 +44,12 @@ class _GroupCardState extends ConsumerState<GroupCard> {
// Цвет подсветки карточки зависит от режима и состояния
final cardAccent = isOn
? (_mode == 'temp'
? Color.lerp(Colors.orange, Colors.blueAccent, (tempValue - 2700) / 3800)!
: Color.fromARGB(255, r, gVal, b))
? Color.lerp(
Colors.orange,
Colors.blueAccent,
(tempValue - 2700) / 3800,
)!
: Color.fromARGB(255, r, gVal, b))
: Colors.white12;
return Card(
@@ -56,10 +59,7 @@ class _GroupCardState extends ConsumerState<GroupCard> {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
border: isOn
? Border.all(
color: cardAccent.withValues(alpha: 0.3),
width: 1,
)
? Border.all(color: cardAccent.withValues(alpha: 0.3), width: 1)
: null,
),
child: Padding(
@@ -84,9 +84,14 @@ class _GroupCardState extends ConsumerState<GroupCard> {
// Кнопка "таймер на 4 часа"
if (isOn)
IconButton(
icon: const Icon(Icons.timer, size: 20, color: Colors.white38),
icon: const Icon(
Icons.timer,
size: 20,
color: Colors.white38,
),
tooltip: 'Включить на 4 часа',
onPressed: () => ref.read(groupsProvider.notifier).setTimer4h(id),
onPressed: () =>
ref.read(groupsProvider.notifier).setTimer4h(id),
),
Switch(
value: isOn,
@@ -112,7 +117,9 @@ class _GroupCardState extends ConsumerState<GroupCard> {
activeColor: Colors.amber,
onChanged: (v) {
setState(() => _localBrightness = v);
ref.read(groupsProvider.notifier).setBrightness(id, v.toInt());
ref
.read(groupsProvider.notifier)
.setBrightness(id, v.toInt());
},
onChangeEnd: (v) {
setState(() => _localBrightness = null);
@@ -156,10 +163,15 @@ class _GroupCardState extends ConsumerState<GroupCard> {
divisions: 38, // шаг 100K
label: "${tempValue.toInt()}K",
activeColor: Color.lerp(
Colors.orange, Colors.blueAccent, (tempValue - 2700) / 3800),
Colors.orange,
Colors.blueAccent,
(tempValue - 2700) / 3800,
),
onChanged: (v) {
setState(() => _localTemp = v);
ref.read(groupsProvider.notifier).setTemperature(id, v.toInt());
ref
.read(groupsProvider.notifier)
.setTemperature(id, v.toInt());
},
onChangeEnd: (v) {
setState(() => _localTemp = null);
@@ -172,7 +184,9 @@ class _GroupCardState extends ConsumerState<GroupCard> {
initialColor: Color.fromARGB(255, r, gVal, b),
onColorChanged: (c) {
// Обновление UI-превью -- через debounce отправляется на сервер
ref.read(groupsProvider.notifier).setColor(
ref
.read(groupsProvider.notifier)
.setColor(
id,
_channelValue(c.r),
_channelValue(c.g),
@@ -279,7 +293,11 @@ class _ModeChip extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 14, color: selected ? Colors.deepOrange : Colors.white54),
Icon(
icon,
size: 14,
color: selected ? Colors.deepOrange : Colors.white54,
),
const SizedBox(width: 4),
Text(
label,
@@ -349,8 +367,10 @@ class _SceneSelectorState extends ConsumerState<_SceneSelector> {
sceneName = scene;
sceneId = scene;
} else if (scene is Map) {
sceneName = (scene['name'] ?? scene['id'] ?? scene.toString()).toString();
sceneId = (scene['id'] ?? scene['name'] ?? scene.toString()).toString();
sceneName = (scene['name'] ?? scene['id'] ?? scene.toString())
.toString();
sceneId = (scene['id'] ?? scene['name'] ?? scene.toString())
.toString();
} else {
sceneName = scene.toString();
sceneId = scene.toString();