{
  "version": "https://jsonfeed.org/version/1",
  "title": "capyreader on jocmp",
  "icon": "https://avatars.micro.blog/avatars/2026/14/52207.jpg",
  "home_page_url": "https://jocmp.com/",
  "feed_url": "https://jocmp.com/feed.json",
  "items": [
      {
        "id": "http://jocmp.micro.blog/2026/04/30/reworking-sync-for-better-offline/",
        "title": "Reworking sync for better offline support",
        "content_html": "<p>Capy version <a href=\"https://github.com/jocmp/capyreader/releases/tag/2026.05.1208\">2026.05.1208</a> includes improvements to better support offline reading. Previous attempts relied too heavily on Android <a href=\"https://developer.android.com/develop/background-work/background-tasks\">background tasks</a> for state management. Background tasks worked well on good connections but drifted on spotty networks. Even when statuses did sync, they would sync outside the refresh interval, if ever.</p>\n<p>Now, statuses are always added to an &ldquo;outbox&rdquo; controlled by the app, not the OS. This is a SQLite table that tracks &ldquo;read&rdquo; or &ldquo;starred&rdquo; states. This is pulled from NetNewsWire&rsquo;s sync status model which is battle tested and works across many platforms.</p>\n<p>So if 100 articles are marked as read, all 100 will be pushed to the server before new statuses are pulled. This does assume that the offline client is the most up-to-date based on current sync systems. Regardless, this is a necessary trade-off that either clobbers client statuses or server statuses since there are no timestamp or conflict resolutions shared for FreshRSS, Feedbin or Miniflux.</p>\n<p>The new system is drastically simpler and means statuses always move in one direction via one outbox as opposed to two competing background jobs. Let me know how it works the next time you lose connection in a tunnel!</p>\n<p><strong>Before</strong></p>\n<p>If this graph looks painful, that&rsquo;s because it is, and was always difficult to debug.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2026/before-mermaid-diagram-2026-04-28-212711.png\" width=\"600\" height=\"414\" alt=\"Auto-generated description: A flowchart illustrates the process where a user marks an item as read or starred and synchronizes changes between a client database and server, showing potential overwrites and background jobs.\">\n<p><strong>After</strong></p>\n<p>One way to sync, in a straight line, start to finish.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2026/after-mermaid-diagram-2026-04-28-213213.png\" width=\"600\" height=\"1000\" alt=\"\">\n<h2 id=\"other-updates\">Other Updates</h2>\n<p><a href=\"https://bazqux.com/\">BazQux</a> is now supported via the Reader API account. There were a few bugs in the way that have now been squashed.</p>\n<p>There are more bandwidth checks on local feeds to ensure that duplicate updates are skipped. This is to avoid a <a href=\"https://github.com/jocmp/capyreader/discussions/2054\">scary issue</a> where the app consumed multiple gigs of data for one user.</p>\n<p>The bottom bar in the reader has been condensed to take advantage of the new <a href=\"https://m3.material.io/components/toolbars/overview\">floating toolbar</a> design in Material 3 Expressive. This gives back more space to the article itself.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2026/toolbar.png\" width=\"600\" height=\"600\" alt=\"\">\n<h2 id=\"whats-next\">What&rsquo;s Next</h2>\n<p>There are a few improvements up for consideration in the next development cycle. Offline mode isn&rsquo;t there yet. I plan to start exploring support for offline full content articles and media (<a href=\"https://github.com/jocmp/capyreader/discussions/2063\">discussion</a>).</p>\n<p>E Ink optimization is another area of investigation. I want to explore article pagination as well as immersive mode for E Ink devices specifically. If that works out, I also want to tweak the Monochrome theme to use up less full colors and more outlines to avoid ghosting.</p>\n<hr>\n<p><em>Capy Reader is a solo project supported by readers like you. Show your support by leaving a tip on <a href=\"https://ko-fi.com/capyreader\">Ko-fi</a>, or by sharing the app with a friend. Thanks!</em></p>\n",
        "date_published": "2026-04-30T22:31:00-05:00",
        "url": "https://jocmp.com/2026/04/30/reworking-sync-for-better-offline/",
        "tags": ["capyreader"]
      },
      {
        "id": "http://jocmp.micro.blog/2026/02/03/capy-log-miniflux-and-more/",
        "title": "Capy Log: Miniflux and more",
        "content_html": "<p>I’m excited to announce initial Miniflux support in Capy Reader in version 2026.01.1189. While it was possible to use Miniflux via the Google Reader API, this latest version of the app calls Miniflux’s API directly. Right now the feature set is just the essentials</p>\n<ul>\n<li>Add, remove, and update feeds</li>\n<li>Add and edit categories</li>\n<li>Fetch new articles, and mark articles as read and starred</li>\n</ul>\n<p>These should cover all the same features as the Google Reader API, but let me know! If you notice anything missing, let me know <a href=\"https://github.com/jocmp/capyreader/discussions/1749\">on GitHub</a> or if you have feature suggestions that are specific to the Miniflux API. I’m already planning to investigate Miniflux’s <a href=\"https://github.com/jocmp/capyreader/issues/1748\">save feature</a> for example.</p>\n<h2 id=\"enabling-miniflux\">Enabling Miniflux</h2>\n<p>To get started, select &ldquo;Miniflux&rdquo; on the account screen and enter your username and password.</p>\n<p>If you’re signed in to Google Reader API, just sign out in Settings &gt; Account &gt; Log Out, and then select Miniflux on the account screen. Note that API Keys are not yet supported, but I’m open to feedback on this, especially if you know of any other apps that have this feature already.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2026/add-account.png\" width=\"300\" height=\"635\" alt=\"Auto-generated description: A smartphone screen displays an Add Account menu with options to connect to RSS services like Local, Feedbin, FreshRSS, Miniflux, and Reader.\">\n<h2 id=\"other-tweaks\">Other Tweaks</h2>\n<p>I’ve enabled the audio player by default in the latest version. The audio player has been behind an experimental flag for the past few versions, and is now ready for general use. This version includes improvements for FreshRSS by de-duplicating enclosures and showing counts for &ldquo;My Labels.&rdquo;</p>\n<p>If you enjoy these updates consider leaving a tip <a href=\"https://ko-fi.com/capyreader\">on Ko-fi</a> or sharing the app with others! As ever, thanks for using Capy Reader.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2026/labels.png\" width=\"300\" height=\"635\" alt=\"Auto-generated description: A smartphone screen displays an RSS feed app interface with sections for unread articles, categories, and labeled feeds.\">\n<img src=\"https://cdn.uploads.micro.blog/238475/2026/block-quotes.png\" width=\"300\" height=\"635\" alt=\"Auto-generated description: A smartphone screen displays an article discussing upcoming features in GNOME 50, focusing on virtual monitor and remote desktop capabilities.\">\n",
        "date_published": "2026-02-03T22:33:07-05:00",
        "url": "https://jocmp.com/2026/02/03/capy-log-miniflux-and-more/",
        "tags": ["capyreader"]
      },
      {
        "id": "http://jocmp.micro.blog/2026/01/17/podcasts-in-capy/",
        "title": "Podcasts in Capy",
        "content_html": "<p>I released audio enclosures in version <a href=\"https://github.com/jocmp/capyreader/releases/tag/2026.01.1186\">2026.01.1186</a> of Capy Reader. The goal is to enable audio on supported feeds to provide the full experience of any post. By no means am I trying to build a full podcast experience!</p>\n<p>I&rsquo;m looking for any and all quirks or bugs you may find. If you run across any issues with the feature, please let me know in the <a href=\"https://github.com/jocmp/capyreader/discussions/1689\">announcement thread on GitHub</a> or by emailing me at <a href=\"mailto:support@jocmp.com\">support@jocmp.com</a>. Screenshots and crashlogs are most helpful, along with detailed steps on how to reproduce the bug.</p>\n<p>Happy listening!</p>\n<h2 id=\"how-to-opt-in\">How to opt-in</h2>\n<p>These are opt-in under Settings &gt; General &gt; Audio player. Demo below.</p>\n<p><video controls=\"controls\" playsinline=\"playsinline\" preload=\"metadata\" width=\"1440\" height=\"1080\" poster=\"https://cdn.uploads.micro.blog/238475/2026/frames/1661997-0-fe4e0e.jpg\" src=\"https://cdn.uploads.micro.mov/238475/2026/site-podcast-demo/playlist.m3u8\"></video></p>\n",
        "date_published": "2026-01-17T14:57:17-05:00",
        "url": "https://jocmp.com/2026/01/17/podcasts-in-capy/",
        "tags": ["capyreader"]
      },
      {
        "id": "http://jocmp.micro.blog/2025/08/22/the-guts-of-a-new/",
        "title": "The Guts of a New Machine",
        "content_html": "<p>ReadYou just released <a href=\"https://github.com/ReadYouApp/ReadYou/releases/tag/0.15.0\">v0.15.0</a> this past week. I&rsquo;ve been waiting to see their take on one very specific feature: large screen support. I tried it out. It&rsquo;s great! There&rsquo;s a subtle animation for article filters in the list column. There&rsquo;s also an expand/collapse option to view the article in full screen. This is a new paradigm that Google has been pushing in Keep and Gmail. In the face of these improvements, I&rsquo;ve been thinking to myself, why did I build Capy Reader when ReadYou has such an advanced UI?</p>\n<p>In retrospect, I set out to build Capy Reader for two reasons: exploration and compatibility. I wanted to explore how RSS readers worked under the hood, how they looked up feeds, and why they made the trade-offs they made. <a href=\"https://github.com/Ranchero-Software/NetNewsWire/tree/main/Technotes\">NetNewsWire&rsquo;s technotes</a> were a major help here since they delve into sync strategies and software architecture. Needless to say, there&rsquo;s no shortage of information.</p>\n<p>I built Capy Reader for compatibility <a href=\"https://feedbin.com/\">with Feedbin</a> too. There are plenty of readers available that work with Feedbin, sure, but none of them are exactly a pleasant experience. So when I built Capy, I built it for that. From there, I thought I could skirt around the need for Feedbin sign-in credentials in Google Play&rsquo;s review process by building out Local accounts. That wasn&rsquo;t the case. Before I knew it, I was supporting Local accounts, Feedbin, and Google Reader (both Miniflux and FreshRSS). This was a far cry from the original, simple vision of Capy as a Feedbin-only client.</p>\n<p>This brings me back to ReadYou&rsquo;s latest improvements. I&rsquo;m now considering forking ReadYou and using it as the basis of Capy Reader going forward. There are a few goals I have in mind that would make this unique:</p>\n<ul>\n<li>Feed discovery. Plugging in Capy Reader&rsquo;s existing feed finder to avoid having to search for exact feed URLs to add a feed.</li>\n<li>Feedbin and Miniflux support. These are components I can port from Capy&rsquo;s existing codebase.</li>\n<li>Inclusion in Google Play. In contrast, ReadYou is only available in F-Droid.</li>\n</ul>\n<p>There are two more considerations I want to highlight if I go this route. Capy Reader would be relicensed under <a href=\"https://www.gnu.org/licenses/gpl-3.0.en.html\">GPLv3</a>, and I&rsquo;d also want to build any revisions in a way that could be upstreamed to ReadYou.</p>\n<p>All of this is preliminary. These are untested ruminations, and talk is easy. If you have any reasons why you use ReadYou over Capy, or Capy over ReadYou, drop me a line <a href=\"https://mastodon.social/@_jocmp\">on Mastodon</a>!</p>\n",
        "date_published": "2025-08-22T16:18:34-05:00",
        "url": "https://jocmp.com/2025/08/22/the-guts-of-a-new/",
        "tags": ["capyreader","rss"]
      },
      {
        "id": "http://jocmp.micro.blog/2025/08/02/capy-log-open-in-browser/",
        "title": "Capy Log: Open In Browser, Article List Tweaks",
        "content_html": "<p>Summer in the midwest is careening towards autumn, and version <a href=\"https://github.com/jocmp/capyreader/releases/tag/2025.08.1153\">2025.08.1153</a> of Capy Reader is in review for the Play Store. I haven&rsquo;t been adding huge feature changes lately. Instead, I&rsquo;ve been trying to pick apart the app and understand some underlying jank that exists. More on that later. While there aren&rsquo;t huge changes in this release, I did get around to adding &ldquo;Open in browser&rdquo; as an option to view articles.</p>\n<h2 id=\"open-in-browser\">Open In Browser</h2>\n<p>&ldquo;Open in browser&rdquo; by default has been a long outstanding feature. It was <a href=\"https://github.com/jocmp/capyreader/discussions/715\">first requested in January</a> of this year. I feel bad sometimes when there&rsquo;s a huge delta between time requested and time implemented, but I spent a lot of time waffling on this feature.</p>\n<p>It&rsquo;s deceptively simple but the &ldquo;open in browser&rdquo; requires two key expectations</p>\n<ol>\n<li>The article opens in the browser</li>\n<li>The article is marked as read</li>\n</ol>\n<p>This second expectation prevents a direct call to an <code>ACTION_VIEW</code> intent since there is not a way to simultaneously launch two actions from a widget RemoteView. The trade-off then is to create a <a href=\"https://marcellogalhardo.dev/posts/2023/trampoline-activities/\">trampoline activity</a> which first opens the app with a transparent view, and then opens the browser. The trampoline activity can be avoided when the &ldquo;open in browser&rdquo; action is initiated within the app since the article state is already within context.</p>\n<p>Putting it all together, the new &ldquo;open in browser&rdquo; feature in Capy does what it says on the tin:</p>\n<p><video controls=\"controls\" playsinline=\"playsinline\" src=\"https://cdn.uploads.micro.blog/238475/2025/demo.mp4\" poster=\"https://jocmp.com/uploads/2025/poster.png\" preload=\"none\"></video></p>\n<h2 id=\"feed-selection-ui-improvements\">Feed Selection UI Improvements</h2>\n<p>One outstanding problem in Capy Reader has been feed list transitions. To spot the bug in previous versions:</p>\n<ol>\n<li>Scroll part way down a page, note the status and toolbar change color</li>\n<li>Open the feed list and select another feed</li>\n<li>Jank! The previous article list will scroll - or teleport - to the first index, and then the next feed will load in</li>\n</ol>\n<p>Here&rsquo;s an example of the problem at 4x speed. The top bar state jank is noticeable at the 10 second mark when it still appears as the changed color when the list has already switched to the next feed.</p>\n<p><video src=\"https://cdn.uploads.micro.blog/238475/2025/before.mp4\" poster=\"https://jocmp.com/uploads/2025/650a7c3a16.png\" controls=\"controls\" preload=\"metadata\"></video></p>\n<p>The solution I found was to <a href=\"https://github.com/jocmp/capyreader/pull/1354/commits/1431818cbc8717816273bc427770127ea76e8458\">rebuild the article pager</a> in the view layer. This in turn invalidates the list state which simultaneously invalidates the scrollbar state.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"><code class=\"language-kotlin\" data-lang=\"kotlin\"><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">import</span> androidx.paging.Pager\n</span></span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">import</span> androidx.paging.PagingConfig\n</span></span><span style=\"display:flex;\"><span>\n</span></span><span style=\"display:flex;\"><span><span style=\"color:#75715e\">// In View Model\n</span></span></span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">fun</span> <span style=\"color:#a6e22e\">buildPager</span>(): Pager {\n</span></span><span style=\"display:flex;\"><span>    <span style=\"color:#66d9ef\">return</span> Pager(\n</span></span><span style=\"display:flex;\"><span>        config = PagingConfig(\n</span></span><span style=\"display:flex;\"><span>            pageSize = <span style=\"color:#ae81ff\">50</span>,\n</span></span><span style=\"display:flex;\"><span>            prefetchDistance = <span style=\"color:#ae81ff\">10</span>,\n</span></span><span style=\"display:flex;\"><span>        ),\n</span></span><span style=\"display:flex;\"><span>        pagingSourceFactory = {\n</span></span><span style=\"display:flex;\"><span>            findArticles(<span style=\"color:#f92672\">..</span>.)\n</span></span><span style=\"display:flex;\"><span>        }\n</span></span><span style=\"display:flex;\"><span>    )\n</span></span><span style=\"display:flex;\"><span>}\n</span></span><span style=\"display:flex;\"><span>\n</span></span><span style=\"display:flex;\"><span><span style=\"color:#75715e\">// Pager is now in Compose view layer\n</span></span></span><span style=\"display:flex;\"><span><span style=\"color:#66d9ef\">val</span> articles = remember(<span style=\"color:#f92672\">..</span>.) {\n</span></span><span style=\"display:flex;\"><span>   viewModel.buildPager(<span style=\"color:#f92672\">..</span>.)\n</span></span><span style=\"display:flex;\"><span>}\n</span></span></code></pre></div><p>The last wrinkle with this approach is pager updates in response to in-feed actions. One example of this is swipe-to-refresh on the &ldquo;Unread&rdquo; filter. When the refresh finishes, articles that have been read disappear. If the invalidation flag - in this case a timestamp - is passed to the <code>remember</code> function then the feed will flash causing the list to flicker and jump back to the first index. Instead the solution is to track a separate variable within the view model. When the timestamp changes, the view-level <code>articles</code> variable <a href=\"https://github.com/jocmp/capyreader/pull/1365/files#diff-a3dc4554d8145d70c4d38aeebda102f8988a6794752336fe21357326112e00d7\">is refreshed</a> which triggers a new call to the <code>pagingSourceFactory</code>.</p>\n<p>Here&rsquo;s a demo putting it all together:</p>\n<p><video src=\"https://cdn.uploads.micro.blog/238475/2025/after.mp4\" poster=\"https://jocmp.com/uploads/2025/726aff4e1c.png\" controls=\"controls\" preload=\"metadata\"></video></p>\n<p>Something so subtle that you might not have even noticed, but your brain did.</p>\n<h2 id=\"whats-next\">What&rsquo;s next</h2>\n<p>In the next few updates I hope to add more settings around &ldquo;open in browser&rdquo; based on <a href=\"https://github.com/jocmp/capyreader/discussions/1306\">early feedback</a>. Additionally, I have an outstanding UI tweak around the <a href=\"https://github.com/jocmp/capyreader/discussions/1211\">local blocklists</a> that I really want to wrap up and deliver.</p>\n",
        "date_published": "2025-08-02T14:49:32-05:00",
        "url": "https://jocmp.com/2025/08/02/capy-log-open-in-browser/",
        "tags": ["capyreader","rss","programming"]
      },
      {
        "id": "http://jocmp.micro.blog/2025/07/06/the-next-version-of-capy/",
        "title": "Capy Log",
        "content_html": "<p>The next version of Capy Reader will reintroduce the &ldquo;Mark All Read&rdquo; button to the toolbar.</p>\n<p>The floating action button will still be an option, but I want to free up space for more complex UIs, specifically audio playback which will occupy the same bottom bar area.</p>\n<img src=\"https://cdn.uploads.micro.blog/238475/2025/mark-as-read.png\" width=\"600\" height=\"450\" alt=\"\">\n",
        "date_published": "2025-07-06T20:23:28-05:00",
        "url": "https://jocmp.com/2025/07/06/the-next-version-of-capy/",
        "tags": ["capyreader"]
      }
  ]
}
