Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The package is available from

## 1.1 Consolidate Android Login

+ Update dependency and use file_picker v12.x [1.0.37]
+ Updated list of known solid servers [1.0.35 20260902 gjw]
+ Streamline login logout [1.0.34 20260828 anushkavidanage]
+ Session storage for web security key [1.0.33 20260819 gjw]
Expand Down
45 changes: 24 additions & 21 deletions example/lib/features/file_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ library;
import 'package:flutter/material.dart';

import 'package:file_picker/file_picker.dart';
import 'package:path/path.dart' as path;
import 'package:solidpod/solidpod.dart';
import 'package:solidui/solidui.dart' show SolidScaffold;

Expand Down Expand Up @@ -167,10 +168,10 @@ class _FileServiceState extends State<FileService> {
Widget build(BuildContext context) {
final browseButton = ElevatedButton(
onPressed: () async {
final result = await FilePicker.pickFiles();
if (result != null) {
final file = await FilePicker.pickFile();
if (file != null) {
setState(() {
uploadFile = result.files.single.path!;
uploadFile = file.path;
uploadDone = false;
uploadPercent = 0.0;
});
Expand Down Expand Up @@ -234,10 +235,10 @@ class _FileServiceState extends State<FileService> {

final browseSharedButton = ElevatedButton(
onPressed: () async {
final result = await FilePicker.pickFiles();
if (result != null) {
final file = await FilePicker.pickFile();
if (file != null) {
setState(() {
uploadSharedFile = result.files.single.path!;
uploadSharedFile = file.path;
uploadSharedDone = false;
uploadSharedPercent = 0.0;
});
Expand Down Expand Up @@ -315,17 +316,17 @@ class _FileServiceState extends State<FileService> {
deleteInProgress)
? null
: () async {
String? outputFile = await FilePicker.saveFile(
dialogTitle: 'Please set the output file:',
// fileName: 'download.bin',
final dirPath = await FilePicker.getDirectoryPath(
dialogTitle: 'Choose a directory to save file',
);

if (outputFile == null) {
if (dirPath == null) {
// User canceled the picker
debugPrint('Download is cancelled');
} else {
final localFilePath = path.join(dirPath, getRemoteFileName());
setState(() {
downloadFile = outputFile;
downloadFile = localFilePath;
});
try {
// remoteFileUrl ??= await getRemoteFileUrl();
Expand All @@ -335,7 +336,7 @@ class _FileServiceState extends State<FileService> {

await readLargeFile(
remoteFilePath: getRemoteFileName(),
localFilePath: outputFile,
localFilePath: localFilePath,
onProgress: (received, total) {
setState(() {
downloadDone = received == total;
Expand Down Expand Up @@ -375,21 +376,17 @@ class _FileServiceState extends State<FileService> {
deleteInProgress)
? null
: () async {
String? outputFile = await FilePicker.saveFile(
dialogTitle: 'Please set the output file:',
final dirPath = await FilePicker.getDirectoryPath(
dialogTitle: 'Choose a directory to save file',
);
if (outputFile == null) {
if (dirPath == null) {
// User canceled the picker
debugPrint('Download is cancelled');
} else {
setState(() {
downloadSharedFile = outputFile;
downloadSharedInProgress = true;
});
try {
setState(() {
downloadSharedInProgress = true;
});

final sharedFileUrl = sharedUrlController.text.trim();
if (sharedFileUrl.isEmpty) {
final msg = 'Shared file URL is empty';
Expand All @@ -411,10 +408,16 @@ class _FileServiceState extends State<FileService> {
.getRange(3, uri.pathSegments.length)
.join('/');

final localFilePath = path.join(dirPath, fileName);

setState(() {
downloadSharedFile = localFilePath;
});

if (context.mounted) {
await readLargeFile(
remoteFilePath: fileName,
localFilePath: outputFile,
localFilePath: localFilePath,
ownerWebId: ownerWebId,
onProgress: (received, total) {
setState(() {
Expand Down
11 changes: 6 additions & 5 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ environment:

dependencies:
editable: ^2.0.0
file_picker: ^11.0.2
file_picker: ^12.1.3
flutter:
sdk: flutter
intl: ^0.20.2
intl: ^0.20.3
markdown_tooltip: ^0.0.10
rdflib: ^0.2.12
solidpod: ^1.0.17
path: ^1.9.1
rdflib: ^0.2.13
solidpod: ^1.0.19
solidui:
path: ..
universal_io: ^2.3.1
window_manager: ^0.5.1
window_manager: ^0.5.2

dev_dependencies:
flutter_lints: ^6.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@

library;

import 'package:flutter/material.dart';

import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:markdown_tooltip/markdown_tooltip.dart';
import 'package:material_ui/material_ui.dart';

import 'package:solidui/src/constants/initial_setup.dart';

Expand Down
78 changes: 35 additions & 43 deletions lib/src/utils/solid_file_operations_download.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
library;

import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';

Expand Down Expand Up @@ -159,18 +158,6 @@ class SolidFileDownloadOperations {

if (!context.mounted) return;

// Let user choose where to save the file.

final cleanFileName = fileName.replaceAll('.enc.ttl', '');
String? outputFile = await FilePicker.saveFile(
dialogTitle: 'Save file as:',
fileName: cleanFileName,
);

if (outputFile == null) return;

if (!context.mounted) return;

// Show loading dialog via a controller, so it can always be torn
// down in the `finally` block — even if the originating context
// becomes unmounted while the download is in flight.
Expand Down Expand Up @@ -209,16 +196,25 @@ class SolidFileDownloadOperations {
}

// Save decrypted content to file.
// Let user choose where to save the file.

await _saveDecryptedContent(fileContent, outputFile);
final cleanFileName = fileName.replaceAll('.enc.ttl', '');
final outputFileUri = await FilePicker.saveFile(
dialogTitle: 'Save file as:',
fileName: cleanFileName,
bytes: utf8.encode(fileContent),
);

if (outputFileUri == null) return;

if (!context.mounted) return;

// Show success message.

ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('File downloaded successfully to $outputFile'),
content:
Text('File downloaded successfully to ${outputFileUri.path}'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 3),
),
Expand Down Expand Up @@ -254,23 +250,23 @@ class SolidFileDownloadOperations {

/// Save decrypted content to a file.

static Future<void> _saveDecryptedContent(
String content,
String outputPath,
) async {
final file = File(outputPath);
// static Future<void> _saveDecryptedContent(
// String content,
// String outputPath,
// ) async {
// final file = File(outputPath);

try {
// Try to decode as base64 (for binary files).
// try {
// // Try to decode as base64 (for binary files).

final bytes = base64Decode(content);
await file.writeAsBytes(bytes);
} catch (e) {
// If base64 decode fails, treat as text content.
// final bytes = base64Decode(content);
// await file.writeAsBytes(bytes);
// } catch (e) {
// // If base64 decode fails, treat as text content.

await file.writeAsString(content);
}
}
// await file.writeAsString(content);
// }
// }

/// Download a mixed batch of files and/or directories from the POD as a
/// single zip archive.
Expand Down Expand Up @@ -313,17 +309,6 @@ class SolidFileDownloadOperations {

if (!context.mounted) return;

// Let the user choose where to save the zip file.

final outputFile = await FilePicker.saveFile(
dialogTitle: 'Save zip as:',
fileName: zipFileName,
);

if (outputFile == null) return;

if (!context.mounted) return;

// Get security key if required.

await getKeyFromUserIfRequired(
Expand Down Expand Up @@ -392,8 +377,15 @@ class SolidFileDownloadOperations {
}

// Write zip to the selected output path.
// Let the user choose where to save the zip file.

final outputFileUri = await FilePicker.saveFile(
dialogTitle: 'Save zip as:',
fileName: zipFileName,
bytes: result.zipBytes,
);

await File(outputFile).writeAsBytes(result.zipBytes);
if (outputFileUri == null) return;

if (!context.mounted) return;

Expand All @@ -409,8 +401,8 @@ class SolidFileDownloadOperations {
final summary = parts.join(', ');

final successMsg = result.failed.isEmpty
? 'Downloaded $summary to $outputFile'
: 'Downloaded $summary to $outputFile '
? 'Downloaded $summary to ${outputFileUri.path}'
: 'Downloaded $summary to ${outputFileUri.path} '
'(${result.failed.length} could not be read)';

ScaffoldMessenger.of(context).showSnackBar(
Expand Down
13 changes: 6 additions & 7 deletions lib/src/utils/solid_file_operations_upload.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
library;

import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';

Expand Down Expand Up @@ -84,14 +83,15 @@ class SolidFileUploadOperations {
// one is provided.

final result = hasRestriction
? await FilePicker.pickFiles(
? await FilePicker.pickFile(
type: FileType.custom,
allowedExtensions: sanitisedExtensions,
)
: await FilePicker.pickFiles();
if (result == null || result.files.isEmpty) return;
if (result == null) return;
if (result is List && result.isEmpty) return;

final file = result.files.first;
PlatformFile file = result is List ? result.first : result;
if (file.path == null) return;

// Defensive client-side check in case the underlying picker on a given
Expand Down Expand Up @@ -129,15 +129,14 @@ class SolidFileUploadOperations {
);

try {
final localFile = File(file.path!);
String fileContent;

// Read file content.
final bytes = await file.readAsBytes();

if (isTextFile(file.path!)) {
fileContent = await localFile.readAsString();
fileContent = utf8.decode(bytes);
} else {
final bytes = await localFile.readAsBytes();
fileContent = base64Encode(bytes);
}

Expand Down
3 changes: 1 addition & 2 deletions lib/src/widgets/secret_text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@

library;

import 'package:flutter/material.dart';

import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:material_ui/material_ui.dart';

import 'package:solidui/src/constants/ui.dart';

Expand Down
Loading
Loading