This attempts to fix the issue described here: https://invent.kde.org/plasma-mobile/kasts/-/issues/20
There seemed to be a loop that occurs when setting an img width which causes the view to re-render which causes the window to grow which goes back to setting an img width causing an loop that keeps growing the img width and eventually crashing.
There are a few ways to fix this but I believe not setting a width on an img without a width both fixes it and behaves as expected (see context section). I'm not sure if this is a solution Kasts wants to go with but at the very least it adds more details to the issue.
## Reproducing
The gist of that issue is that a crash occurs when you visit https://feed.zugfunk-podcast.de/podcastrss.xml, episode 53 and this is reproducible.
I was able to get to the bottom of why that particular podcast episode crashes and can be reproduced with the following content
```html
<table style=\"width:30rem;\"><tbody><tr><td style=\"width:14rem;\">Some Text On Left </td><td><img src=\"https://invent.kde.org/plasma-mobile/kasts/-/raw/master/icons/128-apps-kasts.png\"></td></tr></tbody></table>
```
*(can repro by setting this string as a QStringLiteral in Entry.cpp, line 64 when the content is first set and then clicking on any episode)
## Context
The problem seems to be with `<img`s that don't have a width set. In those cases the code tries to set the image to the width of the component. The problem with this seems to be that this assumes that these images are on their own horizontal line and that they should take the whole width. So to repro (see content I used to repro above as an example):
* put an image tag next to some element that takes some width (like a table where there's a left column with some text and a right column in the right)
* img tag without a width
What ends up happening is that the `img width` gets updated to the size of the component width but because there's another element to the left of it, it will mean that the resulting view is bigger than the component width which causes `onWidthChanged`(`EntryPage.qml::88`) to be triggered and the `adjustedContent` function to be called again where this whole process happens again (img width is updated to component width -> rendered but it's larger than width -> causing onWidthChanged -> adjustedContent runs again -> rinse/repeat).
There are other ways to try to solve this but the three I looked at are:
1. After `adjustedContent` is run, it should update the actual `m_content` so that the following runs can work off the last text update (this will mean that the problematic `else` wouldn't be run constantly).
* You can do this by setting the content at the end of the function (`setContent(ret);`)
2. Checking for some reasonable width limit (if width > 10000 then width = 10000)
3. Not resizing an image without a width because we're not sure about the intention of the author
* in this case these were small icons for social media that shouldn't be scaled up
* I think we shouldn't scale any images because of the same reason but the PR is conservative and just stops it in the case of a img without a width
For the PR I went with # 3 because the others led to the icons being scaled but it messed up the look of the page.
Closes#20
This commit adds a bunch of API extensions (public and private) to the
entry, enclosure, etc classes to allow runtime updates of internal data.
Additionally, the feed update routine has been adapted to find updates
in entries, enclosures, etc and pass them on to the relevant objects.
All of this functionality is put behind a new toggle exposed in the
settings (default is on). This is useful since a full update takes
quite a bit longer on underpowered hardware, so users should be able to
switch off this potentially non-essential overhead.
BUG: 446158
This implements the gpodder API from scratch. It turned out that
libmygpo-qt has several critical bugs, and there's no response to pull
requests upstream. So using that library was not an option.
The implementation into kasts consists of the following:
- Can sync with gpodder.net or with a nextcloud server that has the
nextcloud-gpodder app installed. (This app is mostly API compatible
with gpodder.)
- Passwords are stored using qtkeychain. If the keychain is
unavailable it will fallback to file.
- It syncs podcast subscriptions and episode play positions, including
marking episodes as played. Episodes that have a non-zero play
position will be added to the queue automatically.
- It will check for a metered connection before syncing. This is
coupled to the allowMeteredFeedUpdates setting.
- Full synchronization can be performed either manually (from the
settings page) or through automatic triggers: on startup and/or on
feed refresh.
- There is an additional possibility to trigger quick upload-only syncs
to make sure that the local changes are immediately uploaded to the
server (if the connection allows). This will trigger when
subscriptions are added or removed, when the pause/play button is
toggled or an episode is marked as played.
- This implements a few safeguards to avoid having multiple feed URLS
pointing to the same underlying feed (e.g. http vs https). This
solves part of #17
Solves #13
This commit adds keyboard navigation to entry lists.
Selection of items can be done through keyboard (shift+up/down), mouse
(left, left+shift, left+ctrl) or touch (long press).
When items are selected, contextual actions will show up on
the page (useful for touch screens), or, alternatively, a context menu
with the same actions can be opened through right mouse click (useful
for desktop).
If a single entry is selected, then only the relevant actions will be
shown (e.g. only "Mark as Played" if the entry has not been played yet).
Additionally, (database) transactions for the actions have been
optimized. This was necessary to make sure that actions on large
selections of entries finish within an acceptable time. E.g. actions on
a list of 1000 items should finish within a few seconds (on all but
underpowered hardware).
BUG: 441764
For now this only works with NetworkManager. The related settings are
greyed out on systems not using NetworkManager.
Some details of the implementation:
- Implement settings in the settings menu to enable/disable feed
updates, episode downloads and/ or image downloads on metered
connections. If the option(s) is disabled, an overlay dialog is shown
with options to "not allow", "allow once", or "allow always".
- If the network is down, no attempt is made to download images and the
fallback image will be used until the network is up again.
This also solves an issue where the application hangs when the network
is down and feed images have not been cached yet.
- Next to this, part of the cachedImage implementation in Entry and Feed
has been refactored to re-use code as part of the image() method in
Fetcher.
- In case something unexpected happens, an error will be logged.
- This refactoring also includes a cleanup of a lot of header includes to
avoid circular dependencies.
- The error message will now be shown below the info message.
- Add database migration (for Errors)
This property returns the path to the cached image if it's been
downloaded, or return "" if it's not been downloaded yet, or "no-image"
in case the image property does not contain a URL to an image.