Add import/export functionality for keymap profiles

Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-10-09 19:32:46 +00:00
parent 45112ccfcf
commit 0e5f6ef2dd
2 changed files with 130 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:dartx/dartx.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:swift_control/bluetooth/devices/zwift_clickv2.dart';
import 'package:swift_control/main.dart';
import 'package:swift_control/pages/touch_area.dart';
@@ -284,6 +285,55 @@ ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : ''
},
child: Text('Manage Profile'),
),
if (actionHandler.supportedApp is CustomApp)
ElevatedButton(
onPressed: () async {
final currentProfile = (actionHandler.supportedApp as CustomApp).profileName;
final jsonData = settings.exportCustomAppProfile(currentProfile);
if (jsonData != null) {
await Clipboard.setData(ClipboardData(text: jsonData));
if (mounted) {
_snackBarMessengerKey.currentState!.showSnackBar(
SnackBar(
content: Text('Profile "$currentProfile" exported to clipboard'),
duration: Duration(seconds: 2),
),
);
}
}
},
child: Text('Export Profile'),
),
ElevatedButton(
onPressed: () async {
final jsonData = await _showImportDialog();
if (jsonData != null && jsonData.isNotEmpty) {
final success = await settings.importCustomAppProfile(jsonData);
if (mounted) {
if (success) {
_snackBarMessengerKey.currentState!.showSnackBar(
SnackBar(
content: Text('Profile imported successfully'),
duration: Duration(seconds: 2),
),
);
setState(() {});
} else {
_snackBarMessengerKey.currentState!.showSnackBar(
SnackBar(
content: Text('Failed to import profile. Invalid format.'),
duration: Duration(seconds: 2),
backgroundColor: Colors.red,
),
);
}
}
}
},
child: Text('Import Profile'),
),
],
),
if (actionHandler.supportedApp != null)
@@ -468,4 +518,51 @@ ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : ''
),
);
}
Future<String?> _showImportDialog() async {
final controller = TextEditingController();
// Try to get data from clipboard
try {
final clipboardData = await Clipboard.getData('text/plain');
if (clipboardData?.text != null) {
controller.text = clipboardData!.text!;
}
} catch (e) {
// Ignore clipboard errors
}
return showDialog<String>(
context: context,
builder: (context) => AlertDialog(
title: Text('Import Profile'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Paste the exported JSON data below:'),
SizedBox(height: 16),
TextField(
controller: controller,
decoration: InputDecoration(
labelText: 'JSON Data',
border: OutlineInputBorder(),
),
maxLines: 5,
autofocus: true,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context, controller.text),
child: Text('Import'),
),
],
),
);
}
}

View File

@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:dartx/dartx.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -100,6 +102,37 @@ class Settings {
await _prefs.setStringList('customapp_$newProfileName', sourceData);
}
}
String? exportCustomAppProfile(String profileName) {
final data = _prefs.getStringList('customapp_$profileName');
if (data == null) return null;
// Export as JSON with metadata
return jsonEncode({
'version': 1,
'profileName': profileName,
'keymap': data,
});
}
Future<bool> importCustomAppProfile(String jsonData, {String? newProfileName}) async {
try {
final decoded = jsonDecode(jsonData);
// Validate the structure
if (decoded['version'] == null || decoded['keymap'] == null) {
return false;
}
final profileName = newProfileName ?? decoded['profileName'] ?? 'Imported';
final keymap = List<String>.from(decoded['keymap']);
await _prefs.setStringList('customapp_$profileName', keymap);
return true;
} catch (e) {
return false;
}
}
String? getLastSeenVersion() {
return _prefs.getString('last_seen_version');