add settings page so set ssh login
request storage permissions on android
This commit is contained in:
		@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="eu.heili.gallery">
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 | 
			
		||||
   <application
 | 
			
		||||
        android:label="gallery"
 | 
			
		||||
        android:name="${applicationName}"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,11 @@ class Item {
 | 
			
		||||
  String name;
 | 
			
		||||
 | 
			
		||||
  Item(this.isFolder, this.uri, this.name);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() {
 | 
			
		||||
    return 'Item{isFolder: $isFolder, uri: $uri, name: $name}';
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Folder {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,11 @@ import 'dart:ui' as ui show Codec, ImmutableBuffer;
 | 
			
		||||
import 'package:path_provider/path_provider.dart';
 | 
			
		||||
 | 
			
		||||
class SSHDataProvider extends DataProvider {
 | 
			
		||||
  final String host;
 | 
			
		||||
  final int port;
 | 
			
		||||
  final String username;
 | 
			
		||||
  final String password;
 | 
			
		||||
  final String initialPath;
 | 
			
		||||
  final Future<String> host;
 | 
			
		||||
  final Future<int> port;
 | 
			
		||||
  final Future<String> username;
 | 
			
		||||
  final Future<String> password;
 | 
			
		||||
  final Future<String> 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<Item> res = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -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<MyHomePage> createState() => _MyHomePageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum Page { local, remote }
 | 
			
		||||
enum Page { local, remote, settings }
 | 
			
		||||
 | 
			
		||||
class _MyHomePageState extends State<MyHomePage> {
 | 
			
		||||
  Page page = Page.local;
 | 
			
		||||
@@ -34,19 +35,27 @@ class _MyHomePageState extends State<MyHomePage> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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<MyHomePage> {
 | 
			
		||||
                Navigator.pop(context);
 | 
			
		||||
              },
 | 
			
		||||
            ),
 | 
			
		||||
            ListTile(
 | 
			
		||||
              title: const Text('Settings'),
 | 
			
		||||
              onTap: () {
 | 
			
		||||
                setState(() {
 | 
			
		||||
                  page = Page.settings;
 | 
			
		||||
                });
 | 
			
		||||
                Navigator.pop(context);
 | 
			
		||||
              },
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
 
 | 
			
		||||
@@ -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<ImageGrid> {
 | 
			
		||||
              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<ImageGrid> {
 | 
			
		||||
                        ? Column(
 | 
			
		||||
                            mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                            children: [
 | 
			
		||||
                              const Icon(Icons.folder_open, size: 142),
 | 
			
		||||
                              Icon(Icons.folder_open,
 | 
			
		||||
                                  size: Platform.isAndroid ? 64 : 142),
 | 
			
		||||
                              Text(elem.name)
 | 
			
		||||
                            ],
 | 
			
		||||
                          )
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								lib/settings_page.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								lib/settings_page.dart
									
									
									
									
									
										Normal file
									
								
							@@ -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<SettingsPage> createState() => _SettingsPageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _SettingsPageState extends State<SettingsPage> {
 | 
			
		||||
  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"))
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,6 +6,10 @@
 | 
			
		||||
 | 
			
		||||
#include "generated_plugin_registrant.h"
 | 
			
		||||
 | 
			
		||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
list(APPEND FLUTTER_PLUGIN_LIST
 | 
			
		||||
  flutter_secure_storage_linux
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user