add settings page so set ssh login
request storage permissions on android
This commit is contained in:
parent
2ba9fb3fbd
commit
369da56258
@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
|||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion flutter.compileSdkVersion
|
compileSdkVersion 33
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="eu.heili.gallery">
|
package="eu.heili.gallery">
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<application
|
<application
|
||||||
android:label="gallery"
|
android:label="gallery"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
@ -6,6 +6,11 @@ class Item {
|
|||||||
String name;
|
String name;
|
||||||
|
|
||||||
Item(this.isFolder, this.uri, this.name);
|
Item(this.isFolder, this.uri, this.name);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Item{isFolder: $isFolder, uri: $uri, name: $name}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Folder {
|
class Folder {
|
||||||
|
@ -10,11 +10,11 @@ import 'dart:ui' as ui show Codec, ImmutableBuffer;
|
|||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
class SSHDataProvider extends DataProvider {
|
class SSHDataProvider extends DataProvider {
|
||||||
final String host;
|
final Future<String> host;
|
||||||
final int port;
|
final Future<int> port;
|
||||||
final String username;
|
final Future<String> username;
|
||||||
final String password;
|
final Future<String> password;
|
||||||
final String initialPath;
|
final Future<String> initialPath;
|
||||||
|
|
||||||
SftpClient? sftpClient;
|
SftpClient? sftpClient;
|
||||||
SSHClient? sshClient;
|
SSHClient? sshClient;
|
||||||
@ -31,8 +31,8 @@ class SSHDataProvider extends DataProvider {
|
|||||||
if (sshClient != null && !sshClient!.isClosed) return;
|
if (sshClient != null && !sshClient!.isClosed) return;
|
||||||
|
|
||||||
sshClient = SSHClient(
|
sshClient = SSHClient(
|
||||||
await SSHSocket.connect(host, port),
|
await SSHSocket.connect(await host, await port),
|
||||||
username: username,
|
username: await username,
|
||||||
onPasswordRequest: () => password,
|
onPasswordRequest: () => password,
|
||||||
);
|
);
|
||||||
await sshClient?.authenticated;
|
await sshClient?.authenticated;
|
||||||
@ -45,7 +45,8 @@ class SSHDataProvider extends DataProvider {
|
|||||||
await connect();
|
await connect();
|
||||||
if (sftpClient == null) throw const FormatException("");
|
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);
|
final items = await sftpClient!.listdir(dir.path);
|
||||||
List<Item> res = [];
|
List<Item> res = [];
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
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/image_grid.dart';
|
||||||
|
import 'package:gallery/settings_page.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
import 'data_provider/local_data_provider.dart';
|
import 'data_provider/local_data_provider.dart';
|
||||||
@ -17,7 +18,7 @@ class MyHomePage extends StatefulWidget {
|
|||||||
State<MyHomePage> createState() => _MyHomePageState();
|
State<MyHomePage> createState() => _MyHomePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Page { local, remote }
|
enum Page { local, remote, settings }
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
Page page = Page.local;
|
Page page = Page.local;
|
||||||
@ -34,19 +35,27 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPage() {
|
Widget _buildPage() {
|
||||||
DataProvider provider;
|
|
||||||
|
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case Page.local:
|
case Page.local:
|
||||||
provider = LocalDataProvider(_getLocalDir());
|
return ImageGrid(dProvider: LocalDataProvider(_getLocalDir()));
|
||||||
break;
|
|
||||||
case Page.remote:
|
case Page.remote:
|
||||||
// todo do not generate a new provider on each tab switch
|
// todo do not generate a new provider on each tab switch
|
||||||
provider = SSHDataProvider(
|
const storage = FlutterSecureStorage();
|
||||||
initialPath: "/", host: "", password: "", port: 0, username: "");
|
|
||||||
break;
|
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
|
@override
|
||||||
@ -84,6 +93,15 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
Navigator.pop(context);
|
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 'package:flutter/material.dart';
|
||||||
import 'data_provider/data_provider.dart';
|
import 'data_provider/data_provider.dart';
|
||||||
|
|
||||||
@ -41,13 +43,15 @@ class _ImageGridState extends State<ImageGrid> {
|
|||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisSpacing: 0,
|
crossAxisSpacing: 0,
|
||||||
mainAxisSpacing: 0,
|
mainAxisSpacing: 0,
|
||||||
crossAxisCount: width ~/ 300,
|
crossAxisCount:
|
||||||
|
Platform.isAndroid ? width ~/ 100 : width ~/ 300,
|
||||||
),
|
),
|
||||||
itemCount: data.items.length + 1,
|
itemCount: data.items.length + 1,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return ImageTile(
|
return ImageTile(
|
||||||
child: const Icon(Icons.arrow_back, size: 142),
|
child: Icon(Icons.arrow_back,
|
||||||
|
size: Platform.isAndroid ? 64 : 142),
|
||||||
onClick: () {
|
onClick: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
folder = widget.dProvider.listOfFiles(uri: data.parent);
|
folder = widget.dProvider.listOfFiles(uri: data.parent);
|
||||||
@ -93,7 +97,8 @@ class _ImageGridState extends State<ImageGrid> {
|
|||||||
? Column(
|
? Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.folder_open, size: 142),
|
Icon(Icons.folder_open,
|
||||||
|
size: Platform.isAndroid ? 64 : 142),
|
||||||
Text(elem.name)
|
Text(elem.name)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
|
import 'dart:io';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
import 'home_page.dart';
|
import 'home_page.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
if (await Permission.storage.request().isGranted) {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
runApp(const MyApp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class AppScrollBehavior extends MaterialScrollBehavior {
|
class AppScrollBehavior extends MaterialScrollBehavior {
|
||||||
@override
|
@override
|
||||||
|
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 "generated_plugin_registrant.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) 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
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
flutter_secure_storage_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
82
pubspec.lock
82
pubspec.lock
@ -111,11 +111,58 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
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:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
intl:
|
intl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -214,6 +261,41 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
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:
|
pinenacl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -38,6 +38,8 @@ dependencies:
|
|||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
path_provider: ^2.0.11
|
path_provider: ^2.0.11
|
||||||
dartssh2: ^2.7.2+3
|
dartssh2: ^2.7.2+3
|
||||||
|
permission_handler: ^10.0.2
|
||||||
|
flutter_secure_storage: ^6.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user