Uploads run entirely in ShareUploadService.kt, an Android foreground
service with no channel back to Dart once started - by design, so
closing the app mid-upload doesn't interrupt it. That meant
FilesController had no way to know a batch had finished, so a newly
uploaded file only appeared after a manual pull-to-refresh.
Adds a one-shot completion signal instead of a full stream: the
service publishes into a new UploadEventBus (in-process pub/sub,
mirroring SyncStatusBus) once a batch finishes with at least one
success, MainActivity forwards it to Dart over a new
dev.ayushya.noo/upload_service/status EventChannel, and
FilesController (subscribed in its own constructor, same pattern
OfflineController already uses for sync completion) calls
refreshData() when the event's destination folder matches
currentFolderPath. Covers both upload entry points (share-to-Noo and
Files' own "+" -> Upload file), since they already share the same
ShareUploadView/UploadService path.
Move/Copy needed no fix - ItemOperations already calls
files.invalidateCache() + refreshData() on success.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New launcher icon from IconKitchen: adaptive icon layers now live in
mipmap-* (already padded for the safe zone, so the 16% inset wrapper is
gone) and the old drawable-* launcher layers are removed. assets/icon
sources updated to match; app_icon.png is the 512px Play Store icon.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Offline tab is now FilesView(offline: true) over a FolderBrowser interface
(FilesController / OfflineController) sharing controls, tiles, thumbnails
- Synced files follow the Files Cache rule (default: refresh every 15 min):
per-account WorkManager jobs, in-app timer, resume and pull triggers;
root-etag shortcut skips full walks when nothing changed
- Single sync at a time (shared lock); logging out stops that account's sync
- Sync safety: PROPFIND failures skip the path instead of deleting local files
- Mirror empty folders and remove deleted ones; drop synced paths deleted on
the server; missing local files are re-downloaded
- Notifications: silent per-account sync notifications, "Background sync
notifications" setting, audible upload/download completion
- Files refresh in place (no spinner flash); retry after network returns
- Fix sync badges not updating (shared native status stream), "Sync off" on
launch (eager providers), Files Cache section moved under Device Sync
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Folders now show the synced status badge themselves, not just their
nested files - device-sync state never tracked folders individually, so
syncStatusFor derives a folder's badge from whether its path falls
within sync scope instead.
- Turning sync off for a path now deletes its local mirror and clears its
native sync-state entries (SyncEngine.removeLocalSync), instead of just
stopping future updates and leaving the downloaded copy behind.
- "Sync to device" in Files' selection toolbar now works over the whole
selection at once instead of being gated to a single selected item.
- The sync header's expanded panel shows real folder/item counts instead
of a static "Synced" label that stayed accurate-sounding even before
anything had actually synced.
- Confirmation SnackBars on starting/stopping sync from both the
selection toolbar and Settings' Device Sync card.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
- New native sync engine (SyncEngine/SyncWorker/ConflictResolveWorker,
WorkManager-based) that mirrors selected Nextcloud folders or files to
app-private local storage, periodically and on-demand ("Sync now"),
with never-auto-resolved conflict notifications.
- Single files (not just folders) can now be marked "Sync to device".
- Live sync status (syncing/synced/conflicts) pushes from native to Dart
over a new EventChannel; the persistent header chip/panel now reflects
device-sync status instead of the WebDAV-refresh loading state, with a
cloud_off/cloud_sync/cloud_done/cloud_alert icon set and an expandable
conflicts list with in-app "Keep local"/"Use server" resolution.
Per-item cloud_done/sync badges show on Files tiles.
- Share/Download short-circuit to the local copy for already-synced
files instead of a fresh network fetch.
- Settings gained a Device Sync section (per-folder list, "Sync
everything", Wi-Fi-only toggle, manual "Sync now").
- Fixed two release-only bugs found via on-device testing: Android's
HttpURLConnection silently rejects the PROPFIND method (switched to
OkHttp), and R8 was stripping WorkManager's reflection-instantiated
internals (broadened proguard-rules.pro to keep androidx.work.**
wholesale rather than chasing individual classes).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- WebDAV MOVE/COPY-backed copy/move for files and folders, with a
destination picker (independent nav state so it doesn't disturb the
Files tab's browsing position) and a conflict-resolution sheet
(overwrite all / keep both / decide per item).
- Downloads now use the same foreground-service + notification approach
as uploads, surviving app closure.
- Favorites is now its own tab (account-wide, via a WebDAV SEARCH query)
instead of a Files-tab filter toggle, which couldn't represent
favorited items outside the currently browsed folder correctly.
- Share sheet restyled to match the app's design language, plus a
"share file directly" action via the OS share sheet; details sheet
tab icons resized to match the bottom nav.
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>
- 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>
- Remove peek details sheet from media viewer; scope Activity tab to
the current file via client-side filtering instead of unreliable
server-side query params
- Add file rename action (WebDAV MOVE); fix search result taps to
switch to Files tab and rebuild breadcrumbs from an absolute path
- Add swipe-to-delete confirmation dialog; fix a crash from disposing
the rename dialog's TextEditingController too early
- Rework pull-to-sync gesture so sync and lock-open thresholds fire
independently within one gesture, raise thresholds, and add a
classic Material refresh spinner
- Add "tap active tab to scroll to top" behavior with a settings toggle
- Align selection toolbar padding with the sort/filter controls row
- Replace app icon assets (adaptive icon + splash screen) with
updated IconKitchen export
- Replace the seek bar style dropdown with a Default/Wavy/Slim/Squiggly
preset picker, each rendered with a live, perpetually-animated
preview via a new shared SeekBarPainter/SeekBarPreview
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Major additions since the initial rebuild:
- New tabs: Trash, Shares, Recent, configurable tab visibility/order/default
- Nextcloud sharing: search users/teams, internal link, email shares,
public links, "others with access" - in its own Share bottom sheet
- Details bottom sheet (Info/Versions/Activity) with a persistent peek
panel in the media viewer, reachable from selection, swipe, and the
media viewer
- Files/Photos: tap-and-hold multi-select with a sticky selection toolbar,
swipe actions (favorite/delete/share), sticky sort/filter controls,
list/grid views, breadcrumb chips, whole-account Photos view
- Media viewer: pinch/double-tap zoom on images, predictive-back support,
fixed PDF zoom-out floor
- Settings: Material You theming incl. AMOLED black, configurable bottom
bar tabs, swipe actions, media seek bar style, and folder-listing cache
policy (never/periodic/manual) to cut down on refetching
- Login flow moved to an in-app Chrome Custom Tab with retry-tolerant
polling
- Replaced ad hoc widgets with native Material 3 equivalents (toggle
IconButtons, SliverAppBar selection toolbar, SearchBar, drag handles)
- Rebrand: app renamed to Noo throughout, package id -> dev.ayushya.noo,
new adaptive launcher icon
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>