Split project context into .claude/context/ (architecture, server, styling, standards) instead of one large file, referenced from a minimal root CLAUDE.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2.7 KiB
Architecture
Layout
lib/
main.dart # app root, theme wiring, top-level navigation switch
models/ # plain data classes (NextcloudItem, NextcloudShare, ...)
providers/ # ServerProvider — the single app-wide ChangeNotifier
services/ # network/IO: NextcloudService, LoginFlowService
theme/ # AppTheme (Material 3 ThemeData)
views/ # one screen each (FilesView, PhotosView, ...)
widgets/ # reusable pieces shared across views
details/ # the file-details bottom sheet and its tabs
views/ files are screens routed to directly (a tab, or pushed via
Navigator). widgets/ files are building blocks used by more than one
view (or complex enough to warrant their own file) — nothing in widgets/
owns app state itself; it reads it from the ServerProvider passed down or
read via context.watch/context.read.
State management
There is exactly one ChangeNotifier: ServerProvider.
It is created once in main() and provided at the root with provider's
ChangeNotifierProvider. It owns:
- auth/session state (
isLoggedIn,isRestoringSession, login-flow status) - the active
NextcloudServiceinstance (null until logged in) - all fetched data (
items,quota,activities) - navigation-within-files state (
currentFolderPath,pathStack) - UI settings that persist across launches (theme mode, seed color, dynamic color toggle, bottom-bar opacity/blur, sort/filter/view-mode prefs)
New app-wide state belongs on ServerProvider as a private field + getter +
a method that mutates it and calls notifyListeners(). Screen-local state
(e.g. a TextEditingController, an expanded/collapsed flag) stays in that
view's own State class — see standards.md for the split.
There's no separate repository/data layer: views call ServerProvider
methods directly, which call NextcloudService/LoginFlowService.
Navigation / screen flow
main.dart's NextcloudApp picks the app's home screen from provider
state, no named routes:
provider.isRestoringSession→_SplashView(spinner whileflutter_secure_storage/shared_preferencesare read on startup)- else
!provider.isLoggedIn→LoginView(server-address entry + Login Flow v2) - else
MainShellView
MainShellView is a bottom-nav IndexedStack with three persistent tabs —
Files, Photos, Activity — each keeping its own ScrollController so state
(scroll position, IndexedStack's built-but-hidden trees) survives tab
switches. SearchView and the file-details sheet are pushed on top via
Navigator/showModalBottomSheet rather than being tabs.