diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..66082a0 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,39 @@ +image: cirrusci/flutter + +stages: + - build + +flutter_build_android: #Job name + stage: build # kind of job + before_script: + - flutter packages get + - flutter clean + script: + - flutter build apk --target-platform android-arm64 + artifacts: + paths: + - build/app/outputs/apk/release/app-release.apk + +linux_build: + stage: build + script: + - apt-get update + - apt-get install -y --no-install-recommends cmake ninja-build clang build-essential pkg-config libgtk-3-dev liblzma-dev lcov libvlc-dev vlc libsecret-1-dev libjsoncpp-dev + - flutter config --enable-linux-desktop + - flutter packages get + - flutter build linux + artifacts: + paths: + - build/linux/x64/release/bundle/* + + +flutter_lint: + stage: build + script: + - flutter format . --output none --set-exit-if-changed + +flutter_analyze: + stage: build + script: + - flutter analyze ./lib + diff --git a/lib/data_provider/data_provider.dart b/lib/data_provider/data_provider.dart index 47b1aae..986bb02 100644 --- a/lib/data_provider/data_provider.dart +++ b/lib/data_provider/data_provider.dart @@ -16,7 +16,6 @@ class Folder { Folder(this.items, this.self, this.parent); } - abstract class DataProvider { final List validSuffix = [".jpg", ".jpeg", ".png"]; diff --git a/lib/data_provider/ssh_data_provider.dart b/lib/data_provider/ssh_data_provider.dart index 937c58e..62daa31 100644 --- a/lib/data_provider/ssh_data_provider.dart +++ b/lib/data_provider/ssh_data_provider.dart @@ -1,5 +1,4 @@ import 'dart:io'; -import 'dart:typed_data'; import 'package:dartssh2/dartssh2.dart'; import 'package:flutter/cupertino.dart'; @@ -8,6 +7,8 @@ import 'package:gallery/data_provider/data_provider.dart'; 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; @@ -48,6 +49,8 @@ class SSHDataProvider extends DataProvider { final items = await sftpClient!.listdir(dir.path); List res = []; for (final val in items) { + if (val.filename == "." || val.filename == "..") continue; + if (validSuffix.any((suff) => val.filename.endsWith(suff))) { res.add(Item(false, Uri.file(dir.path + val.filename), val.filename)); } else if (val.attr.isDirectory) { @@ -56,6 +59,10 @@ class SSHDataProvider extends DataProvider { } } + res.sort( + (a, b) => b.isFolder ? 1 : -1, + ); + return Folder(res, dir.uri, dir.parent.uri); } @@ -66,13 +73,8 @@ class SSHDataProvider extends DataProvider { } class _SSHImageProvider extends ImageProvider<_SSHImageProvider> { - /// Creates an object that decodes a [File] as an image. - /// - /// The arguments must not be null. - const _SSHImageProvider(this.uri, this.sftpClient, {this.scale = 1.0}) - : assert(scale != null); + const _SSHImageProvider(this.uri, this.sftpClient, {this.scale = 1.0}); - /// The file to decode into an image. final Uri uri; final SftpClient sftpClient; @@ -113,14 +115,27 @@ class _SSHImageProvider extends ImageProvider<_SSHImageProvider> { DecoderBufferCallback? decode, DecoderCallback? decodeDeprecated) async { assert(key == this); - final file = await sftpClient.open(uri.toFilePath()); - // todo do not load whole image in ram, create tempfile instead. - final Uint8List bytes = await file.readBytes(); + Directory tempDir = await getTemporaryDirectory(); + String tempPath = "${tempDir.path}/gallery"; + // check if temp file exists + Uint8List bytes; + final File tmpPic = File(tempPath + uri.toFilePath()); + if (await tmpPic.exists()) { + // use temp file + bytes = await tmpPic.readAsBytes(); + } else { + final file = await sftpClient.open(uri.toFilePath()); + // todo do not load whole image in ram, create tempfile instead. + bytes = await file.readBytes(); + await tmpPic.create(recursive: true); + await tmpPic.writeAsBytes(bytes); + } if (bytes.lengthInBytes == 0) { // The file may become available later. PaintingBinding.instance.imageCache.evict(key); - throw StateError('$file is empty and cannot be loaded as an image.'); + throw StateError( + 'bytes are empty is empty and cannot be loaded as an image.'); } if (decode != null) { diff --git a/lib/full_screen_image_view.dart b/lib/full_screen_image_view.dart index 93877a0..13a69f2 100644 --- a/lib/full_screen_image_view.dart +++ b/lib/full_screen_image_view.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/lib/image_tile.dart b/lib/image_tile.dart index 6a3ab4d..81211d5 100644 --- a/lib/image_tile.dart +++ b/lib/image_tile.dart @@ -1,10 +1,10 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:gallery/data_provider/data_provider.dart'; class ImageTile extends StatelessWidget { - const ImageTile({Key? key, this.onClick, this.child, this.imageUri, this.dtaProvider}) : super(key: key); + const ImageTile( + {Key? key, this.onClick, this.child, this.imageUri, this.dtaProvider}) + : super(key: key); final Function? onClick; final Widget? child; final Uri? imageUri; @@ -16,26 +16,26 @@ class ImageTile extends StatelessWidget { onTap: () { onClick?.call(); }, - child: Container(padding: const EdgeInsets.all(5), child: Container( - decoration: imageUri == null - ? const BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.all(Radius.circular(10.0)), - boxShadow: [ - BoxShadow( - color: Colors.black12, - spreadRadius: 2.0, - blurRadius: 5.0), - ]) - : BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: dtaProvider!.getImageProvider(imageUri!), - ), - ), - child: child - )), + child: Container( + padding: const EdgeInsets.all(5), + child: Container( + decoration: imageUri == null + ? const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10.0)), + boxShadow: [ + BoxShadow( + color: Colors.black12, + spreadRadius: 2.0, + blurRadius: 5.0), + ]) + : BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: dtaProvider!.getImageProvider(imageUri!), + ), + ), + child: child)), ); } } diff --git a/lib/main.dart b/lib/main.dart index 13a4677..590a78b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,9 +11,9 @@ void main() { class AppScrollBehavior extends MaterialScrollBehavior { @override Set get dragDevices => { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }; + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + }; } class MyApp extends StatelessWidget { @@ -31,4 +31,3 @@ class MyApp extends StatelessWidget { ); } } -