Add GET_CONTENT picker support, fix account/login bugs, restyle selection UI
Build APK / build (push) Successful in 7m40s

- Let Noo be picked as a source (Files + Photos) by other apps' native
  file/photo pickers via Android's GET_CONTENT intent, mirroring the
  existing "Share to Noo" plumbing: MainActivity.kt/PickIntentService/
  PickRequest, ServerProvider.pickRequest/confirmPick/cancelPick, and
  pick-mode tap handling in FilesView/PhotosView. While picking, the
  bottom nav and MoreTabsButton are restricted to Files/Photos only.
- Fix two account bugs: testConnection() failures no longer delete a
  still-valid stored app password (only an actual 401 does), and
  switchAccount() now retries a nominally-active-but-logged-out account
  instead of no-op'ing - both were silently locking users out of "Continue
  as" with no way back in except removing and re-adding the account
  (now exposed via login_view.dart's inline remove button).
- Fix the login WebView: clear cookies before every load so "Add Account"
  can't silently reuse an existing session, and push it as a
  non-animated route to avoid a known WebView-as-PlatformView black-screen-
  on-pop issue under Impeller.
- Redesign the Files/Photos selection toolbar to take over the top app bar
  entirely (SyncedHeaderScaffold.selectionBar) instead of sitting as a
  second bar under the controls row, with a horizontally-scrollable,
  uniformly-colored actions row and the same one-shot scroll-hint nudge
  the controls row uses.
- Redesign ShareUploadView to share the same SyncedHeaderScaffold chrome
  as every tab, with the uploading-file summary (marqueed via the new
  shared MarqueeTitle widget) and upload button grouped into one
  rounded/elevated bottom sheet.
- Restyle ShareSheet to open on the same DetailsHeader every other
  per-item sheet uses, and fix a couple of small design-language drifts
  (hardcoded text style, a non-rounded icon).
- Settings' account card: icon buttons with tooltips instead of text
  buttons for refresh/logout/remove, divider removed.
This commit is contained in:
2026-09-17 23:36:54 -04:00
parent eee2730fbe
commit 44a23c3632
24 changed files with 1298 additions and 394 deletions
+2 -49
View File
@@ -3,7 +3,6 @@ import 'dart:math' as math;
import 'dart:typed_data';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart';
import 'package:marquee/marquee.dart';
import 'package:open_file/open_file.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
@@ -14,6 +13,7 @@ import '../models/nextcloud_item.dart';
import '../providers/server_provider.dart';
import '../widgets/details/details_sheet.dart';
import '../widgets/frosted_glass_container.dart';
import '../widgets/marquee_title.dart';
import '../widgets/seek_bar_painter.dart';
import '../widgets/share_sheet.dart';
@@ -339,7 +339,7 @@ class _FileViewerScreenState extends State<FileViewerScreen> {
),
const SizedBox(width: 4),
Expanded(
child: _MarqueeTitle(
child: MarqueeTitle(
text: _currentItem.name,
style: Theme.of(context).textTheme.titleSmall
?.copyWith(
@@ -562,53 +562,6 @@ class _ActionIconButton extends StatelessWidget {
}
}
/// The media viewer's title: a plain, single-line ellipsized [Text] for
/// names that fit, or an auto-scrolling [Marquee] for names too long for
/// the available width - measured once via [TextPainter] rather than
/// always marqueeing, so a short filename just sits still like normal.
class _MarqueeTitle extends StatelessWidget {
final String text;
final TextStyle? style;
const _MarqueeTitle({required this.text, required this.style});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final painter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: 1,
textDirection: Directionality.of(context),
)..layout(maxWidth: double.infinity);
if (painter.width <= constraints.maxWidth) {
return Text(
text,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: style,
);
}
return SizedBox(
height: painter.height,
child: Marquee(
text: text,
style: style,
blankSpace: 48,
velocity: 30,
startPadding: 0,
pauseAfterRound: const Duration(seconds: 1),
fadingEdgeStartFraction: 0.1,
fadingEdgeEndFraction: 0.15,
),
);
},
);
}
}
class _ImagePreview extends StatefulWidget {
final String url;
final Map<String, String> headers;