Consolidates duplicated GET/PUT/notification-channel logic across
DownloadService/ShareUploadService/SyncEngine into shared Kotlin helpers,
gives upload/download real batch queueing instead of dropping a second
concurrent batch, and dedupes repeated Dart channel-argument boilerplate.
Replaces the 2300+ line ServerProvider god object with ten focused
ChangeNotifiers (SessionController, SettingsController, FilesController,
PhotosController, FavoritesController, TrashController, SharesController,
RecentController, SyncStatusController, PickController) plus ItemOperations,
a plain coordinator for cross-domain item mutations - fixing the coupling
where device-sync status, per-tab data, and global UI prefs all lived in
one object. Updates every view/widget call site accordingly and refreshes
the architecture/server/standards/styling docs to match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 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.
The Chrome Custom Tab path for the first/only login had real costs -
no way to close it automatically on success, and it's a separate task
outside the app's own navigation - that only bought Chrome's own
autofill in exchange. LoginWebViewView now handles every login, not
just add-account, which was already using it to avoid a Custom Tab
silently reusing Chrome's session for a different account.
url_launcher is no longer a dependency as a result.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sharing a large file to Noo used to black-screen and silently kick back
to the home screen: receive_sharing_intent copies the entire shared file
into the cache dir synchronously on the main thread before Flutter even
renders, which Android's watchdog eventually kills. Replaced with
hand-rolled handling in MainActivity.kt that only ever reads cheap Uri
metadata up front (ShareIntentService), so the destination picker always
appears instantly regardless of file size.
The destination picker (ShareUploadView) now mirrors the Files tab's own
controls/filters/listing instead of a bare folder list, and the actual
prepare+upload is handed off to ShareUploadService.kt, a real Android
foreground service with a single cancellable progress notification for
the whole batch - this survives the app being closed right after the
user confirms a destination, the same guarantee a file-manager app's own
upload notification gives.
Also fixes the "add another account" login page: it used to open in
url_launcher's bare inAppWebView, which has no close button and can hide
the status bar. LoginWebViewView is a real screen this app owns instead
(package:webview_flutter), with a normal AppBar/close button/safe area,
and can now auto-close itself on successful login.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
App lock (local_auth) gates the app behind the OS's biometric/device
credential prompt via a new lock screen, layered on top of the existing
Nextcloud session rather than replacing it.
Multi-account support lets users save several Nextcloud logins and switch
between them (AccountStore, per-account browsing prefs, avatar swipe-to-
cycle); logout() now keeps an account's saved credentials/prefs intact so
it can be resumed from a "Continue as..." list, while removeAccount()
stays the only destructive path.
The account settings screen is redesigned around a single profile card
(avatar/name/email, server host, storage quota with groups) with
Refresh Cache/Logout/Remove actions, replacing the old separate "Server
Connection Info" section.
Also fixes activity-tab timestamps: the OCS Activity API reports time as
an ISO 8601 `datetime` string, not the numeric `timestamp` field the code
incorrectly assumed, which made every activity render as Jan 1 1970.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace the generic Material cloud icon in a colored circle with the
actual branded app_icon.png (same asset already used for the splash
screen). Checked the rest of the app for other Icons.cloud* usages -
the remaining ones (sync-status chip, activity feed fallback icon)
are functional/semantic, not app branding, so left as-is.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add SavedAccount/AccountStore and rework ServerProvider around a list
of saved accounts: switch/remove/add, swipe-to-cycle on the avatar
button, per-account browsing prefs (sort/view/filters/cache), and a
session-generation guard so a stale fetch from an abandoned account
can't land in the newly active one
- Migrate existing single-account installs into the new schema
automatically so upgrading users stay logged in
- Settings gains an Accounts section; LoginView gains an "add account"
mode pushed on top of the main shell instead of replacing it
- Give every Scrollbar in the app a thicker, draggable, Android-style
thumb via a shared ScrollbarTheme instead of the default hairline
- Splash screen: use the monochrome app icon (tinted per theme) and a
smaller spinner
- Update CLAUDE.md and .claude/context/*.md to reflect the accumulated
multi-account, sharing, and UI changes across this session, and add
a standing instruction to keep these docs current going forward
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the starter template with Login Flow v2 auth, WebDAV-backed
Files/Photos/Activity tabs, a swipeable media viewer with PDF/text/video
preview, Material You dynamic theming, a frosted-glass floating nav bar,
and a rebranded app icon/identity (com.example -> family.nasa).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>