diff --git a/lib/add_server_modal.dart b/lib/add_server_modal.dart index 076a769..d2810bd 100644 --- a/lib/add_server_modal.dart +++ b/lib/add_server_modal.dart @@ -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_secure_storage/flutter_secure_storage.dart'; +import 'package:fluxcloud/user.dart'; class AddServerModal extends StatefulWidget { const AddServerModal({ @@ -20,6 +22,7 @@ class _AddServerModalState extends State { bool _fileSelected = false; bool _showPassword = false; + final Connection _connection = Connection(); @override Widget build(BuildContext context) { @@ -38,7 +41,7 @@ class _AddServerModalState extends State { spacing: 16, children: [ Text( - 'Add Server', + 'Add Connection', textAlign: TextAlign.left, style: TextStyle(fontSize: 18), ), @@ -46,7 +49,16 @@ class _AddServerModalState extends State { decoration: InputDecoration( 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( keyboardType: TextInputType.number, @@ -61,22 +73,25 @@ class _AddServerModalState extends State { return 'Please enter a valid port'; } return null; - } + }, + onSaved: (value) => _connection.port = int.parse(value!), ), TextFormField( decoration: InputDecoration( 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( controller: _privateKeyFileController, readOnly: true, onTap: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles(); + final XFile? result = await openFile(); if (result != null) { setState(() => _fileSelected = true); - _privateKeyFileController.text = result.files.single.name; + _privateKeyFileController.text = result.name; + _connection.privateKeyFilePath = result.path; } }, decoration: InputDecoration( @@ -112,13 +127,23 @@ class _AddServerModalState extends State { return 'At least provide one of these'; } 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') ) ], ) diff --git a/lib/user.dart b/lib/user.dart new file mode 100644 index 0000000..f3e9a05 --- /dev/null +++ b/lib/user.dart @@ -0,0 +1,36 @@ +import 'dart:convert'; + +class Connection { + String? host; + int? port; + String? username; + String? privateKeyFilePath; + String? password; + + Connection(); + + Connection.fromJson(Map 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; + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index d0e7f79..85a2413 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include 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 = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b29e9ba..62e3ed5 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux flutter_secure_storage_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index ce7cca6..5d35054 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,12 @@ import FlutterMacOS import Foundation -import file_picker +import file_selector_macos import flutter_secure_storage_macos import path_provider_foundation 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")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 4d6e84e..e7b2f4d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -65,14 +65,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - file_picker: + file_selector: dependency: "direct main" description: - name: file_picker - sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a + name: file_selector + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" url: "https://pub.dev" 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: dependency: "direct main" description: flutter @@ -86,14 +142,6 @@ packages: url: "https://pub.dev" source: hosted 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: dependency: "direct main" description: @@ -152,6 +200,22 @@ packages: description: flutter source: sdk 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: dependency: transitive description: @@ -341,6 +405,14 @@ packages: url: "https://pub.dev" source: hosted 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: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5c9e013..853979e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - file_picker: ^10.2.0 + file_selector: ^1.0.3 flutter_secure_storage: ^9.2.4 dev_dependencies: diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..dca0eae --- /dev/null +++ b/test/widget_test.dart @@ -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); + }); +} diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 0c50753..b53f20e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,12 @@ #include "generated_plugin_registrant.h" +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 4fc759c..2b9f993 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows flutter_secure_storage_windows )