Каркас приложения: авторизация, зоны/устройства/правила, управление устройствами
HTTP-клиент к /api/v1 с Sanctum-токеном (хранится в secure storage), модели зеркалят Laravel API Resources. Экраны: логин, список устройств с живым статусом, детальная страница устройства (история телеметрии, turn-on/turn-off/set-level с проверкой capability), списки зон и правил автоматизации (пока только чтение — формы создания/редактирования впереди).
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import '../models/automation_rule.dart';
|
||||
import '../models/device.dart';
|
||||
import '../models/device_type.dart';
|
||||
import '../models/zone.dart';
|
||||
import 'api_client.dart';
|
||||
|
||||
/// Typed wrappers for every `/api/v1` endpoint besides auth (see
|
||||
/// [AuthService] for login/logout/me). One method per backend action —
|
||||
/// no generic "request" escape hatch, so call sites stay self-documenting.
|
||||
class ApiService {
|
||||
ApiService(this._client);
|
||||
|
||||
final ApiClient _client;
|
||||
|
||||
// --- Zones ---
|
||||
|
||||
Future<List<Zone>> zones() async {
|
||||
final json = await _client.get('/zones');
|
||||
return _list(json).map(Zone.fromJson).toList();
|
||||
}
|
||||
|
||||
Future<Zone> createZone({required String name, String? description}) async {
|
||||
final json = await _client.post('/zones', {
|
||||
'name': name,
|
||||
if (description != null && description.isNotEmpty) 'description': description,
|
||||
});
|
||||
return Zone.fromJson(json['data'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<Zone> updateZone(int id, {required String name, String? description}) async {
|
||||
final json = await _client.put('/zones/$id', {
|
||||
'name': name,
|
||||
if (description != null && description.isNotEmpty) 'description': description,
|
||||
});
|
||||
return Zone.fromJson(json['data'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<void> deleteZone(int id) => _client.delete('/zones/$id');
|
||||
|
||||
// --- Device types ---
|
||||
|
||||
Future<List<DeviceType>> deviceTypes() async {
|
||||
final json = await _client.get('/device-types');
|
||||
return _list(json).map(DeviceType.fromJson).toList();
|
||||
}
|
||||
|
||||
// --- Devices ---
|
||||
|
||||
Future<List<Device>> devices() async {
|
||||
final json = await _client.get('/devices');
|
||||
return _list(json).map(Device.fromJson).toList();
|
||||
}
|
||||
|
||||
Future<DeviceDetail> device(int id) async {
|
||||
final json = await _client.get('/devices/$id');
|
||||
return DeviceDetail.fromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<Device> createDevice({
|
||||
required int zoneId,
|
||||
required int deviceTypeId,
|
||||
required String name,
|
||||
required String externalId,
|
||||
String protocol = 'mqtt',
|
||||
}) async {
|
||||
final json = await _client.post('/devices', {
|
||||
'zone_id': zoneId,
|
||||
'device_type_id': deviceTypeId,
|
||||
'name': name,
|
||||
'external_id': externalId,
|
||||
'protocol': protocol,
|
||||
});
|
||||
return Device.fromJson(json['data'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<Device> updateDevice(
|
||||
int id, {
|
||||
required int zoneId,
|
||||
required int deviceTypeId,
|
||||
required String name,
|
||||
required String externalId,
|
||||
String protocol = 'mqtt',
|
||||
}) async {
|
||||
final json = await _client.put('/devices/$id', {
|
||||
'zone_id': zoneId,
|
||||
'device_type_id': deviceTypeId,
|
||||
'name': name,
|
||||
'external_id': externalId,
|
||||
'protocol': protocol,
|
||||
});
|
||||
return Device.fromJson(json['data'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<void> deleteDevice(int id) => _client.delete('/devices/$id');
|
||||
|
||||
Future<String> turnOn(int deviceId) => _commandMessage(_client.post('/devices/$deviceId/turn-on'));
|
||||
|
||||
Future<String> turnOff(int deviceId) => _commandMessage(_client.post('/devices/$deviceId/turn-off'));
|
||||
|
||||
Future<String> setLevel(int deviceId, double level) =>
|
||||
_commandMessage(_client.post('/devices/$deviceId/set-level', {'level': level}));
|
||||
|
||||
Future<String> _commandMessage(Future<dynamic> request) async {
|
||||
final json = await request;
|
||||
return (json as Map<String, dynamic>)['message'] as String? ?? 'Готово.';
|
||||
}
|
||||
|
||||
// --- Automation rules ---
|
||||
|
||||
Future<List<AutomationRule>> automationRules() async {
|
||||
final json = await _client.get('/automation-rules');
|
||||
return _list(json).map(AutomationRule.fromJson).toList();
|
||||
}
|
||||
|
||||
Future<AutomationRule> createAutomationRule(Map<String, dynamic> payload) async {
|
||||
final json = await _client.post('/automation-rules', payload);
|
||||
return AutomationRule.fromJson(json['data'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<AutomationRule> updateAutomationRule(int id, Map<String, dynamic> payload) async {
|
||||
final json = await _client.put('/automation-rules/$id', payload);
|
||||
return AutomationRule.fromJson(json['data'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<void> deleteAutomationRule(int id) => _client.delete('/automation-rules/$id');
|
||||
|
||||
List<Map<String, dynamic>> _list(dynamic json) =>
|
||||
List<Map<String, dynamic>>.from((json as Map<String, dynamic>)['data'] as List);
|
||||
}
|
||||
Reference in New Issue
Block a user