diff --git a/android/app/build.gradle b/android/app/build.gradle index 00b4db9..21d123a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion flutter.compileSdkVersion + compileSdkVersion 33 ndkVersion flutter.ndkVersion compileOptions { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9a9f474..6ae3f95 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,7 @@ + + host; + final Future port; + final Future username; + final Future password; + final Future initialPath; SftpClient? sftpClient; SSHClient? sshClient; @@ -31,8 +31,8 @@ class SSHDataProvider extends DataProvider { if (sshClient != null && !sshClient!.isClosed) return; sshClient = SSHClient( - await SSHSocket.connect(host, port), - username: username, + await SSHSocket.connect(await host, await port), + username: await username, onPasswordRequest: () => password, ); await sshClient?.authenticated; @@ -45,7 +45,8 @@ class SSHDataProvider extends DataProvider { await connect(); if (sftpClient == null) throw const FormatException(""); - final dir = uri != null ? Directory.fromUri(uri) : Directory(initialPath); + final dir = + uri != null ? Directory.fromUri(uri) : Directory(await initialPath); final items = await sftpClient!.listdir(dir.path); List res = []; diff --git a/lib/home_page.dart b/lib/home_page.dart index df0d881..dd95a42 100644 --- a/lib/home_page.dart +++ b/lib/home_page.dart @@ -1,8 +1,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:gallery/data_provider/data_provider.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:gallery/image_grid.dart'; +import 'package:gallery/settings_page.dart'; import 'package:path_provider/path_provider.dart'; import 'data_provider/local_data_provider.dart'; @@ -17,7 +18,7 @@ class MyHomePage extends StatefulWidget { State createState() => _MyHomePageState(); } -enum Page { local, remote } +enum Page { local, remote, settings } class _MyHomePageState extends State { Page page = Page.local; @@ -34,19 +35,27 @@ class _MyHomePageState extends State { } Widget _buildPage() { - DataProvider provider; - switch (page) { case Page.local: - provider = LocalDataProvider(_getLocalDir()); - break; + return ImageGrid(dProvider: LocalDataProvider(_getLocalDir())); case Page.remote: // todo do not generate a new provider on each tab switch - provider = SSHDataProvider( - initialPath: "/", host: "", password: "", port: 0, username: ""); - break; + const storage = FlutterSecureStorage(); + + return ImageGrid( + dProvider: SSHDataProvider( + initialPath: + Future.value("/media/3TBRaid/3TBRaid/Bilder/2022/"), + host: (() async => (await storage.read(key: "host")) ?? "") + .call(), + password: + (() async => (await storage.read(key: "pwd")) ?? "").call(), + port: Future.value(22), + username: (() async => (await storage.read(key: "user")) ?? "") + .call())); + case Page.settings: + return const SettingsPage(); } - return ImageGrid(dProvider: provider); } @override @@ -84,6 +93,15 @@ class _MyHomePageState extends State { Navigator.pop(context); }, ), + ListTile( + title: const Text('Settings'), + onTap: () { + setState(() { + page = Page.settings; + }); + Navigator.pop(context); + }, + ), ], ), ), diff --git a/lib/image_grid.dart b/lib/image_grid.dart index 28e35c1..f2d87de 100644 --- a/lib/image_grid.dart +++ b/lib/image_grid.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'data_provider/data_provider.dart'; @@ -41,13 +43,15 @@ class _ImageGridState extends State { gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisSpacing: 0, mainAxisSpacing: 0, - crossAxisCount: width ~/ 300, + crossAxisCount: + Platform.isAndroid ? width ~/ 100 : width ~/ 300, ), itemCount: data.items.length + 1, itemBuilder: (context, index) { if (index == 0) { return ImageTile( - child: const Icon(Icons.arrow_back, size: 142), + child: Icon(Icons.arrow_back, + size: Platform.isAndroid ? 64 : 142), onClick: () { setState(() { folder = widget.dProvider.listOfFiles(uri: data.parent); @@ -93,7 +97,8 @@ class _ImageGridState extends State { ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.folder_open, size: 142), + Icon(Icons.folder_open, + size: Platform.isAndroid ? 64 : 142), Text(elem.name) ], ) diff --git a/lib/main.dart b/lib/main.dart index 590a78b..89ea439 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,21 @@ +import 'dart:io'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'home_page.dart'; -void main() { - runApp(const MyApp()); +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + if (Platform.isAndroid) { + if (await Permission.storage.request().isGranted) { + runApp(const MyApp()); + } + } else { + runApp(const MyApp()); + } } class AppScrollBehavior extends MaterialScrollBehavior { diff --git a/lib/settings_page.dart b/lib/settings_page.dart new file mode 100644 index 0000000..96ace2b --- /dev/null +++ b/lib/settings_page.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SettingsPage extends StatefulWidget { + const SettingsPage({Key? key}) : super(key: key); + + @override + State createState() => _SettingsPageState(); +} + +class _SettingsPageState extends State { + late TextEditingController _controllerHost; + late TextEditingController _controllerUser; + late TextEditingController _controllerPwd; + + @override + void initState() { + super.initState(); + _controllerHost = TextEditingController(); + _controllerUser = TextEditingController(); + _controllerPwd = TextEditingController(); + + const storage = FlutterSecureStorage(); + storage + .read(key: "host") + .then((value) => _controllerHost.text = value ?? ""); + storage + .read(key: "user") + .then((value) => _controllerUser.text = value ?? ""); + storage.read(key: "pwd").then((value) => _controllerPwd.text = value ?? ""); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(5), + child: Column( + children: [ + const SizedBox( + height: 10, + ), + TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: "host"), + controller: _controllerHost, + ), + const SizedBox( + height: 5, + ), + TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: "user"), + controller: _controllerUser, + ), + const SizedBox( + height: 5, + ), + TextField( + obscureText: true, + decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: "password"), + controller: _controllerPwd, + ), + const SizedBox( + height: 5, + ), + TextButton( + onPressed: () { + const storage = FlutterSecureStorage(); + storage.write(key: "host", value: _controllerHost.value.text); + storage.write(key: "user", value: _controllerUser.value.text); + storage.write(key: "pwd", value: _controllerPwd.value.text); + }, + child: const Text("Save")) + ], + ), + ); + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..d0e7f79 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + 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 2e1de87..b29e9ba 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_secure_storage_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/pubspec.lock b/pubspec.lock index 0e9d731..173023d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -111,11 +111,58 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" intl: dependency: transitive description: @@ -214,6 +261,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.3" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + url: "https://pub.dartlang.org" + source: hosted + version: "10.0.2" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + url: "https://pub.dartlang.org" + source: hosted + version: "10.0.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.4" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "3.8.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" pinenacl: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5ed2419..cf4f8b2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,8 @@ dependencies: cupertino_icons: ^1.0.2 path_provider: ^2.0.11 dartssh2: ^2.7.2+3 + permission_handler: ^10.0.2 + flutter_secure_storage: ^6.0.0 dev_dependencies: flutter_test: