From 7890bfd7369a9dcc388dfc3a45caaaefa7e0661c Mon Sep 17 00:00:00 2001 From: Adron Hall Date: Sat, 11 Jul 2026 00:33:32 -0700 Subject: [PATCH 1/8] Next stages. --- .mcp.json | 12 + CLAUDE.md | 134 ++++++- .../Images/SplashScreen.png | Bin 0 -> 17872 bytes .../Images/Square150x150Logo.png | Bin 0 -> 9102 bytes .../Images/Square44x44Logo.png | Bin 0 -> 1734 bytes InterlinedList.Package/Images/StoreLogo.png | Bin 0 -> 2090 bytes .../InterlinedList.Package.wapproj | 45 +++ InterlinedList.Package/Package.appxmanifest | 46 +++ InterlinedList.slnx | 2 + InterlinedList/App.xaml | 3 +- InterlinedList/App.xaml.cs | 37 +- InterlinedList/InterlinedList.csproj | 4 + InterlinedList/LoginWindow.xaml | 220 +++++++++++ InterlinedList/LoginWindow.xaml.cs | 61 ++++ InterlinedList/MainWindow.xaml | 262 ++++++-------- InterlinedList/MainWindow.xaml.cs | 108 +++--- InterlinedList/Models/ApiUser.cs | 9 + InterlinedList/Models/CurrentUser.cs | 20 + InterlinedList/Models/DocumentFolder.cs | 9 + InterlinedList/Models/DocumentFolderEntry.cs | 8 + InterlinedList/Models/DocumentFoldersPage.cs | 6 + InterlinedList/Models/DocumentSearchResult.cs | 8 + InterlinedList/Models/DocumentSummary.cs | 12 + InterlinedList/Models/DocumentTemplate.cs | 8 + .../Models/DocumentTemplatesResponse.cs | 7 + InterlinedList/Models/DocumentsPage.cs | 6 + InterlinedList/Models/FollowCounts.cs | 8 + InterlinedList/Models/LinkedIdentity.cs | 15 + InterlinedList/Models/ListDataPage.cs | 7 + InterlinedList/Models/ListDataRow.cs | 16 + InterlinedList/Models/ListSearchResult.cs | 8 + InterlinedList/Models/ListSummary.cs | 11 + InterlinedList/Models/ListsPage.cs | 7 + InterlinedList/Models/Message.cs | 22 ++ InterlinedList/Models/MessagesPage.cs | 7 + InterlinedList/Models/NotificationItem.cs | 15 + InterlinedList/Models/NotificationsPage.cs | 7 + InterlinedList/Models/OrganizationSummary.cs | 16 + InterlinedList/Models/OrganizationsPage.cs | 9 + InterlinedList/Models/Pagination.cs | 9 + InterlinedList/Models/Post.cs | 17 - InterlinedList/Models/UserSearchResult.cs | 10 + InterlinedList/Models/UsersSearchPage.cs | 7 + InterlinedList/Services/ApiConfig.cs | 6 + InterlinedList/Services/AppServices.cs | 13 + InterlinedList/Services/CredentialStore.cs | 44 +++ .../Services/InterlinedApiClient.CrossPost.cs | 54 +++ .../Services/InterlinedApiClient.Documents.cs | 78 ++++ .../Services/InterlinedApiClient.Lists.cs | 53 +++ .../InterlinedApiClient.Organizations.cs | 49 +++ .../Services/InterlinedApiClient.Search.cs | 46 +++ .../Services/InterlinedApiClient.cs | 142 ++++++++ .../Services/InterlinedApiException.cs | 11 + InterlinedList/Services/SessionService.cs | 60 +++ .../ViewModels/ConnectedAccountsViewModel.cs | 84 +++++ .../ViewModels/DocumentsViewModel.cs | 162 +++++++++ InterlinedList/ViewModels/FeedViewModel.cs | 165 +++++++++ InterlinedList/ViewModels/ListsViewModel.cs | 177 +++++++++ InterlinedList/ViewModels/LoginViewModel.cs | 53 +++ .../ViewModels/MessageItemViewModel.cs | 94 +++++ .../ViewModels/NotificationItemViewModel.cs | 29 ++ .../ViewModels/NotificationsViewModel.cs | 71 ++++ .../ViewModels/OrganizationsViewModel.cs | 105 ++++++ .../ViewModels/ProfileSummaryViewModel.cs | 57 +++ InterlinedList/ViewModels/SearchViewModel.cs | 103 ++++++ .../Views/ConnectedAccountsView.xaml | 210 +++++++++++ .../Views/ConnectedAccountsView.xaml.cs | 15 + InterlinedList/Views/DocumentsView.xaml | 341 ++++++++++++++++++ InterlinedList/Views/DocumentsView.xaml.cs | 15 + InterlinedList/Views/FeedView.xaml | 290 +++++++++++++++ InterlinedList/Views/FeedView.xaml.cs | 21 ++ InterlinedList/Views/ListsView.xaml | 267 ++++++++++++++ InterlinedList/Views/ListsView.xaml.cs | 15 + InterlinedList/Views/ListsViewConverters.cs | 25 ++ InterlinedList/Views/OrganizationsView.xaml | 319 ++++++++++++++++ .../Views/OrganizationsView.xaml.cs | 15 + InterlinedList/Views/SearchView.xaml | 207 +++++++++++ InterlinedList/Views/SearchView.xaml.cs | 34 ++ installer/InterlinedList.Installer.wixproj | 25 ++ installer/License.rtf | 8 + installer/Package.wxs | 57 +++ 81 files changed, 4504 insertions(+), 234 deletions(-) create mode 100644 .mcp.json create mode 100644 InterlinedList.Package/Images/SplashScreen.png create mode 100644 InterlinedList.Package/Images/Square150x150Logo.png create mode 100644 InterlinedList.Package/Images/Square44x44Logo.png create mode 100644 InterlinedList.Package/Images/StoreLogo.png create mode 100644 InterlinedList.Package/InterlinedList.Package.wapproj create mode 100644 InterlinedList.Package/Package.appxmanifest create mode 100644 InterlinedList/LoginWindow.xaml create mode 100644 InterlinedList/LoginWindow.xaml.cs create mode 100644 InterlinedList/Models/ApiUser.cs create mode 100644 InterlinedList/Models/CurrentUser.cs create mode 100644 InterlinedList/Models/DocumentFolder.cs create mode 100644 InterlinedList/Models/DocumentFolderEntry.cs create mode 100644 InterlinedList/Models/DocumentFoldersPage.cs create mode 100644 InterlinedList/Models/DocumentSearchResult.cs create mode 100644 InterlinedList/Models/DocumentSummary.cs create mode 100644 InterlinedList/Models/DocumentTemplate.cs create mode 100644 InterlinedList/Models/DocumentTemplatesResponse.cs create mode 100644 InterlinedList/Models/DocumentsPage.cs create mode 100644 InterlinedList/Models/FollowCounts.cs create mode 100644 InterlinedList/Models/LinkedIdentity.cs create mode 100644 InterlinedList/Models/ListDataPage.cs create mode 100644 InterlinedList/Models/ListDataRow.cs create mode 100644 InterlinedList/Models/ListSearchResult.cs create mode 100644 InterlinedList/Models/ListSummary.cs create mode 100644 InterlinedList/Models/ListsPage.cs create mode 100644 InterlinedList/Models/Message.cs create mode 100644 InterlinedList/Models/MessagesPage.cs create mode 100644 InterlinedList/Models/NotificationItem.cs create mode 100644 InterlinedList/Models/NotificationsPage.cs create mode 100644 InterlinedList/Models/OrganizationSummary.cs create mode 100644 InterlinedList/Models/OrganizationsPage.cs create mode 100644 InterlinedList/Models/Pagination.cs delete mode 100644 InterlinedList/Models/Post.cs create mode 100644 InterlinedList/Models/UserSearchResult.cs create mode 100644 InterlinedList/Models/UsersSearchPage.cs create mode 100644 InterlinedList/Services/ApiConfig.cs create mode 100644 InterlinedList/Services/AppServices.cs create mode 100644 InterlinedList/Services/CredentialStore.cs create mode 100644 InterlinedList/Services/InterlinedApiClient.CrossPost.cs create mode 100644 InterlinedList/Services/InterlinedApiClient.Documents.cs create mode 100644 InterlinedList/Services/InterlinedApiClient.Lists.cs create mode 100644 InterlinedList/Services/InterlinedApiClient.Organizations.cs create mode 100644 InterlinedList/Services/InterlinedApiClient.Search.cs create mode 100644 InterlinedList/Services/InterlinedApiClient.cs create mode 100644 InterlinedList/Services/InterlinedApiException.cs create mode 100644 InterlinedList/Services/SessionService.cs create mode 100644 InterlinedList/ViewModels/ConnectedAccountsViewModel.cs create mode 100644 InterlinedList/ViewModels/DocumentsViewModel.cs create mode 100644 InterlinedList/ViewModels/FeedViewModel.cs create mode 100644 InterlinedList/ViewModels/ListsViewModel.cs create mode 100644 InterlinedList/ViewModels/LoginViewModel.cs create mode 100644 InterlinedList/ViewModels/MessageItemViewModel.cs create mode 100644 InterlinedList/ViewModels/NotificationItemViewModel.cs create mode 100644 InterlinedList/ViewModels/NotificationsViewModel.cs create mode 100644 InterlinedList/ViewModels/OrganizationsViewModel.cs create mode 100644 InterlinedList/ViewModels/ProfileSummaryViewModel.cs create mode 100644 InterlinedList/ViewModels/SearchViewModel.cs create mode 100644 InterlinedList/Views/ConnectedAccountsView.xaml create mode 100644 InterlinedList/Views/ConnectedAccountsView.xaml.cs create mode 100644 InterlinedList/Views/DocumentsView.xaml create mode 100644 InterlinedList/Views/DocumentsView.xaml.cs create mode 100644 InterlinedList/Views/FeedView.xaml create mode 100644 InterlinedList/Views/FeedView.xaml.cs create mode 100644 InterlinedList/Views/ListsView.xaml create mode 100644 InterlinedList/Views/ListsView.xaml.cs create mode 100644 InterlinedList/Views/ListsViewConverters.cs create mode 100644 InterlinedList/Views/OrganizationsView.xaml create mode 100644 InterlinedList/Views/OrganizationsView.xaml.cs create mode 100644 InterlinedList/Views/SearchView.xaml create mode 100644 InterlinedList/Views/SearchView.xaml.cs create mode 100644 installer/InterlinedList.Installer.wixproj create mode 100644 installer/License.rtf create mode 100644 installer/Package.wxs diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..95a9f9c --- /dev/null +++ b/.mcp.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "microsoft-learn": { + "type": "http", + "url": "https://learn.microsoft.com/api/mcp" + }, + "nuget": { + "command": "dotnet", + "args": ["dnx", "NuGet.Mcp.Server", "--source", "https://api.nuget.org/v3/index.json", "--yes"] + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md index 46c00c8..5847499 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -28,24 +28,146 @@ InterlinedList.slnx InterlinedList/ InterlinedList.csproj (net10.0-windows, UseWPF=true) app.manifest (Windows 10+ DPI awareness + UAC) - App.xaml / App.xaml.cs (App entry point, theme switching) - MainWindow.xaml (Shell: custom title bar, nav, feed, right rail) - MainWindow.xaml.cs (Code-behind: clock, nav, window chrome) + App.xaml / App.xaml.cs (Entry point: theme switching + login/session orchestration) + LoginWindow.xaml / .xaml.cs (Email/password gate, shown when no session restores) + MainWindow.xaml (Shell: custom title bar, left nav, center ContentControl, right rail) + MainWindow.xaml.cs (Code-behind: clock, nav → view switching, window chrome) Resources/ Palette.xaml (Invariant brand colors) Theme.Light.xaml (Light semantic brushes) Theme.Dark.xaml (Dark semantic brushes) - Models/ - Post.cs (Post data model) + Models/ (Wire types matching the real API JSON — see API integration below) + Services/ + ApiConfig.cs (Base URL: https://interlinedlist.com/) + InterlinedApiClient.cs (Core: HTTP/JSON plumbing + auth/user/messages/dig/notifications) + InterlinedApiClient.Lists.cs (partial class: Lists domain) + InterlinedApiClient.Documents.cs (partial class: Documents domain) + InterlinedApiClient.Organizations.cs (partial class: Organizations domain) + InterlinedApiClient.Search.cs (partial class: cross-resource search) + InterlinedApiClient.CrossPost.cs (partial class: linked-identity/OAuth helpers) + InterlinedApiException.cs + CredentialStore.cs (DPAPI-encrypted sync-token persistence) + SessionService.cs (login/logout/restore, exposes CurrentUser) + AppServices.cs (process-lifetime singletons: Api, Session) + ViewModels/ (CommunityToolkit.Mvvm ObservableObject + [RelayCommand]) + LoginViewModel.cs, FeedViewModel.cs, MessageItemViewModel.cs, + NotificationsViewModel.cs, NotificationItemViewModel.cs, ProfileSummaryViewModel.cs, + ListsViewModel.cs, DocumentsViewModel.cs, OrganizationsViewModel.cs, + SearchViewModel.cs, ConnectedAccountsViewModel.cs + Views/ (Self-contained UserControls; each owns its ViewModel — + `DataContext = new XyzViewModel(AppServices.Session)` in its + own constructor, not injected by MainWindow) + FeedView, ListsView, DocumentsView, OrganizationsView, SearchView, ConnectedAccountsView +installer/ + InterlinedList.Installer.wixproj (WiX v5 SDK project → classic .msi) + Package.wxs (product/feature/shortcut definition) + License.rtf (placeholder EULA for WixUI_Minimal) +InterlinedList.Package/ + InterlinedList.Package.wapproj (Windows Application Packaging Project → MSIX) + Package.appxmanifest (Store identity, visual elements, capabilities) + Images/ (tile/splash assets generated from brand-kit logo) ``` +## API integration + +The app talks to the real InterlinedList backend at `https://interlinedlist.com` +(154-endpoint REST API, OpenAPI spec at `/api/openapi.json`) — there is no mock +data layer. Auth is a long-lived bearer token from `POST /api/auth/sync-token` +(the same mechanism the `il-sync` CLI and other native clients use — no cookie +jar), persisted DPAPI-encrypted via `CredentialStore`. **There is no +server-side revoke endpoint for this token** — treat `%LocalAppData%\InterlinedList\session.dat` +as a standing credential. + +Covered now: login/session restore, paginated feed, compose, Dig/Undig, +notifications tray, profile/follow-counts rail, **Lists** (browse/create/ +delete, freeform JSON data rows — no schema/column editor, see below), +**Documents** (personal markdown notes: root docs, folders, templates, +create/edit/delete), **Organizations** (browse orgs you belong to + the +public directory, create — **no member management**, see below), unified +**Search** (messages/people/lists/documents from one box), and **Connected +Accounts** (Bluesky/Mastodon/LinkedIn/Twitter linking + compose-time +cross-post toggles). Still not built: Stripe billing, replies/threads, +register/forgot-password, GitHub issue sync, per-list schema/column +definitions, LinkedIn per-page posting targets. + +**Two real, load-bearing constraints discovered by live-probing the API — don't +"fix" these without re-verifying, they're not bugs in this app:** + +1. **Not every endpoint accepts the bearer sync-token.** `GET/POST + /api/organizations/{id}/members` and `GET /api/linkedin/targets` / + `posting-targets` return `401` even with a valid token — that subsystem + requires cookie-session auth this native client doesn't have. This is why + Organizations has no member-management UI and Connected Accounts has no + LinkedIn per-page targeting. +2. **The per-provider `GET /api/auth/{provider}/status` endpoints are a red + herring** — they report whether the *server* has that OAuth integration + configured, not whether *this user* has linked it. The real per-user link + state is `GET /api/user/identities` (works fine with the bearer token), + which is what `ConnectedAccountsViewModel` actually uses. + +**Write-path caution, same pattern throughout:** `PostMessageAsync`/ +`DigAsync`/`UndigAsync`/`AddListRowAsync`/`CreateOrganizationAsync`/ +`RemoveIdentityAsync` don't parse their response bodies — some were +deliberately never exercised live (creating an org, disconnecting a linked +identity) to avoid mutating shared test infrastructure, so callers re-fetch +from a `GET` afterward rather than trusting a typed write response. Lists' +schema/column DSL (`PUT /api/lists/{id}/schema`) was only partially reverse +engineered and is **not implemented** — data rows work fine schema-less +(confirmed live), so that's the supported path. If you pick up any of this, +verify the actual response shape against a real (test) account before typing +it strictly, and prefer read-after-write over trusting an unverified envelope. + +Left nav maps to real views now: **Feed**, **Lists**, **Documents**, +**Organizations**, **Search** (`MainWindow.xaml.cs` `NavItem_Click` swaps a +`ContentControl` via a small per-tag cache in `_views`), **Accounts** +(Connected Accounts), and **Alerts** (unchanged from Phase 2 — still a +right-rail toggle, not a center view). + +## Packaging & distribution + +Two independent, parallel packaging tracks — both wrap the same +`InterlinedList/InterlinedList.csproj` build, neither depends on the other: + +**MSI (`installer/`)** — WiX Toolset v5 (SDK-style, NuGet-restored via +`WixToolset.Sdk`). Build with `dotnet build installer/InterlinedList.Installer.wixproj` +on Windows; a `PublishApp` pre-build target runs `dotnet publish -r win-x64 +--self-contained` on the app first, then WiX harvests everything under +`InterlinedList/bin/Release/net10.0-windows/win-x64/publish/**` into the MSI via +a `` glob (no manual harvesting/heat step). Produces +`InterlinedList-Setup.msi` for direct download/side-loading, Start Menu +shortcut, per-machine install under Program Files. **Before shipping:** +replace `installer/License.rtf` with the real EULA. + +**MSIX (`InterlinedList.Package/`)** — classic Desktop Bridge "Windows +Application Packaging Project" (`.wapproj`), the standard route for putting +an existing Win32/.NET desktop app into the Microsoft Store or sideloaded +MSIX. This project type is **not** dotnet-CLI buildable — it requires the +"Universal Windows Platform development" workload in Visual Studio 2022, +since its targets come from the VS-installed +`Microsoft.DesktopBridge.props/.targets`, not a NuGet package. To build: +open `InterlinedList.slnx` in VS2022 on Windows, right-click +`InterlinedList.Package` → Publish (or Build for a local test package). Since +this project was hand-authored outside VS, **on first open let VS +reload/validate it** — check `TargetPlatformVersion`/`TargetPlatformMinVersion` +against installed SDKs, and confirm the `InterlinedList` project reference is +recognized as the entry point (`EntryPointProjectUniqueName`). **Before Store +submission:** replace the placeholder `Publisher` value in +`Package.appxmanifest` with the identity reserved in Partner Center (Partner +Center's "Associate App with the Store" wizard in VS will rewrite `Identity` +and `Properties` for you). + +Image assets in `InterlinedList.Package/Images/` were generated from +`brand-kit/logo/logo-icon-master.png` with transparent padding (tiles) and a +teal-deep `#0C2C3A` background (splash) — regenerate them the same way if the +mark changes, don't hand-edit the PNGs. + ## Windows-specific rules - App icon: `brand-kit/icons/windows/InterlinedList.ico` (set via ApplicationIcon in .csproj) - Title bar: `WindowChrome` (custom chrome, native resize); deep-teal `#0C2C3A` - Window controls: right-aligned min / max / close; close highlights red on hover - Card corners: 4px (`CornerRadius="4"`) -- Post card left edge: 4px wide, colored by stream type (teal / green / amber) +- Post card left edge: 4px wide; teal by default, amber once you've Dug that message (there's no server-side "stream type" to color by — see API integration) - Dark mode: read from HKCU registry at launch + listen via `SystemEvents.UserPreferenceChanged` ## Developing on macOS diff --git a/InterlinedList.Package/Images/SplashScreen.png b/InterlinedList.Package/Images/SplashScreen.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd9a2efc9537f804d19c860802f8902177bc20b GIT binary patch literal 17872 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 literal 0 HcmV?d00001 diff --git a/InterlinedList.Package/Images/Square44x44Logo.png b/InterlinedList.Package/Images/Square44x44Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..459e2fedf59c583372f5e162d01dc27181ddd7d8 GIT binary patch literal 1734 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 U+4sM%eE=%dqyPW_ literal 0 HcmV?d00001 diff --git a/InterlinedList.Package/InterlinedList.Package.wapproj b/InterlinedList.Package/InterlinedList.Package.wapproj new file mode 100644 index 0000000..7194c20 --- /dev/null +++ b/InterlinedList.Package/InterlinedList.Package.wapproj @@ -0,0 +1,45 @@ + + + + 08FF27C8-1F81-4A8F-B4B4-F7471E74710A + 10.0.22621.0 + 10.0.19041.0 + 15 + en-US + AppPackages\ + Always + x64 + 1 + OnApplicationRun + False + False + + Debug + x64 + {C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\InterlinedList\InterlinedList.csproj + + + + + + + Designer + + + + + + + + + + + + + InterlinedList + + + + + diff --git a/InterlinedList.Package/Package.appxmanifest b/InterlinedList.Package/Package.appxmanifest new file mode 100644 index 0000000..21e4a9a --- /dev/null +++ b/InterlinedList.Package/Package.appxmanifest @@ -0,0 +1,46 @@ + + + + + + + + + InterlinedList + InterlinedList + Images\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + diff --git a/InterlinedList.slnx b/InterlinedList.slnx index d2e75cc..5bdfd62 100644 --- a/InterlinedList.slnx +++ b/InterlinedList.slnx @@ -1,3 +1,5 @@ + + diff --git a/InterlinedList/App.xaml b/InterlinedList/App.xaml index 5d5d3ec..8b77ff3 100644 --- a/InterlinedList/App.xaml +++ b/InterlinedList/App.xaml @@ -1,7 +1,6 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> diff --git a/InterlinedList/App.xaml.cs b/InterlinedList/App.xaml.cs index 0e0e3a0..3cd7ae9 100644 --- a/InterlinedList/App.xaml.cs +++ b/InterlinedList/App.xaml.cs @@ -1,3 +1,4 @@ +using InterlinedList.Services; using Microsoft.Win32; using System.Windows; @@ -8,11 +9,45 @@ public partial class App : Application private const string ThemeRegistryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; - protected override void OnStartup(StartupEventArgs e) + protected override async void OnStartup(StartupEventArgs e) { base.OnStartup(e); ApplyTheme(IsSystemDarkMode()); SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged; + + var restored = await AppServices.Session.TryRestoreSessionAsync(); + if (restored) + ShowMainWindow(); + else + ShowLoginWindow(); + } + + // ── Login/session orchestration ──────────────────────────────────────────── + // No StartupUri: which window appears first depends on whether a saved + // session restores successfully, so both windows are shown manually. + + private void ShowLoginWindow() + { + var login = new LoginWindow(); + login.LoginSucceeded += (_, _) => + { + ShowMainWindow(); + login.Close(); + }; + MainWindow = login; + login.Show(); + } + + private void ShowMainWindow() + { + var main = new MainWindow(); + main.LoggedOut += (_, _) => + { + main.Close(); + ShowLoginWindow(); + }; + MainWindow = main; + main.Show(); } protected override void OnExit(ExitEventArgs e) diff --git a/InterlinedList/InterlinedList.csproj b/InterlinedList/InterlinedList.csproj index fa67ea2..75529ea 100644 --- a/InterlinedList/InterlinedList.csproj +++ b/InterlinedList/InterlinedList.csproj @@ -14,4 +14,8 @@ InterlinedList + + + + diff --git a/InterlinedList/LoginWindow.xaml b/InterlinedList/LoginWindow.xaml new file mode 100644 index 0000000..916a5c5 --- /dev/null +++ b/InterlinedList/LoginWindow.xaml @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/InterlinedList/Views/PeopleView.xaml.cs b/InterlinedList/Views/PeopleView.xaml.cs new file mode 100644 index 0000000..b0449e6 --- /dev/null +++ b/InterlinedList/Views/PeopleView.xaml.cs @@ -0,0 +1,24 @@ +using System.Windows.Controls; +using InterlinedList.ViewModels; + +namespace InterlinedList.Views; + +public partial class PeopleView : UserControl +{ + private readonly ProfileViewModel _vm; + + public PeopleView() + { + InitializeComponent(); + _vm = new ProfileViewModel(Services.AppServices.Session); + DataContext = _vm; + _ = _vm.LoadCommand.ExecuteAsync(null); + } + + ///

Open a specific user's profile (used by shell navigation from a feed/search card). + public void LoadProfile(string username) + { + _vm.LookupUsername = username; + _ = _vm.LoadProfileCommand.ExecuteAsync(null); + } +} diff --git a/InterlinedList/Views/SettingsView.xaml b/InterlinedList/Views/SettingsView.xaml new file mode 100644 index 0000000..27f0dbd --- /dev/null +++ b/InterlinedList/Views/SettingsView.xaml @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +