Portfolio / C# / Desktop lane / MyPortfolio
CS

MyPortfolio

Unified Windows catalog for every app I ship — binaries, extensions, APKs from GitHub releases

C#Desktop
Delivery
Source-first
Browse code, README, and release notes on GitHub.
Primary lane
C# / Desktop lane
The clearest adjacent context for this project inside the portfolio.
Freshness
Updated Apr 26, 2026
Latest release
No tag yet
README is the clearest project overview right now.

Preview

Using the generated project card as a clean fallback until a live capture is available.

MyPortfolio card

Source at github.com/SysAdminDoc/MyPortfolio.

README

Cached at build time, cleaned up for in-site reading, and linked back to the canonical GitHub source.

MyPortfolio

MyPortfolio

Version License Platform .NET

One desktop catalog for every app you ship. MyPortfolio reads your GitHub releases and gives you a single Windows app to install desktop binaries, load Chromium extensions, and pull Android APKs across to your PC.

MyPortfolio replaces three separate stores — LocalDesktopStore, LocalChromeStore, and LocalAndroidStore — with one shell. The Desktop and Chrome tabs install and uninstall like before. The Android tab is download-only on the Windows host: it pulls every .apk you publish straight into your local download folder so you can sideload it onto a device yourself.


What's in the app

Tab Source What it does
Desktop apps .msi, .exe (Inno / NSIS / generic), .zip portable Install, run, and uninstall — silent installers via msiexec /qb, /SILENT /NORESTART, /S, or extract-and-shortcut for portable ZIPs. SHA-256 sidecar verification.
Chrome extensions .zip or .crx Download, extract (zip-slip guarded, CRX2/CRX3 header strip), then launch Chrome / Brave / Edge / Vivaldi / Opera with --load-extension="path1,path2,...".
Android APKs .apk Download to %USERPROFILE%\Downloads\MyPortfolio\Android\<owner>\<repo>\<version>\ with hash verification. Read package name, version name, and version code from the APK manifest when available. Reveal in Explorer when you're ready to sideload.

One settings drawer drives all three tabs — same GitHub user, same PAT, optional extra collaborator owners, shared Mocha / Latte appearance, accent color, separate topic filter / verification toggles per tab.


Why one app instead of three

Three separate stores, three separate setups, three separate logs. Same GitHub user every time. The only thing that varied per store was which release asset to pick and what to do with it. So:

  • Shared shell — one window, Catppuccin Mocha / Latte themes, one activity log feeding from every tab, one settings drawer.
  • Tabbed surface — switch between Desktop / Chrome / Android with a click; per-tab refresh button + per-tab "Refresh all" trigger from the header.
  • One on-disk identity%APPDATA%\MyPortfolio\settings.json. Per-tab manifests for installed/downloaded state.

Install

  1. Grab MyPortfolio-vX.Y.Z-win-x64.zip from the Releases page.
  2. Verify SHA-256 against the .sha256.txt sidecar.
  3. Extract anywhere. Run MyPortfolio.exe.

Requires the .NET 9 Desktop Runtime — Windows x64 Desktop Runtime installer.

From source

git clone https://github.com/SysAdminDoc/MyPortfolio.git
cd MyPortfolio
dotnet build src/MyPortfolio/MyPortfolio.csproj -c Release
./src/MyPortfolio/bin/Release/net9.0-windows/MyPortfolio.exe

Usage

  1. Click Settings (top-right).
  2. Set your GitHub user / org (defaults to SysAdminDoc).
  3. (Optional) Paste a personal access token to raise the rate limit and surface private repos.
  4. (Optional) Add extra owners — use the chip editor for collaborator users / orgs, or paste a comma / semicolon / newline-separated list.
  5. Toggle topic filters per tab if you want to scope discovery (windows-app, chrome-extension, android-app are the suggested defaults).
  6. Pick a Catppuccin Theme and Accent if you want a lighter surface or a different focus color.
  7. Enable Refresh all tabs when MyPortfolio starts if you want discovery to run automatically on launch.
  8. Click Save and refresh all — each tab refreshes in a staged pass that can be canceled from the header.
  9. Switch between tabs and click Install / Download APK / Launch with extensions as you like.

Each tab shows its last successful refresh time beside its catalog summary, so stale discovery state is visible before you install or download anything. While a tab refreshes, the header shows the current discovery stage plus owner/repo counts. After refresh, each catalog also shows a compact discovery summary with partial-failure warnings, skipped archived/hidden/topic-filtered repo counts, repo probe issues, cache-hit counts, and current GitHub API quota. Expand owner diagnostics when you need the per-owner breakdown of matched, skipped, cached, failed, and probe-issue counts without adding noise to the activity log. Copy diagnostics creates a shareable support bundle with the compact summary, owner breakdown, rate-limit state, and recent activity lines; Save diagnostics writes the same redacted bundle to %LOCALAPPDATA%\MyPortfolio\diagnostics\ with a timestamped .txt filename and reveals it in Explorer. The saved GitHub token and common GitHub token formats are redacted before the text reaches the clipboard or disk. Release and topic probes are cached in memory for five minutes per GitHub user/token so repeated refreshes avoid burning through the same per-repo API calls. If GitHub stops discovery for a primary or secondary rate limit, the warning text tells you when or how long to wait before retrying. Downloaded Android cards also show the APK package name plus manifest version name and code when the manifest can be decoded. The Details action on each card expands local artifact metadata, including path, release asset, SHA-256, release date, and copy/open shortcuts.

Every action streams into the activity log at the bottom of the window. Nothing fails silently; everything is logged in-app and to %LOCALAPPDATA%\MyPortfolio\logs\.


On-disk layout

%APPDATA%\MyPortfolio\
├── settings.json                 # one shared AppSettings instance
├── desktop-installed.json        # InstalledAppsManifest + local artifact details
├── chrome-installed.json         # InstalledExtensionsManifest + local artifact details
└── android-downloads.json        # DownloadedApksManifest + APK manifest details

%LOCALAPPDATA%\MyPortfolio\
├── desktop\apps\<owner>\<repo>\<version>\    # portable ZIP extractions
├── desktop\downloads\                        # MSI / EXE staging
├── chrome\extensions\<owner>\<repo>\<version>\
├── cache\icons\                              # icon cache (per-tab prefix)
├── diagnostics\                              # timestamped redacted support bundles
└── logs\                                     # crash logs

%USERPROFILE%\Downloads\MyPortfolio\Android\<owner>\<repo>\<version>\<asset>.apk

The Android download folder lives under your Downloads on purpose — it's where you actually look when you go to sideload.


Architecture

C# WPF, .NET 9, single-project MVVM. No third-party MVVM toolkit. Three NuGet deps:

  • AndroidXml 1.1.24 — binary Android manifest decoding for APK metadata
  • Octokit 13.0.1 — GitHub API
  • Microsoft.Win32.Registry 5.0.0 — Windows uninstall key reads (Desktop tab only)
src/MyPortfolio/
├── App.xaml              # merged-dictionary theme bootstrap
├── MainWindow.xaml       # header / settings drawer / TabControl / log / status bar
├── MainViewModel.cs      # owns SettingsService, HttpDownloader, LogSink, three tab VMs
│
├── Common/               # ViewModelBase, RelayCommand, AppSettings, SettingsService,
│                         # GitHubClientFactory, DiscoveryDiagnostics,
│                         # DiscoveryProgress, DiagnosticsSupportBundle,
│                         # DiscoveryProbeCache, HttpDownloader,
│                         # HashVerifier, LogSink, Format
├── Converters/           # BoolToVis, NullToVis, EmptyStringToVis
├── Themes/               # Catppuccin token dictionary + runtime Mocha / Latte theme service
│
├── Desktop/              # Models / Services / ViewModels / Views — desktop-app install
├── Chrome/               # Models / Services / ViewModels / Views — extension install + launcher
└── Android/              # Models / Services / ViewModels / Views — APK download-only

Each tab owns its discovery service, its cards collection, and its install/download manifest. The shell exposes them through a single MainViewModel.


Source repos that fed into this

Repo Status
LocalDesktopStore Code ported; functionality lives in the Desktop tab.
LocalChromeStore Code ported; functionality lives in the Chrome tab.
LocalAndroidStore The Android tab here is download-only. The Android-host install pipeline (signature pinning, PackageInstaller.Session, ACTION_DELETE) stays inside the LocalAndroidStore Android app — it can't run on Windows.

License

MIT — see the LICENSE file for full text.

Read on GitHub → github.com/SysAdminDoc/MyPortfolio