Add share-to-upload, per-folder sort, and media viewer polish

- Accept Android's "Share to..." intent (ACTION_SEND/SEND_MULTIPLE) to
  upload a shared file, with a new destination-folder picker screen
- Unlink Files/Photos sort settings and make Files remember sort
  per folder (like per-folder view settings), instead of one shared
  global sort field for both tabs
- Media viewer: show the file name (marquee-scrolling if too long) in
  the top bar next to a resized back button, slide the top bar out of
  view instead of fading it, and unify icon color/contrast across the
  top bar, bottom action bar, and video transport controls
- Add a scrollbar thumb to every scrollable list in the app (all tab
  views via SyncedHeaderScaffold, search results, settings, the new
  upload folder picker, share sheet, and the Details sheet's tabs)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-16 11:05:54 -04:00
co-authored by Claude Sonnet 5
parent d5675d853c
commit 5299ac5c2c
17 changed files with 1137 additions and 702 deletions
+28 -18
View File
@@ -18,6 +18,7 @@ class SearchView extends StatefulWidget {
class _SearchViewState extends State<SearchView> {
final _controller = TextEditingController();
final _focusNode = FocusNode();
final _resultsScrollController = ScrollController();
Timer? _debounce;
List<NextcloudItem> _results = [];
@@ -30,6 +31,7 @@ class _SearchViewState extends State<SearchView> {
_debounce?.cancel();
_controller.dispose();
_focusNode.dispose();
_resultsScrollController.dispose();
super.dispose();
}
@@ -185,24 +187,32 @@ class _SearchViewState extends State<SearchView> {
),
);
}
return ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
itemCount: _results.length,
itemBuilder: (context, index) {
final item = _results[index];
return ListTile(
leading: Icon(_iconFor(item.type), color: colorScheme.primary),
title: Text(item.name, maxLines: 1, overflow: TextOverflow.ellipsis),
subtitle: Text(
item.isFolder
? item.path
: DateFormat.yMMMd().format(item.lastModified),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onTap: () => _openResult(item),
);
},
return Scrollbar(
controller: _resultsScrollController,
child: ListView.builder(
controller: _resultsScrollController,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
itemCount: _results.length,
itemBuilder: (context, index) {
final item = _results[index];
return ListTile(
leading: Icon(_iconFor(item.type), color: colorScheme.primary),
title: Text(
item.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: Text(
item.isFolder
? item.path
: DateFormat.yMMMd().format(item.lastModified),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onTap: () => _openResult(item),
);
},
),
);
}
}