Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5cda084
Add a popup to inform users that the file they are about to download …
tonypioneer Feb 5, 2026
6ef5cad
Fix the issue that uploaded file appears in the unexpected directory
tonypioneer Feb 5, 2026
9583f73
Refactor file-browsing code built upon basePath
tonypioneer Feb 5, 2026
2ccc3bc
Lint
tonypioneer Feb 5, 2026
5a01f4e
Add validation for absolute paths or empty path
tonypioneer Feb 6, 2026
4aca698
Merge branch 'dev' of https://github.com/anusii/solidui into tony/153…
tonypioneer Feb 6, 2026
551aaa1
Merge branch 'dev' of https://github.com/anusii/solidui into tony/154…
tonypioneer Feb 6, 2026
b6e5689
Use `pathType: PathType.relativeToPod` instead of `pathType: pathType…
tonypioneer Feb 6, 2026
3c43e1c
Remove basePath in utils folder
tonypioneer Feb 6, 2026
fe24889
Remove basePath in widgets folder
tonypioneer Feb 6, 2026
00a4e53
Remove basePath in widgets folder
tonypioneer Feb 6, 2026
b96c7bc
Lint
tonypioneer Feb 6, 2026
33dba75
Ensure the security key is available before writing encrypted data
tonypioneer Feb 6, 2026
7b57ad9
Change the input filePath to a file URL
tonypioneer Feb 6, 2026
60cfc23
Add an 'All POD Files' page
tonypioneer Feb 6, 2026
f54bb66
Revert filePath
tonypioneer Feb 6, 2026
f484dc8
Revert filePath
tonypioneer Feb 6, 2026
4b26351
Merge branch 'tony/153_refactor_file_browsing_code' of https://github…
tonypioneer Feb 8, 2026
0976de1
Replace basePath with currentPath
tonypioneer Feb 8, 2026
482db53
Refine the code
tonypioneer Feb 8, 2026
cc471ed
Add initialPath to enable browsing files on the root directory of the…
tonypioneer Feb 8, 2026
9f04472
Adjust the warning message
tonypioneer Feb 9, 2026
d3489ea
Merge branch 'dev' of https://github.com/anusii/solidui into tony/154…
tonypioneer Feb 10, 2026
f6ba52f
Merge branch 'dev' of https://github.com/anusii/solidui into tony/153…
tonypioneer Feb 10, 2026
07fd2b4
Remove hard-coded path names related to HealthPod
tonypioneer Feb 10, 2026
75f41bc
Lint
tonypioneer Feb 10, 2026
258c062
Merge pull request #202 from anusii/tony/199_healthpod_hard_coded_paths
gjwgit Feb 10, 2026
b69de34
Merge pull request #196 from anusii/tony/154_download_files_from_othe…
gjwgit Feb 10, 2026
68150a7
Merge pull request #196 from anusii/tony/154_download_files_from_othe…
gjwgit Feb 10, 2026
fdd4a5e
Merge remote-tracking branch 'origin/tony/153_refactor_file_browsing_…
tonypioneer Feb 11, 2026
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
12 changes: 12 additions & 0 deletions example/lib/app_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import 'package:solidui/solidui.dart';

import 'constants/app.dart';
import 'home.dart';
import 'screens/all_pod_files_page.dart';
import 'screens/sample_page.dart';

final _scaffoldController = SolidScaffoldController();
Expand Down Expand Up @@ -73,6 +74,17 @@ class AppScaffold extends StatelessWidget {
''',
child: SolidFile(),
),
SolidMenuItem(
icon: Icons.storage,
title: 'All POD Files',
tooltip: '''

**All POD Files:** Tap here to browse all folders on your POD
from the root.

''',
child: AllPodFilesPage(),
),
],

// APP BAR.
Expand Down
49 changes: 49 additions & 0 deletions example/lib/screens/all_pod_files_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/// All POD Files page - Displays all folders on the POD for testing.
///
/// Copyright (C) 2026, Software Innovation Institute, ANU.
///
/// Licensed under the MIT License (the "License").
///
/// License: https://choosealicense.com/licenses/mit/.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
///
/// Authors: Tony Chen

library;

import 'package:flutter/material.dart';

import 'package:solidui/solidui.dart';

/// A page that browses all folders and files on the POD from the root.

class AllPodFilesPage extends StatelessWidget {
const AllPodFilesPage({super.key});

@override
Widget build(BuildContext context) {
return const SolidFile(
currentPath: SolidFile.podRoot,
friendlyFolderName: 'All POD Files',
showBackButton: true,
backButtonText: 'Back to POD Root',
);
}
}
42 changes: 0 additions & 42 deletions lib/src/models/data_format_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,45 +97,3 @@ class DataFormatConfig {
description.hashCode;
}
}

/// Pre-defined format configurations for common health data types.

class SolidFileDataFormats {
static const bloodPressure = DataFormatConfig(
title: 'Blood Pressure CSV Format',
requiredFields: ['timestamp', 'systolic', 'diastolic', 'heart_rate'],
optionalFields: ['notes'],
);

static const vaccination = DataFormatConfig(
title: 'Vaccination CSV Format',
requiredFields: ['timestamp', 'name', 'type'],
optionalFields: ['location', 'notes', 'batch_number'],
);

static const medication = DataFormatConfig(
title: 'Medication CSV Format',
requiredFields: ['timestamp', 'name', 'dosage', 'frequency', 'start_date'],
optionalFields: ['notes'],
);

static const diary = DataFormatConfig(
title: 'Appointment CSV Format',
requiredFields: ['timestamp', 'content'],
optionalFields: ['mood', 'tags', 'notes'],
);

static const profile = DataFormatConfig(
title: 'Profile JSON Format',
requiredFields: [
'name',
'address',
'bestContactPhone',
'alternativeContactNumber',
'email',
'dateOfBirth',
'gender',
],
isJson: true,
);
}
148 changes: 51 additions & 97 deletions lib/src/models/file_type_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,29 @@
library;

import 'package:solidui/src/models/data_format_config.dart';
import 'package:solidui/src/utils/path_utils.dart';
import 'package:solidui/src/widgets/solid_file_helpers.dart';
import 'package:solidui/src/widgets/solid_file_upload_config.dart';

/// Predefined file types for different data categories.
/// A callback type for resolving file type configurations from a path.
///
/// Applications can provide their own resolver to map directory paths to
/// specific [FileTypeConfig] instances. Return `null` to fall through to the
/// default generic behaviour.

enum SolidFileType {
bloodPressure,
vaccination,
medication,
diary,
profile,
general,
}
typedef FileTypeResolver = FileTypeConfig? Function(
String normalisedPath,
String? basePath,
);

/// Configuration for different file types.

class FileTypeConfig {
/// The file type.
/// A string identifier for this file type (e.g. 'general', 'blood_pressure').
///
/// Applications may define their own type identifiers.

final SolidFileType type;
final String typeId;

/// Display name for the folder.

Expand Down Expand Up @@ -83,7 +86,7 @@ class FileTypeConfig {
final String uploadTooltip;

const FileTypeConfig({
required this.type,
this.typeId = 'general',
required this.displayName,
this.showCsvButtons = false,
this.showProfileButtons = false,
Expand All @@ -96,106 +99,57 @@ class FileTypeConfig {

/// Gets the file type configuration based on the current path.

static FileTypeConfig fromPath(String currentPath, [String? basePath]) {
if (currentPath.contains('/blood_pressure')) {
return const FileTypeConfig(
type: SolidFileType.bloodPressure,
displayName: 'Blood Pressure Data',
showCsvButtons: true,
formatConfig: SolidFileDataFormats.bloodPressure,
uploadTooltip: '''
static FileTypeConfig fromPath(
String currentPath, [
String? basePath,
FileTypeResolver? resolver,
]) {
// Normalise the path for consistent pattern matching.

**Upload**: Tap here to upload a file to your Solid Health Pod.

''',
);
} else if (currentPath.contains('/vaccination')) {
return const FileTypeConfig(
type: SolidFileType.vaccination,
displayName: 'Vaccination Data',
showCsvButtons: true,
formatConfig: SolidFileDataFormats.vaccination,
uploadTooltip: '''
final normalisedPath = PathUtils.normalise(currentPath);

**Upload**: Tap here to upload a file to your Solid Health Pod.
// Attempt app-specific resolution first.

''',
);
} else if (currentPath.contains('/medication')) {
return const FileTypeConfig(
type: SolidFileType.medication,
displayName: 'Medication Data',
showCsvButtons: true,
formatConfig: SolidFileDataFormats.medication,
uploadTooltip: '''

**Upload**: Tap here to upload a file to your Solid Health Pod.
if (resolver != null) {
final resolved = resolver(normalisedPath, basePath);
if (resolved != null) return resolved;
}

''',
);
} else if (currentPath.contains('/diary')) {
return const FileTypeConfig(
type: SolidFileType.diary,
displayName: 'Appointments Data',
showCsvButtons: true,
formatConfig: SolidFileDataFormats.diary,
uploadTooltip: '''
// Generic fallback — derive a friendly display name from the path.

**Upload**: Tap here to upload a file to your Solid Health Pod.
String effectiveBasePath =
basePath != null ? PathUtils.normalise(basePath) : '';

''',
);
} else if (currentPath.contains('/profile')) {
return const FileTypeConfig(
type: SolidFileType.profile,
displayName: 'Profile Data',
showProfileButtons: true,
formatConfig: SolidFileDataFormats.profile,
uploadTooltip: '''
if (effectiveBasePath.isEmpty) {
final segments =
normalisedPath.split('/').where((s) => s.isNotEmpty).toList();

**Upload**: Tap here to upload a file to your Solid Health Pod.
// Construct a reasonable base path — typically the first 2 segments
// for most cases.

''',
);
} else {
// General case - use the existing friendly folder name logic for
// consistency. If basePath is provided, use it; otherwise, construct a
// reasonable default.

String effectiveBasePath = basePath ?? '';

if (effectiveBasePath.isEmpty) {
final segments =
currentPath.split('/').where((s) => s.isNotEmpty).toList();

// Construct a reasonable base path - typically the first 2 segments
// for most cases.

if (segments.length >= 2) {
effectiveBasePath = '/${segments[0]}/${segments[1]}';
} else if (segments.length == 1) {
effectiveBasePath = '/${segments[0]}';
}
if (segments.length >= 2) {
effectiveBasePath = '${segments[0]}/${segments[1]}';
} else if (segments.length == 1) {
effectiveBasePath = segments[0];
}
}

final friendlyName = SolidFileHelpers.getFriendlyFolderName(
currentPath,
effectiveBasePath,
);
final friendlyName = SolidFileHelpers.getFriendlyFolderName(
normalisedPath,
effectiveBasePath,
);

String displayName =
friendlyName == 'Home' ? 'Home Folder' : friendlyName;
String displayName = friendlyName == 'Home' ? 'Home Folder' : friendlyName;

return FileTypeConfig(
type: SolidFileType.general,
displayName: displayName,
uploadTooltip: '''
return FileTypeConfig(
typeId: 'general',
displayName: displayName,
uploadTooltip: '''

**Upload**: Tap here to upload a file to your Solid Health Pod.
**Upload**: Tap here to upload a file to your Solid Pod.

''',
);
}
);
}

/// Creates the upload configuration for this file type.
Expand Down
Loading