feat: GeViScope SDK integration with C# Bridge and Flutter app
- Add GeViScope Bridge (C# .NET 8.0) on port 7720 - Full SDK wrapper for camera control, PTZ, actions/events - 17 REST API endpoints for GeViScope server interaction - Support for MCS (Media Channel Simulator) with 16 test channels - Real-time action/event streaming via PLC callbacks - Add GeViServer Bridge (C# .NET 8.0) on port 7710 - Integration with GeViSoft orchestration layer - Input/output control and event management - Update Python API with new routers - /api/geviscope/* - Proxy to GeViScope Bridge - /api/geviserver/* - Proxy to GeViServer Bridge - /api/excel/* - Excel import functionality - Add Flutter app GeViScope integration - GeViScopeRemoteDataSource with 17 API methods - GeViScopeBloc for state management - GeViScopeScreen with PTZ controls - App drawer navigation to GeViScope - Add SDK documentation (extracted from PDFs) - GeViScope SDK docs (7 parts + action reference) - GeViSoft SDK docs (12 chunks) - Add .mcp.json for Claude Code MCP server config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -81,18 +81,24 @@ class SecureStorageManager {
|
||||
|
||||
Future<String?> getUsername() async {
|
||||
try {
|
||||
return await storage.read(key: 'username');
|
||||
final username = await storage.read(key: 'username');
|
||||
if (username != null) return username;
|
||||
} catch (e) {
|
||||
throw CacheException('Failed to read username');
|
||||
print('Warning: Failed to read username from secure storage, using memory');
|
||||
}
|
||||
// Fallback to memory storage (which now uses localStorage on web)
|
||||
return TokenManager().username;
|
||||
}
|
||||
|
||||
Future<String?> getUserRole() async {
|
||||
try {
|
||||
return await storage.read(key: 'user_role');
|
||||
final role = await storage.read(key: 'user_role');
|
||||
if (role != null) return role;
|
||||
} catch (e) {
|
||||
throw CacheException('Failed to read user role');
|
||||
print('Warning: Failed to read user role from secure storage, using memory');
|
||||
}
|
||||
// Fallback to memory storage (which now uses localStorage on web)
|
||||
return TokenManager().userRole;
|
||||
}
|
||||
|
||||
// Clear all data
|
||||
|
||||
@@ -25,7 +25,8 @@ abstract class ServerLocalDataSource {
|
||||
Future<void> markServerAsSynced(String id, String type);
|
||||
|
||||
/// Replace all servers (used after fetching from API)
|
||||
Future<void> replaceAllServers(List<ServerModel> servers);
|
||||
/// If force=true, discards all local changes and replaces with fresh data
|
||||
Future<void> replaceAllServers(List<ServerModel> servers, {bool force = false});
|
||||
|
||||
/// Clear all local data
|
||||
Future<void> clearAll();
|
||||
@@ -127,27 +128,38 @@ class ServerLocalDataSourceImpl implements ServerLocalDataSource {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> replaceAllServers(List<ServerModel> servers) async {
|
||||
Future<void> replaceAllServers(List<ServerModel> servers, {bool force = false}) async {
|
||||
final b = await box;
|
||||
|
||||
// Don't clear dirty servers - keep them for sync
|
||||
final dirtyServers = await getDirtyServers();
|
||||
final dirtyKeys = dirtyServers.map((s) => _getKey(s.id, s.serverType)).toSet();
|
||||
if (force) {
|
||||
// Force mode: discard all local changes and replace with fresh data
|
||||
await b.clear();
|
||||
|
||||
// Clear only non-dirty servers
|
||||
await b.clear();
|
||||
|
||||
// Re-add dirty servers
|
||||
for (final dirty in dirtyServers) {
|
||||
await b.put(_getKey(dirty.id, dirty.serverType), dirty);
|
||||
}
|
||||
|
||||
// Add all fetched servers (but don't overwrite dirty ones)
|
||||
for (final server in servers) {
|
||||
final key = _getKey(server.id, server.serverType);
|
||||
if (!dirtyKeys.contains(key)) {
|
||||
// Add all fetched servers
|
||||
for (final server in servers) {
|
||||
final key = _getKey(server.id, server.serverType);
|
||||
await b.put(key, ServerHiveModel.fromServerModel(server));
|
||||
}
|
||||
} else {
|
||||
// Normal mode: preserve dirty servers for sync
|
||||
final dirtyServers = await getDirtyServers();
|
||||
final dirtyKeys = dirtyServers.map((s) => _getKey(s.id, s.serverType)).toSet();
|
||||
|
||||
// Clear all servers
|
||||
await b.clear();
|
||||
|
||||
// Re-add dirty servers
|
||||
for (final dirty in dirtyServers) {
|
||||
await b.put(_getKey(dirty.id, dirty.serverType), dirty);
|
||||
}
|
||||
|
||||
// Add all fetched servers (but don't overwrite dirty ones)
|
||||
for (final server in servers) {
|
||||
final key = _getKey(server.id, server.serverType);
|
||||
if (!dirtyKeys.contains(key)) {
|
||||
await b.put(key, ServerHiveModel.fromServerModel(server));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user