Skip to content

Commit 5f7e777

Browse files
committed
Merge branch 'dev' of https://github.com/anusii/solidui into tony/257_notification
# Conflicts: # lib/src/widgets/solid_scaffold_appbar_actions.dart # lib/src/widgets/solid_scaffold_appbar_builder.dart # lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart # lib/src/widgets/solid_scaffold_helpers.dart # lib/src/widgets/solid_scaffold_widget_builder.dart
2 parents c950b9b + d7b4e15 commit 5f7e777

34 files changed

Lines changed: 726 additions & 263 deletions

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ au](https://solidcommunity.au/docs/solidui)
1515

1616
## 0.4.0 Refine and Tune
1717

18+
+ Add a Wrap() to avoid overflow on SolidLogin [0.3.18 20260410 gjw]
19+
+ Place ABOUT button to right most by default [0.3.17 20260410 gjw]
20+
+ Add mising wordWrap function [0.3.16 20260410 gjw]
21+
+ Add showLogin to support no login button [0.3.15 20260410 gjw]
22+
+ Support invisible LOGIN/CONTINUE buttons [0.3.14 20260409 gjw]
23+
+ Support invisible REGISTER/INFO buttons for SolidLogin [0.3.13 20260409 gjw]
24+
+ Retain app theme across restart [0.3.12 20260409 gjw]
25+
+ Add get key if required to login [0.3.11 20260406 tonypioneer]
26+
+ Fine tune UX for SolidScaffold elements [0.3.10 20260406 gjw]
27+
+ List files/folder count in FileBrowser, not just file count [0.3.9 20260402 gjw]
1828
+ Add keep login and other webid to SolidLogin() [0.3.8 20260326 tonypioneer]
1929
+ Adds additional layout width checks [0.3.7 20260326 tonypioneer]
2030
+ Add Security Key and Logged In to Nav menu [0.3.6 20260326 tonypioneer]

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Generic Makefile
44
#
5-
# Time-stamp: <Saturday 2026-01-03 16:58:59 +1100 Graham Williams>
5+
# Time-stamp: <Wednesday 2026-03-18 12:22:03 +1100 Graham Williams>
66
#
77
# Copyright (c) Graham.Williams@togaware.com
88
#
@@ -188,3 +188,12 @@ ginfo:
188188
else \
189189
echo "No bump ID found."; \
190190
fi
191+
192+
.PHONY: zip
193+
zip:
194+
rm -f ignore/my_lib.zip
195+
zip -r ignore/my_lib.zip lib
196+
197+
.PHONY: claude
198+
claude:
199+
bash support/meld_zip_from_claude.sh

example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dependencies:
1515
markdown_tooltip: ^0.0.10
1616
rdflib: ^0.2.12
1717
solidpod: ^0.11.0
18-
solidui: # ^0.2.0
18+
solidui:
1919
path: ..
2020
universal_io: ^2.3.1
2121
window_manager: ^0.5.1

lib/src/constants/navigation.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,27 @@ class NavigationConstants {
5151

5252
/// Minimum width for the navigation rail.
5353
54-
static const double navRailMinWidth = 80.0;
54+
static const double navRailMinWidth = 84.0;
5555

5656
/// Vertical alignment for navigation rail items.
5757
5858
static const double navRailGroupAlignment = -1.0;
5959

6060
/// Icon size for navigation items.
6161
62-
static const double navIconSize = 26.0;
62+
static const double navIconSize = 24.0;
6363

6464
/// Font size for navigation labels.
6565
66-
static const double navLabelFontSize = 10.5;
66+
static const double navLabelFontSize = 11.0;
6767

6868
/// Letter spacing for navigation labels.
6969
70-
static const double navLabelLetterSpacing = 0.2;
70+
static const double navLabelLetterSpacing = 0.3;
7171

7272
/// Vertical padding for navigation rail destinations.
7373
74-
static const double navDestinationVerticalPadding = 6.0;
74+
static const double navDestinationVerticalPadding = 8.0;
7575

7676
/// Maximum lines for navigation labels.
7777

lib/src/utils/file_operations.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ class FileOperations {
168168
String currentPath,
169169
List<String> directories,
170170
) async {
171-
// Count files in each subdirectory.
171+
// Count items (files + folders) in each subdirectory.
172172

173173
final counts = <String, int>{};
174174
for (var dir in directories) {
@@ -179,24 +179,26 @@ class FileOperations {
179179
return counts;
180180
}
181181

182-
/// Counts the number of files in a directory.
182+
/// Counts the total number of items (files and folders) in a directory.
183183
///
184184
/// Parameters:
185-
/// - [dirPath]: The directory path to count files in.
185+
/// - [dirPath]: The directory path to count items in.
186186
///
187-
/// Returns the number of files in the directory, or 0 if an error occurs.
187+
/// Returns the number of files and subdirectories, or 0 if an error occurs.
188188
189189
static Future<int> getDirectoryFileCount(String dirPath) async {
190190
try {
191-
// Get directory contents and count files.
191+
// Get directory contents and count both files and subdirectories.
192192

193193
final dirUrl = await getDirUrl(dirPath);
194194
final resources = await getResourcesInContainer(dirUrl);
195-
return resources.files
195+
final fileCount = resources.files
196196
.where((f) => f.endsWith('.enc.ttl') || f.endsWith('.ttl'))
197197
.length;
198+
199+
return fileCount + resources.subDirs.length;
198200
} catch (e) {
199-
debugPrint('Error counting files in directory: $e');
201+
debugPrint('Error counting items in directory: $e');
200202
return 0;
201203
}
202204
}

lib/src/widgets/app_bar.dart

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,13 @@ PreferredSizeWidget defaultAppBar(
4747
}) {
4848
return AppBar(
4949
leading: IconButton(
50-
icon: const Icon(Icons.arrow_back, color: Colors.black),
50+
icon: Icon(
51+
Icons.arrow_back,
52+
color: ThemeData.estimateBrightnessForColor(backgroundColor) ==
53+
Brightness.dark
54+
? Colors.white
55+
: Colors.black87,
56+
),
5157
onPressed: () {
5258
// Call the callback if provided.
5359

@@ -61,15 +67,19 @@ PreferredSizeWidget defaultAppBar(
6167
// Use the original pushReplacement behaviour.
6268

6369
pushReplacement(context, child);
64-
65-
// Navigator.pushReplacement(
66-
// context,
67-
// MaterialPageRoute(builder: (context) => child),
68-
// );
6970
}
7071
},
7172
),
7273
backgroundColor: backgroundColor,
73-
title: Text(title),
74+
elevation: 0,
75+
scrolledUnderElevation: 0.5,
76+
title: Text(
77+
title,
78+
style: const TextStyle(
79+
fontWeight: FontWeight.w700,
80+
letterSpacing: -0.3,
81+
fontSize: 18,
82+
),
83+
),
7484
);
7585
}

lib/src/widgets/solid_about_button.dart

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// Solid About Button.
22
///
3-
// Time-stamp: <Monday 2025-08-25 09:43:05 +1000 Graham Williams>
3+
// Time-stamp: <Thursday 2026-04-09 11:51:44 +1000 Graham Williams>
44
///
55
/// Copyright (C) 2025, Software Innovation Institute, ANU.
66
///
@@ -42,6 +42,44 @@ import 'package:solidui/src/constants/about.dart';
4242
import 'package:solidui/src/widgets/solid_about_models.dart';
4343
import 'package:solidui/src/widgets/solid_preferences_dialog.dart';
4444

45+
/// Collapses single newlines (source-code soft wraps) into spaces so the
46+
/// Markdown renderer can reflow text to fit the dialog width.
47+
///
48+
/// Double newlines (paragraph breaks) and Markdown syntax lines (headings,
49+
/// links, bold, etc.) are preserved verbatim.
50+
51+
String wordWrap(String text) {
52+
// Normalise Windows line endings.
53+
final s = text.replaceAll('\r\n', '\n');
54+
final lines = s.split('\n');
55+
final out = StringBuffer();
56+
57+
for (int i = 0; i < lines.length; i++) {
58+
final line = lines[i];
59+
final next = i + 1 < lines.length ? lines[i + 1] : null;
60+
61+
// Empty line = paragraph break — preserve as-is.
62+
if (line.trim().isEmpty) {
63+
out.writeln();
64+
continue;
65+
}
66+
67+
// Markdown structural lines (headings, list items, links, bold starts)
68+
// must stay on their own line.
69+
final isMdLine =
70+
RegExp(r'^(#{1,6} |\*\*|\* |- |\[|\!)').hasMatch(line.trim());
71+
72+
if (isMdLine || next == null || next.trim().isEmpty) {
73+
out.writeln(line);
74+
} else {
75+
// Soft wrap: join to next line with a space instead of a newline.
76+
out.write('$line ');
77+
}
78+
}
79+
80+
return out.toString().trimRight();
81+
}
82+
4583
/// A button that shows an About dialogue when pressed.
4684
4785
class SolidAboutButton extends StatefulWidget {
@@ -316,7 +354,7 @@ class SolidAbout {
316354
alignment: Alignment.centerLeft,
317355
child: TextButton.icon(
318356
icon: const Icon(Icons.tune),
319-
label: const Text('AppBar Layout Preferences'),
357+
label: const Text('AppBar Preferences'),
320358
onPressed: () {
321359
Navigator.of(dialogContext).pop();
322360
SolidPreferencesDialog.show(context);

lib/src/widgets/solid_dynamic_auth_button.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,15 @@ import 'package:solidui/src/handlers/solid_auth_handler.dart';
4343
4444
class SolidDynamicAuthButton extends StatefulWidget {
4545
/// Whether to show the logout button when user is logged in.
46-
/// When false, only the login button is shown when logged out.
4746
4847
final bool showLogout;
4948

49+
/// Whether to show the login button when user is logged out.
50+
/// Set to false to hide the login button entirely (e.g. when the app
51+
/// uses a dedicated login screen via SolidLogin).
52+
53+
final bool showLogin;
54+
5055
/// Callback function triggered when user taps logout (when logged in).
5156
/// If null, uses SolidAuthHandler.instance.handleLogout().
5257
@@ -68,6 +73,7 @@ class SolidDynamicAuthButton extends StatefulWidget {
6873
const SolidDynamicAuthButton({
6974
super.key,
7075
this.showLogout = true,
76+
this.showLogin = true,
7177
this.onLogout,
7278
this.onLogin,
7379
this.loginTooltip = 'Log in to your Solid POD',
@@ -173,11 +179,16 @@ class _SolidDynamicAuthButtonState extends State<SolidDynamicAuthButton> {
173179
);
174180
}
175181

176-
// When showLogout is false and user is logged in, hide the button.
182+
// Hide logout button when logged in and showLogout is false.
177183
if (!widget.showLogout && _isLoggedIn) {
178184
return const SizedBox.shrink();
179185
}
180186

187+
// Hide login button when logged out and showLogin is false.
188+
if (!widget.showLogin && !_isLoggedIn) {
189+
return const SizedBox.shrink();
190+
}
191+
181192
final icon = _isLoggedIn ? Icons.logout : Icons.login;
182193
final tooltip = _isLoggedIn ? widget.logoutTooltip : widget.loginTooltip;
183194

lib/src/widgets/solid_file_directory_list.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ library;
3030

3131
import 'package:flutter/material.dart';
3232

33-
/// A widget that displays a list of directories with their file counts.
33+
/// A widget that displays a list of directories with their item counts.
3434
3535
class DirectoryList extends StatelessWidget {
3636
/// List of directory names to display.
3737
3838
final List<String> directories;
3939

40-
/// Map of directory names to their file counts.
40+
/// Map of directory names to their item counts (files + folders).
4141
4242
final Map<String, int> directoryCounts;
4343

@@ -172,7 +172,7 @@ class DirectoryList extends StatelessWidget {
172172
),
173173
),
174174

175-
// File count badge. Shows a compact loading indicator while
175+
// Item count badge. Shows a compact loading indicator while
176176
// counts are being fetched in the background.
177177

178178
if (directoryCounts.containsKey(dir))
@@ -188,7 +188,8 @@ class DirectoryList extends StatelessWidget {
188188
borderRadius: BorderRadius.circular(12),
189189
),
190190
child: Text(
191-
'${directoryCounts[dir]} files',
191+
'${directoryCounts[dir]}'
192+
' item${directoryCounts[dir] == 1 ? '' : 's'}',
192193
style: TextStyle(
193194
fontSize: 12,
194195
color: Theme.of(context).textTheme.bodySmall?.color,

lib/src/widgets/solid_file_path_bar.dart

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -328,24 +328,22 @@ class PathBar extends StatelessWidget {
328328
),
329329
)
330330
else
331-
Row(
332-
children: [
333-
Text(
334-
'Directories: $currentDirDirectoryCount',
331+
Builder(
332+
builder: (context) {
333+
final total =
334+
currentDirDirectoryCount + currentDirFileCount;
335+
final dirs = currentDirDirectoryCount;
336+
final files = currentDirFileCount;
337+
return Text(
338+
'$total item${total == 1 ? '' : 's'}'
339+
' ($dirs director${dirs == 1 ? 'y' : 'ies'}'
340+
' and $files file${files == 1 ? '' : 's'})',
335341
style: TextStyle(
336342
color: Theme.of(context).textTheme.bodySmall?.color,
337343
fontSize: 12,
338344
),
339-
),
340-
const SizedBox(width: 8),
341-
Text(
342-
'Files: $currentDirFileCount',
343-
style: TextStyle(
344-
color: Theme.of(context).textTheme.bodySmall?.color,
345-
fontSize: 12,
346-
),
347-
),
348-
],
345+
);
346+
},
349347
),
350348

351349
const SizedBox(width: 12),

0 commit comments

Comments
 (0)