form done

This commit is contained in:
RafayAhmad7548 2025-07-22 14:35:22 +05:00
parent 02dc3e5757
commit bd8884787d
10 changed files with 200 additions and 28 deletions

View file

@ -1,5 +1,7 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:fluxcloud/user.dart';
class AddServerModal extends StatefulWidget { class AddServerModal extends StatefulWidget {
const AddServerModal({ const AddServerModal({
@ -20,6 +22,7 @@ class _AddServerModalState extends State<AddServerModal> {
bool _fileSelected = false; bool _fileSelected = false;
bool _showPassword = false; bool _showPassword = false;
final Connection _connection = Connection();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -38,7 +41,7 @@ class _AddServerModalState extends State<AddServerModal> {
spacing: 16, spacing: 16,
children: [ children: [
Text( Text(
'Add Server', 'Add Connection',
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle(fontSize: 18), style: TextStyle(fontSize: 18),
), ),
@ -46,7 +49,16 @@ class _AddServerModalState extends State<AddServerModal> {
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Host', labelText: 'Host',
), ),
validator: (value) => value == null || value.isEmpty ? 'This value is required' : null validator: (value) {
if (value == null || value.isEmpty) {
return 'This value is required';
}
if (!RegExp(r'^(([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,})|(\d{1,3}(\.\d{1,3}){3})$').hasMatch(value)) {
return 'Please enter a valid host';
}
return null;
},
onSaved: (value) => _connection.host = value,
), ),
TextFormField( TextFormField(
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
@ -61,22 +73,25 @@ class _AddServerModalState extends State<AddServerModal> {
return 'Please enter a valid port'; return 'Please enter a valid port';
} }
return null; return null;
} },
onSaved: (value) => _connection.port = int.parse(value!),
), ),
TextFormField( TextFormField(
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Username', labelText: 'Username',
), ),
validator: (value) => value == null || value.isEmpty ? 'This value is required' : null validator: (value) => value == null || value.isEmpty ? 'This value is required' : null,
onSaved: (value) => _connection.username = value,
), ),
TextFormField( TextFormField(
controller: _privateKeyFileController, controller: _privateKeyFileController,
readOnly: true, readOnly: true,
onTap: () async { onTap: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(); final XFile? result = await openFile();
if (result != null) { if (result != null) {
setState(() => _fileSelected = true); setState(() => _fileSelected = true);
_privateKeyFileController.text = result.files.single.name; _privateKeyFileController.text = result.name;
_connection.privateKeyFilePath = result.path;
} }
}, },
decoration: InputDecoration( decoration: InputDecoration(
@ -112,13 +127,23 @@ class _AddServerModalState extends State<AddServerModal> {
return 'At least provide one of these'; return 'At least provide one of these';
} }
return null; return null;
}
),
ElevatedButton(
onPressed: () {
_formKey.currentState?.validate();
}, },
child: Text('Submit') onSaved: (value) => _connection.password = value,
),
ElevatedButton(
onPressed: () async {
if (_formKey.currentState?.validate() == true) {
_formKey.currentState?.save();
assert(_connection.assertComplete());
final storage = FlutterSecureStorage();
await storage.write(key: _connection.host!, value: _connection.toJson);
if (context.mounted) {
Navigator.pop(context);
}
}
},
child: Text('Add Connection')
) )
], ],
) )

36
lib/user.dart Normal file
View file

@ -0,0 +1,36 @@
import 'dart:convert';
class Connection {
String? host;
int? port;
String? username;
String? privateKeyFilePath;
String? password;
Connection();
Connection.fromJson(Map<String, dynamic> json) {
host = json['host'];
port = json['port'];
username = json['username'];
privateKeyFilePath = json['privateKeyFilePath)'];
password = json['password'];
}
String get toJson => jsonEncode({
'host': host,
'port': port,
'username': username,
'privateKeyFilePath': privateKeyFilePath,
'password': password
});
bool assertComplete() {
assert(host != null);
assert(port != null);
assert(username != null);
assert(privateKeyFilePath != null || password != null);
return true;
}
}

View file

@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);

View file

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
flutter_secure_storage_linux flutter_secure_storage_linux
) )

View file

@ -5,12 +5,12 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import file_picker import file_selector_macos
import flutter_secure_storage_macos import flutter_secure_storage_macos
import path_provider_foundation import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
} }

View file

@ -65,14 +65,70 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
file_picker: file_selector:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_selector
sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.2.0" version: "1.0.3"
file_selector_android:
dependency: transitive
description:
name: file_selector_android
sha256: "6bba3d590ee9462758879741abc132a19133600dd31832f55627442f1ebd7b54"
url: "https://pub.dev"
source: hosted
version: "0.5.1+14"
file_selector_ios:
dependency: transitive
description:
name: file_selector_ios
sha256: "94b98ad950b8d40d96fee8fa88640c2e4bd8afcdd4817993bd04e20310f45420"
url: "https://pub.dev"
source: hosted
version: "0.5.3+1"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
url: "https://pub.dev"
source: hosted
version: "0.9.3+2"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711"
url: "https://pub.dev"
source: hosted
version: "0.9.4+3"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.dev"
source: hosted
version: "2.6.2"
file_selector_web:
dependency: transitive
description:
name: file_selector_web
sha256: c4c0ea4224d97a60a7067eca0c8fd419e708ff830e0c83b11a48faf566cec3e7
url: "https://pub.dev"
source: hosted
version: "0.9.4+2"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.dev"
source: hosted
version: "0.9.3+4"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -86,14 +142,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "5.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
url: "https://pub.dev"
source: hosted
version: "2.0.28"
flutter_secure_storage: flutter_secure_storage:
dependency: "direct main" dependency: "direct main"
description: description:
@ -152,6 +200,22 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
http:
dependency: transitive
description:
name: http
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -341,6 +405,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.4" version: "0.7.4"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:

View file

@ -9,7 +9,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
file_picker: ^10.2.0 file_selector: ^1.0.3
flutter_secure_storage: ^9.2.4 flutter_secure_storage: ^9.2.4
dev_dependencies: dev_dependencies:

30
test/widget_test.dart Normal file
View file

@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fluxcloud/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}

View file

@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h> #include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FlutterSecureStorageWindowsPluginRegisterWithRegistrar( FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
} }

View file

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
flutter_secure_storage_windows flutter_secure_storage_windows
) )