Compare commits
28 Commits
1.2.0+fork
...
v1.2.0+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92beac8dff | ||
|
|
ed1fdba9a5 | ||
|
|
5e194e3079 | ||
|
|
27c2791d6c | ||
|
|
d6bcc9c156 | ||
|
|
4c85fd4387 | ||
|
|
80d529d503 | ||
|
|
c5a19a2334 | ||
|
|
16857bebd9 | ||
|
|
1c340b7c66 | ||
|
|
7d9d8f0aae | ||
|
|
21fc35230c | ||
|
|
fc67c82040 | ||
|
|
4d04741fe0 | ||
|
|
5c7fe9dcb5 | ||
|
|
c3aa3af650 | ||
|
|
4a695b2a83 | ||
|
|
a8ba50e762 | ||
|
|
f79fc66578 | ||
|
|
4144639b75 | ||
|
|
0a8d73dc0b | ||
|
|
fd99f3caa1 | ||
|
|
794c4e5227 | ||
|
|
f5df8225d1 | ||
|
|
42c6446125 | ||
|
|
e3486ebf7c | ||
|
|
c0115f068c | ||
|
|
41682d1147 |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,8 +1,9 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: LucasGGamerM
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
patreon: # mastodon
|
patreon: # mastodon
|
||||||
open_collective: # Replace with a single Open Collective username e.g., user1
|
open_collective: # Replace with a single Open Collective username e.g., user1
|
||||||
|
ko_fi: xsk22
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
liberapay: # Replace with a single Liberapay username e.g., user1
|
liberapay: # Replace with a single Liberapay username e.g., user1
|
||||||
|
|||||||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,6 +22,8 @@ Steps to reproduce the behavior:
|
|||||||
**Does this happen in the official app?**
|
**Does this happen in the official app?**
|
||||||
|
|
||||||
Does this issue also occur with the respective upstream release?
|
Does this issue also occur with the respective upstream release?
|
||||||
|
(Please test using the respective `upstream-xxxxxx.apk` provided in [Releases](https://github.com/sk22/megalodon/releases) or at least using the current Mastodon version from the Play Store)
|
||||||
|
|
||||||
> No / Yes
|
> No / Yes
|
||||||
|
|
||||||
> In case it does, please consider filing an [upstream bug report](https://github.com/mastodon/mastodon-android/issues) instead.
|
> In case it does, please consider filing an [upstream bug report](https://github.com/mastodon/mastodon-android/issues) instead.
|
||||||
@@ -33,7 +35,7 @@ If applicable, add screenshots (and screen recordings, if possible) to help expl
|
|||||||
|
|
||||||
**Version**
|
**Version**
|
||||||
|
|
||||||
Moshidon version: [e.g. v1.1.4+fork.#]
|
Megalodon version: [e.g. v1.1.4+fork.#]
|
||||||
|
|
||||||
**Crash log**
|
**Crash log**
|
||||||
|
|
||||||
|
|||||||
167
README.md
167
README.md
@@ -1,42 +1,25 @@
|
|||||||

|

|
||||||
|
|
||||||
# Moshidon, the material you mastodon client!
|
# Megalodon
|
||||||
|
|
||||||
> A fork of [megalodon](https://github.com/sk22/megalodon) which is a fork of [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly won’t ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
|
[](https://translate.codeberg.org/engage/megalodon/)
|
||||||
|
|
||||||
|
[](https://github.com/sk22/megalodon/releases/latest/download/megalodon.apk)
|
||||||
|
|
||||||
|
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
|
||||||
|
|
||||||
|
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
|
||||||
|
|
||||||
[](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
|
> A fork of the [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly won’t ever be implemented, such as the federated timeline, unlisted posting and an image description viewer.
|
||||||
|
|
||||||
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
|
||||||
alt="Get it on IzzyOnDroid"
|
|
||||||
height="80">](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda)
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
## Key features
|
## Key features
|
||||||
|
|
||||||
### **The ability to add new custom local timelines!**
|
|
||||||
|
|
||||||
### **Material you theme support on Android 12+ devices!**
|
|
||||||
|
|
||||||
### **Show posts filtered with a warning!**
|
|
||||||
|
|
||||||
**Allows you to have filtered posts collapsed with a warning! As shown in the screenshots:**
|
|
||||||
|
|
||||||
Before | After
|
|
||||||
:-------------------------:|:-------------------------:
|
|
||||||
 | 
|
|
||||||
|
|
||||||
|
|
||||||
### **Color themes**
|
|
||||||
|
|
||||||
**Allows you to change theme within the app. Supports Purple, pink, green, blue, orange and yellow!**
|
|
||||||
|
|
||||||
### **Unlisted posting**
|
### **Unlisted posting**
|
||||||
|
|
||||||
**Allows you to post publicly without having your post show up in trends, hashtags or public timelines (i.e., in the tabs “Local”, “Community” and “Posts”).**
|
**Allows you to post publicly without having your post show up in trends, hashtags or public timelines (i.e., in the tabs “Community”, “Federated” and “Posts”).**
|
||||||
|
|
||||||
When posting with Unlisted visibility, your posts will still be publicly accessible in your profile. They will also be shown in people’s Home timelines, but only if they follow you or someone they follow reposted/replied to your post.
|
When posting with Unlisted visibility, your posts will still be publicly accessible in your profile. They will also be shown in people’s Home timelines, but only if they follow you or someone they follow reblogged/replied to your post.
|
||||||
|
|
||||||
The Mastodon documentation has some more information about [Unlisted posting](https://docs.joinmastodon.org/user/posting/#unlisted) and [Public timelines](https://docs.joinmastodon.org/user/network/#timelines).
|
The Mastodon documentation has some more information about [Unlisted posting](https://docs.joinmastodon.org/user/posting/#unlisted) and [Public timelines](https://docs.joinmastodon.org/user/network/#timelines).
|
||||||
|
|
||||||
@@ -48,6 +31,12 @@ Despite being one of the main features of federated social media, the Federated
|
|||||||
|
|
||||||
That’s one of the reasons why choosing a small, **well-moderated instance is important**. Instance admins and moderators should always make sure to ban abusive users and stop federating with instances who platform them. On well-moderated instances, the Federated timeline can be a welcoming place to meet new people!
|
That’s one of the reasons why choosing a small, **well-moderated instance is important**. Instance admins and moderators should always make sure to ban abusive users and stop federating with instances who platform them. On well-moderated instances, the Federated timeline can be a welcoming place to meet new people!
|
||||||
|
|
||||||
|
### **Draft and schedule posts**
|
||||||
|
|
||||||
|
**Allows for preparing a post and scheduling it to send it automatically at a specific time.**
|
||||||
|
|
||||||
|
You can create drafts, edit them, send them manually later or set a scheduled date. Drafts are technically saved as scheduled posts, so you can view and edit them from other apps that support scheduled posts. Scheduled posts are handled by your home instance, so they'll work even if you uninstall Megalodon.
|
||||||
|
|
||||||
### **Image description viewer**
|
### **Image description viewer**
|
||||||
|
|
||||||
**Allows you to quickly check whether an image or video has an alternative text attached to it.**
|
**Allows you to quickly check whether an image or video has an alternative text attached to it.**
|
||||||
@@ -60,29 +49,71 @@ This is important to **ensure the content you’re sharing is as accessible as p
|
|||||||
|
|
||||||
On the Fediverse, it’s quite common for people to pin posts they want others to read before following them. You can pin/unpin posts yourself by clicking the `⋯` button in the top right corner of your posts.
|
On the Fediverse, it’s quite common for people to pin posts they want others to read before following them. You can pin/unpin posts yourself by clicking the `⋯` button in the top right corner of your posts.
|
||||||
|
|
||||||
### **Bookmarks**
|
|
||||||
|
|
||||||
**They allow for quickly saving posts and viewing them through the Bookmarks button on the top right of your profile.**
|
|
||||||
|
|
||||||
To bookmark a post, press the button between the Favorite and Share buttons on the bottom of the post. Bookmarks are saved privately, so the post authors won’t know you saved their post – the list of bookmarked posts is only visible to you.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Press the download button above to download the APK. Open the downloaded file on your Android device to install it. Moshidon will automatically notify you about new updates inside the app.**
|
### IzzyOnDroid
|
||||||
|
|
||||||
To install this app on your Android device, download the [latest release from GitHub](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk) and open it. You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
|
[apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk)
|
||||||
|
|
||||||
Moshidon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)’s automatic update checker. Moshidon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
|
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
|
||||||
|
|
||||||
|
Note that you'll need to add Izzy's F-Droid repository to your F-Droid app first:
|
||||||
|
|
||||||
|
[`https://apt.izzysoft.de/fdroid/repo`](https://apt.izzysoft.de/fdroid/repo)
|
||||||
|
|
||||||
|
### Google Play Store
|
||||||
|
|
||||||
|
[play.google.com/store/apps/details?id=org.joinmastodon.android.sk](https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk)
|
||||||
|
|
||||||
|
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.sk"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
|
||||||
|
|
||||||
|
### F-Droid
|
||||||
|
|
||||||
|
**[F-Droid.org?](https://f-droid.org)** Not yet, sorry!
|
||||||
|
|
||||||
|
If you want, you can help me figure out if something's missing in the [Issue #47: F-Droid.org](https://github.com/sk22/megalodon/issues/47)
|
||||||
|
|
||||||
|
### Direct
|
||||||
|
|
||||||
|
Press the download button to download the APK. Open the downloaded file on your Android device to install it. Megalodon will automatically notify you about new updates inside the app.
|
||||||
|
|
||||||
|
[](https://github.com/sk22/megalodon/releases/latest/download/megalodon.apk)
|
||||||
|
|
||||||
|
You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/sk22/megalodon/releases) page.
|
||||||
|
|
||||||
|
Megalodon makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)’s automatic update checker. Megalodon will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Moshidon is also available in [IzzyOnDroid repo](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda), compatible with all F-Droid clients. The APK provided here is the same as the one included in the Releases.
|
|
||||||
|
|
||||||
## Release variants
|
## Release variants
|
||||||
|
|
||||||
All downloads can be found on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
|
All downloads can be found on the [Releases](https://github.com/sk22/megalodon/releases) page.
|
||||||
|
|
||||||
**`moshidon.apk`**
|
**`megalodon.apk`**
|
||||||
|
|
||||||
|
Variant with an integrated updater. If you download Megalodon from here (and not from an app store), just download the regular `megalodon.apk`.
|
||||||
|
|
||||||
|
**`upstream-1234abc.apk`**
|
||||||
|
|
||||||
|
This is an **unmodified version** of the official [Mastodon for Android](https://github.com/mastodon/mastodon-android) app the respective Megalodon release is based on. Should you find any bugs in Megalodon (which you will), try to see if it occurs with this variant, too. The last 7 digits of the file name are important to know which version of the official app you're using.
|
||||||
|
|
||||||
|
<!-- **`megalodon-fdroid.apk`**
|
||||||
|
|
||||||
|
Variant without the integrated updater. This is the variant to be published to F-Droid.org where an integrated updater is not necessary. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contribution
|
||||||
|
|
||||||
|
### Translation
|
||||||
|
|
||||||
|
As with the source code, the translation is sourced from the official project, which you can contribute to on the official “**Mastodon for Android**” Crowdin project: https://crowdin.com/project/mastodon-for-android
|
||||||
|
|
||||||
|
There's also a handful of custom strings exclusive to this projects that would need to be translated. You can help translate **Megalodon** on Weblate: https://translate.codeberg.org/projects/megalodon/
|
||||||
|
|
||||||
|
[](https://translate.codeberg.org/engage/megalodon/)
|
||||||
|
|
||||||
Variant with an integrated updater. If you download Moshidon from here (and not from an app store), just download the regular `moshidon.apk`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -91,23 +122,16 @@ Variant with an integrated updater. If you download Moshidon from here (and not
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* [Adding the ability to have filtered posts show with a warning](https://github.com/LucasGGamerM/moshidon/tree/feature/filters_again)
|
|
||||||
* [Add “Unlisted” as a post visibility option](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/enable-unlisted)
|
* [Add “Unlisted” as a post visibility option](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/enable-unlisted)
|
||||||
([Pull request](https://github.com/mastodon/mastodon-android/pull/103))
|
([Pull request](https://github.com/mastodon/mastodon-android/pull/103))
|
||||||
* Adding a useful private profile note box!*
|
* [Add “Federation” tab and change Discover tab order](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/add-federated-timeline) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/8))
|
||||||
* Auto hiding the compose button on scroll!*
|
|
||||||
* Adding the ability to remind yourself to add alt text to images!*
|
|
||||||
* An indicator for if an image has alt text or not*
|
|
||||||
* Adding the ability to have drafts!*
|
|
||||||
* Also adding the ability to view announcements from your instance!*
|
|
||||||
* Adding the ability to post for local timeline only (Only on instances that support it!)*
|
|
||||||
* [Add image description button and viewer](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
|
* [Add image description button and viewer](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
|
||||||
* [Implement pinning posts and displaying pinned posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/pin-posts) ([Pull request](https://github.com/mastodon/mastodon-android/pull/140))
|
* [Implement pinning posts and displaying pinned posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/pin-posts) ([Pull request](https://github.com/mastodon/mastodon-android/pull/140))
|
||||||
* [Implement deleting and re-drafting](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/delete-redraft) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/21))
|
* [Implement deleting and re-drafting](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/delete-redraft) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/21))
|
||||||
* [Implement a bookmark button and list](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/bookmarks) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/22))
|
* [Implement a bookmark button and list](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/bookmarks) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/22))
|
||||||
* [Add “Check for update” button in addition to integrated update checker](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/check-for-update-button)
|
* [Add “Check for update” button in addition to integrated update checker](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/check-for-update-button)
|
||||||
* [Add “Mark media as sensitive” option](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/mark-media-as-sensitive)
|
* [Add “Mark media as sensitive” option](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/mark-media-as-sensitive)
|
||||||
* [Add settings to hide replies and reposts from the timeline](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/filter-home-timeline) ([Pull request](https://github.com/mastodon/mastodon-android/pull/317))
|
* [Add settings to hide replies and reblogs from the timeline](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/filter-home-timeline) ([Pull request](https://github.com/mastodon/mastodon-android/pull/317))
|
||||||
* [Follow and unfollow hashtags](https://github.com/sk22/megalodon/commit/7d38f031f197aa6cefaf53e39d929538689c1e4e) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/233))
|
* [Follow and unfollow hashtags](https://github.com/sk22/megalodon/commit/7d38f031f197aa6cefaf53e39d929538689c1e4e) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/233))
|
||||||
* [Notification bell for posts](https://github.com/sk22/megalodon/commit/b166ca705eb9169025ef32bbe6315b42491b57ea) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/81))
|
* [Notification bell for posts](https://github.com/sk22/megalodon/commit/b166ca705eb9169025ef32bbe6315b42491b57ea) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/81))
|
||||||
* [Viewing lists and adding/removing users from lists](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:list-timeline-views) based on [@obstsalatschuessel](https://github.com/obstsalatschuessel)'s [Pull request](https://github.com/mastodon/mastodon-android/pull/286)
|
* [Viewing lists and adding/removing users from lists](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:list-timeline-views) based on [@obstsalatschuessel](https://github.com/obstsalatschuessel)'s [Pull request](https://github.com/mastodon/mastodon-android/pull/286)
|
||||||
@@ -117,12 +141,23 @@ Variant with an integrated updater. If you download Moshidon from here (and not
|
|||||||
* [Add notifications tab for posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/posts-notifications-tab)
|
* [Add notifications tab for posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/posts-notifications-tab)
|
||||||
* [Show visibility of original post when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-reply-visibility)
|
* [Show visibility of original post when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/display-reply-visibility)
|
||||||
* [Clickable reply/boost line above posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:clickable-boost-reply-line)
|
* [Clickable reply/boost line above posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:clickable-boost-reply-line)
|
||||||
* [Clickable reply line while replying to open original post](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/clickable-reply-line-compose)
|
* [Add push notification setting for post notifications](https://github.com/sk22/megalodon/commit/b190480d7739be47f23543d9e7644660f9b4b4ee)
|
||||||
|
* [Add option to allow voting for multiple options on polls](https://github.com/sk22/megalodon/commit/5b28468efd49387b4f8b83f142f3adf3104ca60c)
|
||||||
|
* [Add translate function](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/translate-button)
|
||||||
|
* [Add language selector](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/language-selector)
|
||||||
|
* [Implement deleting notifications](https://github.com/sk22/megalodon/commit/b0f9ce081f69f29ad59658fc00ca41372cd2677d) (disabled by default)
|
||||||
|
* [Long-click boost button to "quote" a post](https://github.com/sk22/megalodon/commit/b25a237c20c6a924ed4d9b357999867c3a32b32b)
|
||||||
|
* [Draft and schedule posts](https://github.com/sk22/megalodon/pull/217)
|
||||||
|
* [Display original post when replying](https://github.com/sk22/megalodon/commit/375f8ceb2747705fedf43686681cc0e0b812f899)
|
||||||
|
* [Display server announcements](https://github.com/sk22/megalodon/commit/84179bc207d6b69cc2a770a3c28fa0a39b0b54e8)
|
||||||
|
* [Create](https://github.com/sk22/megalodon/commit/294595513a45037359b31377aafc25ae5b58d8e7), [edit](https://github.com/sk22/megalodon/commit/d47797bf7ac8cff3f9ba1cfee219a1bb2af21da6) and [delete](https://github.com/sk22/megalodon/commit/54c29fd787fc2cd0dfd2787ad796b8190f795973) lists
|
||||||
|
* [Soft-blocking (by blocking and immediately unblocking)](https://github.com/sk22/megalodon/commit/e75d350b7a2709259e9fc5138e0e1f361bdb0972)
|
||||||
|
* [Pinnable custom timelines](https://github.com/sk22/megalodon/pull/338/commits)
|
||||||
|
* Support for local-only posts
|
||||||
|
|
||||||
|
|
||||||
### Behavior
|
### Behavior
|
||||||
|
|
||||||
* Adding a bottom option for the publish button, allowing for easier use on larger screens!
|
|
||||||
* [Make back button return to the home tab before exiting the app](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/back-returns-home) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/118))
|
* [Make back button return to the home tab before exiting the app](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/back-returns-home) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/118))
|
||||||
* [Always preserve content warnings when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/always-preserve-cw) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/113))
|
* [Always preserve content warnings when replying](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/always-preserve-cw) ([Closes issue](https://github.com/mastodon/mastodon-android/issues/113))
|
||||||
* [Display full image when adding image description](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/compose-image-description-full-image) ([Pull request](https://github.com/mastodon/mastodon-android/pull/182))
|
* [Display full image when adding image description](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/compose-image-description-full-image) ([Pull request](https://github.com/mastodon/mastodon-android/pull/182))
|
||||||
@@ -130,6 +165,20 @@ Variant with an integrated updater. If you download Moshidon from here (and not
|
|||||||
* [Option to hide interaction numbers](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:settings/hide-interaction-numbers)
|
* [Option to hide interaction numbers](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:settings/hide-interaction-numbers)
|
||||||
* [Option to always reveal content warnings](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/cw-above-text)
|
* [Option to always reveal content warnings](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/cw-above-text)
|
||||||
* [Option to disable scrolling title bars](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:settings/disable-marquee)
|
* [Option to disable scrolling title bars](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:settings/disable-marquee)
|
||||||
|
* [No ellipsis for long poll answers](https://github.com/mastodon/mastodon-android/commit/c9aae828e2518adccdc092e41f8d1f0489636271)
|
||||||
|
* [Show poll vote button for multiple and single answer polls](https://github.com/mastodon/mastodon-android/commit/e14dfda2fdf32f0fa3043504ac5831683a87559a)
|
||||||
|
* [Show own vote after voting](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28) ([Closes issue](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28))
|
||||||
|
* [Make inline emoji search case-insensitive and don't only search from start of emoji names](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:better-inline-emoji-search) ([Pull request](https://github.com/mastodon/mastodon-android/pull/445))
|
||||||
|
* [Include subject line when sharing e.g. a website to Megalodon](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:external-share-include-subject)
|
||||||
|
* [Improve semantics for voting on polls (radio buttons and checkboxes)](https://github.com/sk22/megalodon/commit/6fd58c96827cb1d2da329cebdc170a1425dd18d7)
|
||||||
|
* [Copy post URL when long-pressing share button](https://github.com/sk22/megalodon/commit/ba36347f03278763ecec617b1ce57ba89db7be72)
|
||||||
|
* [Add option to disable swiping between tabs](https://github.com/sk22/megalodon/commit/1f20b21fc84bf006c1ec14bd2229cbfad5215ec8)
|
||||||
|
* [Resolve Fediverse links in the app](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/open-urls-in-app)
|
||||||
|
* [Preserve whitespaces in HTML](https://github.com/sk22/megalodon/commit/7d876bddc7a07d98f0fecbf62b13bdb9fcce3412)
|
||||||
|
* [Long-click to copy links](https://github.com/sk22/megalodon/commit/b32e32274923a94742a9926ef38785f746d41405)
|
||||||
|
* Improved filtering using Mastodon 4.0 API: [#202](https://github.com/sk22/megalodon/pull/202), [#212](https://github.com/sk22/megalodon/pull/212), [#255](https://github.com/sk22/megalodon/pull/255) by [@thiagojedi](https://github.com/thiagojedi)
|
||||||
|
* [Support admin notifications](https://github.com/sk22/megalodon/commit/c12a6eaee6b609bc53eb0a45d9199f37d5241801) and [notifications for edited reblogged posts](https://github.com/sk22/megalodon/commit/900e8fb2e9353002c16d15e06b78d2731e121601)
|
||||||
|
* [Android file opener added back in addition to image picker](https://github.com/sk22/megalodon/commit/3a6ace53d5ab01e28077c9c930cb6ed487b78031)
|
||||||
|
|
||||||
|
|
||||||
### Visual
|
### Visual
|
||||||
@@ -137,6 +186,16 @@ Variant with an integrated updater. If you download Moshidon from here (and not
|
|||||||
* [Custom extended footer redesign](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:compact-extended-footer)
|
* [Custom extended footer redesign](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:compact-extended-footer)
|
||||||
* [Improvements to the true black mode](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:true-black-improvements)
|
* [Improvements to the true black mode](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:true-black-improvements)
|
||||||
* [Profile header tweaks](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:ui/profile-header-tweaks)
|
* [Profile header tweaks](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:ui/profile-header-tweaks)
|
||||||
|
* [Custom color themes](https://github.com/sk22/megalodon/pull/124) by [@LucasGGamerM](https://github.com/LucasGGamerM)
|
||||||
|
* [Custom "megalodon" text logo](https://github.com/sk22/megalodon/commit/563afd487ca5c608cfbb00fa3909d3c27384acc0) by [@LucasGGamerM](https://github.com/LucasGGamerM)
|
||||||
|
* [Custom login screen](https://github.com/sk22/megalodon/commit/9bbf8c4618dbe13accaeb3b5482bf3fe88cac4c0)
|
||||||
|
* [More distinct filled boost icon](https://github.com/sk22/megalodon/commits/more-distinct-filled-boost-icon)
|
||||||
|
* Material You color theme by [@LucasGGamerM](https://github.com/LucasGGamerM)
|
||||||
|
* [Animations for interaction buttons](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/animate-buttons)
|
||||||
|
* [Dedicated icons for different notification types](https://github.com/sk22/megalodon/pull/178) by [@florian-obernberger](https://github.com/florian-obernberger)
|
||||||
|
* Scale text according to system settings
|
||||||
|
* Header in timeline for followed hashtags
|
||||||
|
* [Indicator for missing alt texts](https://github.com/sk22/megalodon/commit/c0c276f03e793b78c478c17dfdef24a66ef7cedb)
|
||||||
|
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
@@ -153,6 +212,4 @@ This project is released under the [GPL-3 License](./LICENSE).
|
|||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
[Official matrix chatroom:](https://matrix.to/#/#moshidon:matrix.org) https://matrix.to/#/#moshidon:matrix.org
|
<a rel="me" href="https://floss.social/@megalodon">@megalodon<wbr>@floss.social</a>
|
||||||
|
|
||||||
<a rel="me" href="https://floss.social/@moshidon">@moshidon<wbr>@floss.social</a>
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
title: Moshidon
|
title: Megalodon
|
||||||
layout: default
|
layout: default
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Moshidon</title>
|
<title>Megalodon</title>
|
||||||
<link rel="icon" href="mastodon/src/main/res/mipmap-mdpi/ic_launcher_round.png">
|
<link rel="icon" href="mastodon/src/main/res/mipmap-mdpi/ic_launcher_round.png">
|
||||||
<link rel="me" href="https://floss.social/@mastodon">
|
<link rel="me" href="https://floss.social/@mastodon">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
|
||||||
@@ -14,4 +14,4 @@
|
|||||||
{{ content }}
|
{{ content }}
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -5,14 +5,14 @@ plugins {
|
|||||||
android {
|
android {
|
||||||
compileSdk 33
|
compileSdk 33
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
archivesBaseName = "moshidon"
|
archivesBaseName = "megalodon"
|
||||||
applicationId "org.joinmastodon.android.moshinda"
|
applicationId "org.joinmastodon.android.sk"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 97
|
versionCode 77
|
||||||
versionName "1.2.0+fork.97.moshinda"
|
versionName "1.2.0+fork.77"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "nl-rNL", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
|
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -115,7 +115,7 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
|
|||||||
|
|
||||||
private void actuallyCheckForUpdates(){
|
private void actuallyCheckForUpdates(){
|
||||||
Request req=new Request.Builder()
|
Request req=new Request.Builder()
|
||||||
.url("https://api.github.com/repos/LucasGGamerM/moshidon/releases")
|
.url("https://api.github.com/repos/sk22/megalodon/releases")
|
||||||
.build();
|
.build();
|
||||||
Call call=MastodonAPIController.getHttpClient().newCall(req);
|
Call call=MastodonAPIController.getHttpClient().newCall(req);
|
||||||
try(Response resp=call.execute()){
|
try(Response resp=call.execute()){
|
||||||
@@ -153,7 +153,7 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
|
|||||||
Log.d(TAG, "actuallyCheckForUpdates: new version: "+version);
|
Log.d(TAG, "actuallyCheckForUpdates: new version: "+version);
|
||||||
for(JsonElement el:obj.getAsJsonArray("assets")){
|
for(JsonElement el:obj.getAsJsonArray("assets")){
|
||||||
JsonObject asset=el.getAsJsonObject();
|
JsonObject asset=el.getAsJsonObject();
|
||||||
if("moshidon.apk".equals(asset.get("name").getAsString()) && "application/vnd.android.package-archive".equals(asset.get("content_type").getAsString()) && "uploaded".equals(asset.get("state").getAsString())){
|
if("megalodon.apk".equals(asset.get("name").getAsString()) && "application/vnd.android.package-archive".equals(asset.get("content_type").getAsString()) && "uploaded".equals(asset.get("state").getAsString())){
|
||||||
long size=asset.get("size").getAsLong();
|
long size=asset.get("size").getAsLong();
|
||||||
String url=asset.get("browser_download_url").getAsString();
|
String url=asset.get("browser_download_url").getAsString();
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
|
|
||||||
<path android:pathData="M3.897 4.054L3.97 3.97c0.266-0.267 0.683-0.29 0.976-0.073L5.03 3.97 10 8.939l4.97-4.97c0.266-0.266 0.683-0.29 0.976-0.072L16.03 3.97c0.267 0.266 0.29 0.683 0.073 0.976L16.03 5.03 11.061 10l4.97 4.97c0.266 0.266 0.29 0.683 0.072 0.976L16.03 16.03c-0.266 0.267-0.683 0.29-0.976 0.073L14.97 16.03 10 11.061l-4.97 4.97c-0.266 0.266-0.683 0.29-0.976 0.072L3.97 16.03c-0.267-0.266-0.29-0.683-0.073-0.976L3.97 14.97 8.939 10l-4.97-4.97C3.704 4.764 3.68 4.347 3.898 4.054L3.97 3.97 3.897 4.054z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
|
||||||
<path android:pathData="M22 6.5c0 3.038-2.462 5.5-5.5 5.5S11 9.538 11 6.5 13.462 1 16.5 1 22 3.462 22 6.5zm-7.146-2.354c-0.196-0.195-0.512-0.195-0.708 0-0.195 0.196-0.195 0.512 0 0.708L15.793 6.5l-1.647 1.646c-0.195 0.196-0.195 0.512 0 0.707 0.196 0.196 0.512 0.196 0.708 0L16.5 7.208l1.646 1.647c0.196 0.195 0.512 0.195 0.708 0 0.195-0.196 0.195-0.512 0-0.707L17.207 6.5l1.647-1.646c0.195-0.196 0.195-0.512 0-0.708-0.196-0.195-0.512-0.195-0.708 0L16.5 5.793l-1.646-1.647zM19.5 14v-1.732c0.551-0.287 1.056-0.651 1.5-1.078v7.56c0 1.733-1.357 3.15-3.066 3.245L17.75 22H6.25c-1.733 0-3.15-1.357-3.245-3.066L3 18.75V7.25C3 5.517 4.356 4.1 6.066 4.005L6.25 4h4.248c-0.198 0.474-0.34 0.977-0.422 1.5H6.25c-0.918 0-1.671 0.707-1.744 1.606L4.5 7.25V14H9c0.38 0 0.694 0.282 0.743 0.648L9.75 14.75C9.75 15.993 10.757 17 12 17c1.19 0 2.166-0.925 2.245-2.096l0.005-0.154c0-0.38 0.282-0.694 0.648-0.743L15 14h4.5zm-15 1.5v3.25c0 0.918 0.707 1.671 1.606 1.744L6.25 20.5h11.5c0.918 0 1.671-0.707 1.744-1.607L19.5 18.75V15.5h-3.825c-0.335 1.648-1.75 2.904-3.475 2.995L12 18.5c-1.747 0-3.215-1.195-3.632-2.812L8.325 15.5H4.5z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" android:viewportWidth="28" android:viewportHeight="28">
|
|
||||||
<path android:pathData="M26 7.5c0 3.59-2.91 6.5-6.5 6.5S13 11.09 13 7.5 15.91 1 19.5 1 26 3.91 26 7.5zm-9.146-3.354c-0.196-0.195-0.512-0.195-0.708 0-0.195 0.196-0.195 0.512 0 0.708L18.793 7.5l-2.647 2.646c-0.195 0.196-0.195 0.512 0 0.708 0.196 0.195 0.512 0.195 0.708 0L19.5 8.207l2.646 2.647c0.196 0.195 0.512 0.195 0.708 0 0.195-0.196 0.195-0.512 0-0.708L20.207 7.5l2.647-2.646c0.195-0.196 0.195-0.512 0-0.708-0.196-0.195-0.512-0.195-0.708 0L19.5 6.793l-2.646-2.647zM25 22.75V12.6c-0.443 0.476-0.947 0.896-1.5 1.245V16h-6l-0.102 0.007c-0.366 0.05-0.648 0.363-0.648 0.743 0 1.519-1.231 2.75-2.75 2.75s-2.75-1.231-2.75-2.75l-0.007-0.102C11.193 16.282 10.88 16 10.5 16h-6V7.25c0-0.966 0.784-1.75 1.75-1.75h6.02c0.145-0.525 0.345-1.028 0.595-1.5H6.25C4.455 4 3 5.455 3 7.25v15.5C3 24.545 4.455 26 6.25 26h15.5c1.795 0 3.25-1.455 3.25-3.25zm-20.5 0V17.5h5.316l0.041 0.204C10.291 19.592 11.982 21 14 21l0.215-0.005c1.994-0.1 3.627-1.574 3.969-3.495H23.5v5.25c0 0.966-0.784 1.75-1.75 1.75H6.25c-0.966 0-1.75-0.784-1.75-1.75z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
|
|
||||||
<path android:pathData="M10 2c4.418 0 8 3.582 8 8 0 2.706-1.142 4.5-3 4.5-1.226 0-2.14-0.781-2.62-2.09C11.784 13.393 10.781 14 9.5 14 7.36 14 6 12.307 6 10c0-2.337 1.313-4 3.5-4 1.052 0 1.901 0.385 2.5 1.044V6.5C12 6.224 12.224 6 12.5 6c0.245 0 0.45 0.177 0.492 0.41L13 6.5V10c0 2.223 0.813 3.5 2 3.5s2-1.277 2-3.5c0-3.866-3.134-7-7-7s-7 3.134-7 7 3.134 7 7 7c0.823 0 1.626-0.142 2.383-0.416 0.26-0.094 0.547 0.04 0.64 0.3 0.095 0.26-0.04 0.546-0.3 0.64C11.859 17.838 10.94 18 10 18c-4.418 0-8-3.582-8-8s3.582-8 8-8zM9.5 7C7.924 7 7 8.17 7 10c0 1.797 0.966 3 2.5 3s2.5-1.203 2.5-3c0-1.83-0.924-3-2.5-3z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
|
||||||
<path android:pathData="M6.25 4.5C5.283 4.5 4.5 5.284 4.5 6.25v11.5c0 0.966 0.783 1.75 1.75 1.75h11.5c0.966 0 1.75-0.784 1.75-1.75v-4c0-0.414 0.335-0.75 0.75-0.75 0.414 0 0.75 0.336 0.75 0.75v4c0 1.795-1.456 3.25-3.25 3.25H6.25C4.455 21 3 19.545 3 17.75V6.25C3 4.455 4.455 3 6.25 3h4C10.664 3 11 3.336 11 3.75S10.664 4.5 10.25 4.5h-4zM13 3.75C13 3.336 13.335 3 13.75 3h6.5C20.664 3 21 3.336 21 3.75v6.5c0 0.414-0.336 0.75-0.75 0.75s-0.75-0.336-0.75-0.75V5.56l-5.22 5.22c-0.293 0.293-0.768 0.293-1.06 0-0.293-0.293-0.293-0.768 0-1.06l5.22-5.22h-4.69C13.335 4.5 13 4.164 13 3.75z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
|
||||||
<path android:pathData="M8.502 11.5c0.554 0 1.002 0.448 1.002 1.002 0 0.553-0.448 1.002-1.002 1.002-0.553 0-1.002-0.449-1.002-1.002 0-0.554 0.449-1.003 1.002-1.003zM12 4.353v6.651h7.442L17.72 9.28c-0.267-0.266-0.29-0.683-0.073-0.977L17.72 8.22c0.266-0.266 0.683-0.29 0.976-0.072L18.78 8.22l2.997 2.998c0.266 0.266 0.29 0.682 0.073 0.976l-0.073 0.084-2.996 3.003c-0.293 0.294-0.767 0.294-1.06 0.002-0.267-0.266-0.292-0.683-0.075-0.977l0.073-0.084 1.713-1.717h-7.431L12 19.25c0 0.466-0.421 0.82-0.88 0.738l-8.5-1.501C2.26 18.424 2 18.112 2 17.748V5.75c0-0.368 0.266-0.681 0.628-0.74l8.5-1.396C11.585 3.539 12 3.89 12 4.354zm-1.5 0.883l-7 1.15v10.732l7 1.236V5.237zM13 18.5h0.765l0.102-0.007c0.366-0.05 0.649-0.364 0.648-0.744l-0.007-4.25H13v5zm0.002-8.502L13 8.726V5h0.745c0.38 0 0.693 0.281 0.743 0.647l0.007 0.101L14.502 10h-1.5z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
|
||||||
<path android:pathData="M14.704 3.44C14.895 3.667 15 3.953 15 4.248V19.75c0 0.69-0.56 1.25-1.25 1.25-0.296 0-0.582-0.105-0.808-0.296l-4.967-4.206H4.25c-1.243 0-2.25-1.008-2.25-2.25v-4.5c0-1.243 1.007-2.25 2.25-2.25h3.725l4.968-4.204c0.526-0.446 1.315-0.38 1.761 0.147zM13.5 4.787l-4.975 4.21H4.25c-0.414 0-0.75 0.337-0.75 0.75v4.5c0 0.415 0.336 0.75 0.75 0.75h4.275L13.5 19.21V4.787z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" android:viewportWidth="28" android:viewportHeight="28">
|
|
||||||
<path android:pathData="M16.5 4.814c0-1.094-1.307-1.66-2.105-0.912l-4.937 4.63C9.134 8.836 8.706 9.005 8.261 9.005H5.25C3.455 9.005 2 10.46 2 12.255v3.492c0 1.795 1.455 3.25 3.25 3.25h3.012c0.444 0 0.872 0.17 1.196 0.473l4.937 4.626c0.799 0.748 2.105 0.182 2.105-0.912V4.814zm-6.016 4.812L15 5.39v17.216l-4.516-4.232c-0.602-0.564-1.397-0.878-2.222-0.878H5.25c-0.966 0-1.75-0.784-1.75-1.75v-3.492c0-0.966 0.784-1.75 1.75-1.75h3.011c0.826 0 1.62-0.314 2.223-0.88z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
|
||||||
<path android:pathData="M3.28 2.22c-0.293-0.293-0.767-0.293-1.06 0-0.293 0.293-0.293 0.767 0 1.06L6.438 7.5H4.25C3.007 7.499 2 8.506 2 9.749v4.497c0 1.243 1.007 2.25 2.25 2.25h3.68c0.183 0 0.36 0.068 0.498 0.19l4.491 3.994C13.725 21.396 15 20.824 15 19.746V16.06l5.72 5.72c0.292 0.292 0.767 0.292 1.06 0 0.293-0.293 0.293-0.768 0-1.061L3.28 2.22zM13.5 14.56v4.629l-4.075-3.624c-0.412-0.366-0.944-0.569-1.495-0.569H4.25c-0.414 0-0.75-0.335-0.75-0.75V9.75C3.5 9.335 3.836 9 4.25 9h3.688l5.562 5.56zm0-9.753v5.511l1.5 1.5V4.25c0-1.079-1.274-1.65-2.08-0.934l-3.4 3.022 1.063 1.063L13.5 4.807zm3.641 9.152l1.138 1.138C18.741 14.163 19 13.111 19 12c0-1.203-0.304-2.338-0.84-3.328-0.198-0.364-0.653-0.5-1.017-0.303-0.364 0.197-0.5 0.653-0.303 1.017 0.42 0.777 0.66 1.666 0.66 2.614 0 0.691-0.127 1.351-0.359 1.96zm2.247 2.247l1.093 1.094C21.445 15.763 22 13.946 22 12c0-2.226-0.728-4.284-1.96-5.946-0.246-0.333-0.716-0.403-1.048-0.157-0.333 0.247-0.403 0.716-0.157 1.05C19.881 8.358 20.5 10.106 20.5 12c0 1.531-0.404 2.966-1.112 4.206z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="28dp" android:height="28dp" android:viewportWidth="28" android:viewportHeight="28">
|
|
||||||
<path android:pathData="M3.28 2.22c-0.293-0.293-0.767-0.293-1.06 0-0.293 0.293-0.293 0.767 0 1.06l5.724 5.725H5.25C3.455 9.005 2 10.46 2 12.255v3.492c0 1.795 1.455 3.25 3.25 3.25h3.012c0.444 0 0.872 0.17 1.196 0.473l4.937 4.626c0.799 0.748 2.105 0.182 2.105-0.912v-5.623l8.22 8.22c0.292 0.292 0.767 0.292 1.06 0 0.293-0.293 0.293-0.768 0-1.061L3.28 2.22zM15 16.06v6.547l-4.516-4.231c-0.602-0.565-1.397-0.879-2.222-0.879H5.25c-0.966 0-1.75-0.783-1.75-1.75v-3.492c0-0.966 0.784-1.75 1.75-1.75h3.011c0.35 0 0.693-0.056 1.02-0.164L15 16.061zm-4.378-8.62l1.061 1.061L15 5.392v6.427l1.5 1.5V4.814c0-1.094-1.307-1.66-2.105-0.912L10.622 7.44zm9.55 9.55l1.137 1.137C21.912 16.88 22.25 15.478 22.25 14c0-2.136-0.706-4.11-1.897-5.697-0.249-0.332-0.719-0.399-1.05-0.15-0.332 0.249-0.399 0.719-0.15 1.05C20.156 10.54 20.75 12.199 20.75 14c0 1.058-0.205 2.067-0.578 2.99zm2.803 2.803l1.095 1.096c1.224-2.008 1.93-4.366 1.93-6.89 0-3.35-1.245-6.414-3.298-8.747-0.274-0.31-0.747-0.341-1.058-0.068-0.311 0.274-0.342 0.748-0.068 1.059C23.396 8.313 24.5 11.027 24.5 14c0 2.107-0.554 4.084-1.525 5.793z" android:fillColor="@color/fluent_default_icon_tint"/>
|
|
||||||
</vector>
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<application
|
<application
|
||||||
android:name=".MastodonApp"
|
android:name=".MastodonApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:label="@string/mo_app_name"
|
android:label="@string/sk_app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:localeConfig="@xml/locales_config"
|
android:localeConfig="@xml/locales_config"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<action android:name="android.intent.action.VIEW"/>
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
<category android:name="android.intent.category.BROWSABLE"/>
|
<category android:name="android.intent.category.BROWSABLE"/>
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
<data android:scheme="moshidon-android-auth" android:host="callback"/>
|
<data android:scheme="megalodon-android-auth" android:host="callback"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">
|
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 358 KiB |
@@ -4,7 +4,6 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
@@ -30,14 +29,12 @@ public class GlobalUserPreferences{
|
|||||||
public static boolean alwaysExpandContentWarnings;
|
public static boolean alwaysExpandContentWarnings;
|
||||||
public static boolean disableMarquee;
|
public static boolean disableMarquee;
|
||||||
public static boolean disableSwipe;
|
public static boolean disableSwipe;
|
||||||
public static boolean disableDividers;
|
|
||||||
public static boolean voteButtonForSingleChoice;
|
public static boolean voteButtonForSingleChoice;
|
||||||
public static boolean uniformNotificationIcon;
|
|
||||||
public static boolean enableDeleteNotifications;
|
public static boolean enableDeleteNotifications;
|
||||||
public static boolean relocatePublishButton;
|
public static boolean translateButtonOpenedOnly;
|
||||||
|
public static boolean uniformNotificationIcon;
|
||||||
public static boolean reduceMotion;
|
public static boolean reduceMotion;
|
||||||
public static boolean keepOnlyLatestNotification;
|
public static boolean keepOnlyLatestNotification;
|
||||||
public static boolean enableFabAutoHide;
|
|
||||||
public static boolean disableAltTextReminder;
|
public static boolean disableAltTextReminder;
|
||||||
public static boolean showAltIndicator;
|
public static boolean showAltIndicator;
|
||||||
public static boolean showNoAltIndicator;
|
public static boolean showNoAltIndicator;
|
||||||
@@ -58,10 +55,7 @@ public class GlobalUserPreferences{
|
|||||||
public static Set<String> accountsWithLocalOnlySupport;
|
public static Set<String> accountsWithLocalOnlySupport;
|
||||||
public static Set<String> accountsInGlitchMode;
|
public static Set<String> accountsInGlitchMode;
|
||||||
|
|
||||||
private final static Type recentEmojisType = new TypeToken<Map<String, Integer>>() {}.getType();
|
private static SharedPreferences getPrefs(){
|
||||||
public static Map<String, Integer> recentEmojis;
|
|
||||||
|
|
||||||
private static SharedPreferences getPrefs(){
|
|
||||||
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
|
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,18 +74,16 @@ public class GlobalUserPreferences{
|
|||||||
showBoosts=prefs.getBoolean("showBoosts", true);
|
showBoosts=prefs.getBoolean("showBoosts", true);
|
||||||
loadNewPosts=prefs.getBoolean("loadNewPosts", true);
|
loadNewPosts=prefs.getBoolean("loadNewPosts", true);
|
||||||
showNewPostsButton=prefs.getBoolean("showNewPostsButton", true);
|
showNewPostsButton=prefs.getBoolean("showNewPostsButton", true);
|
||||||
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", true);
|
|
||||||
showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
|
showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
|
||||||
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
|
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
|
||||||
disableMarquee=prefs.getBoolean("disableMarquee", false);
|
disableMarquee=prefs.getBoolean("disableMarquee", false);
|
||||||
disableSwipe=prefs.getBoolean("disableSwipe", false);
|
disableSwipe=prefs.getBoolean("disableSwipe", false);
|
||||||
disableDividers=prefs.getBoolean("disableDividers", true);
|
|
||||||
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
|
|
||||||
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
|
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
|
||||||
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", false);
|
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", false);
|
||||||
|
translateButtonOpenedOnly=prefs.getBoolean("translateButtonOpenedOnly", false);
|
||||||
|
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
|
||||||
reduceMotion=prefs.getBoolean("reduceMotion", false);
|
reduceMotion=prefs.getBoolean("reduceMotion", false);
|
||||||
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
||||||
enableFabAutoHide=prefs.getBoolean("enableFabAutoHide", true);
|
|
||||||
disableAltTextReminder=prefs.getBoolean("disableAltTextReminder", false);
|
disableAltTextReminder=prefs.getBoolean("disableAltTextReminder", false);
|
||||||
showAltIndicator=prefs.getBoolean("showAltIndicator", true);
|
showAltIndicator=prefs.getBoolean("showAltIndicator", true);
|
||||||
showNoAltIndicator=prefs.getBoolean("showNoAltIndicator", true);
|
showNoAltIndicator=prefs.getBoolean("showNoAltIndicator", true);
|
||||||
@@ -103,22 +95,16 @@ public class GlobalUserPreferences{
|
|||||||
autoHideFab=prefs.getBoolean("autoHideFab", true);
|
autoHideFab=prefs.getBoolean("autoHideFab", true);
|
||||||
publishButtonText=prefs.getString("publishButtonText", "");
|
publishButtonText=prefs.getString("publishButtonText", "");
|
||||||
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
|
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
|
||||||
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
|
recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new HashMap<>());
|
||||||
recentEmojis=fromJson(prefs.getString("recentEmojis", "{}"), recentEmojisType, new HashMap<>());
|
|
||||||
publishButtonText=prefs.getString("publishButtonText", "");
|
|
||||||
pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
|
pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
|
||||||
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
|
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
|
||||||
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
|
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
|
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PINK.name()));
|
||||||
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.MATERIAL3.name()));
|
|
||||||
}else{
|
|
||||||
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PURPLE.name()));
|
|
||||||
}
|
|
||||||
} catch (IllegalArgumentException|ClassCastException ignored) {
|
} catch (IllegalArgumentException|ClassCastException ignored) {
|
||||||
// invalid color name or color was previously saved as integer
|
// invalid color name or color was previously saved as integer
|
||||||
color=ColorPreference.PURPLE;
|
color=ColorPreference.PINK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,13 +121,11 @@ public class GlobalUserPreferences{
|
|||||||
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
|
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
|
||||||
.putBoolean("disableMarquee", disableMarquee)
|
.putBoolean("disableMarquee", disableMarquee)
|
||||||
.putBoolean("disableSwipe", disableSwipe)
|
.putBoolean("disableSwipe", disableSwipe)
|
||||||
.putBoolean("disableDividers", disableDividers)
|
|
||||||
.putBoolean("relocatePublishButton", relocatePublishButton)
|
|
||||||
.putBoolean("uniformNotificationIcon", uniformNotificationIcon)
|
|
||||||
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
|
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
|
||||||
|
.putBoolean("translateButtonOpenedOnly", translateButtonOpenedOnly)
|
||||||
|
.putBoolean("uniformNotificationIcon", uniformNotificationIcon)
|
||||||
.putBoolean("reduceMotion", reduceMotion)
|
.putBoolean("reduceMotion", reduceMotion)
|
||||||
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
|
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
|
||||||
.putBoolean("enableFabAutoHide", enableFabAutoHide)
|
|
||||||
.putBoolean("disableAltTextReminder", disableAltTextReminder)
|
.putBoolean("disableAltTextReminder", disableAltTextReminder)
|
||||||
.putBoolean("showAltIndicator", showAltIndicator)
|
.putBoolean("showAltIndicator", showAltIndicator)
|
||||||
.putBoolean("showNoAltIndicator", showNoAltIndicator)
|
.putBoolean("showNoAltIndicator", showNoAltIndicator)
|
||||||
@@ -156,7 +140,6 @@ public class GlobalUserPreferences{
|
|||||||
.putString("color", color.name())
|
.putString("color", color.name())
|
||||||
.putString("recentLanguages", gson.toJson(recentLanguages))
|
.putString("recentLanguages", gson.toJson(recentLanguages))
|
||||||
.putString("pinnedTimelines", gson.toJson(pinnedTimelines))
|
.putString("pinnedTimelines", gson.toJson(pinnedTimelines))
|
||||||
.putString("recentEmojis", gson.toJson(recentEmojis))
|
|
||||||
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
|
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
|
||||||
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
|
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
|
||||||
.apply();
|
.apply();
|
||||||
@@ -170,8 +153,7 @@ public class GlobalUserPreferences{
|
|||||||
BLUE,
|
BLUE,
|
||||||
BROWN,
|
BROWN,
|
||||||
RED,
|
RED,
|
||||||
YELLOW,
|
YELLOW
|
||||||
NORD
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ThemePreference{
|
public enum ThemePreference{
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import org.joinmastodon.android.fragments.ProfileFragment;
|
|||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
|
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
private static final String TAG="PushNotificationReceive";
|
private static final String TAG="PushNotificationReceive";
|
||||||
|
|
||||||
public static final int NOTIFICATION_ID=178;
|
public static final int NOTIFICATION_ID=178;
|
||||||
private static final int SUMMARY_ID = 791;
|
|
||||||
private static int notificationId = 0;
|
private static int notificationId = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -143,7 +142,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
.setShowWhen(true)
|
.setShowWhen(true)
|
||||||
.setCategory(Notification.CATEGORY_SOCIAL)
|
.setCategory(Notification.CATEGORY_SOCIAL)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setColor(context.getColor(R.color.shortcut_icon_background));
|
.setColor(context.getColor(R.color.primary_700));
|
||||||
|
|
||||||
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
||||||
builder.setSmallIcon(switch (pn.notificationType) {
|
builder.setSmallIcon(switch (pn.notificationType) {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package org.joinmastodon.android.api.requests.accounts;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import org.joinmastodon.android.model.Account;
|
|
||||||
|
|
||||||
public class GetAccountByHandle extends MastodonAPIRequest<Account>{
|
|
||||||
public GetAccountByHandle(String acct){
|
|
||||||
super(HttpMethod.GET, "/accounts/lookup", Account.class);
|
|
||||||
addQueryParameter("acct", acct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package org.joinmastodon.android.api.requests.accounts;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import org.joinmastodon.android.model.Relationship;
|
|
||||||
|
|
||||||
public class SetPrivateNote extends MastodonAPIRequest<Relationship>{
|
|
||||||
public SetPrivateNote(String id, String comment){
|
|
||||||
super(MastodonAPIRequest.HttpMethod.POST, "/accounts/"+id+"/note", Relationship.class);
|
|
||||||
Request req = new Request(comment);
|
|
||||||
setRequestBody(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Request{
|
|
||||||
public String comment;
|
|
||||||
public Request(String comment){
|
|
||||||
this.comment=comment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package org.joinmastodon.android.api.requests.lists;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AddList extends MastodonAPIRequest<Object> {
|
|
||||||
public AddList(String listName){
|
|
||||||
super(HttpMethod.POST, "/lists", Object.class);
|
|
||||||
Request req = new Request();
|
|
||||||
req.title = listName;
|
|
||||||
setRequestBody(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Request{
|
|
||||||
public String title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package org.joinmastodon.android.api.requests.lists;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EditListName extends MastodonAPIRequest<Object> {
|
|
||||||
public EditListName(String newListName, String listId){
|
|
||||||
super(HttpMethod.PUT, "/lists/"+listId, Object.class);
|
|
||||||
Request req = new Request();
|
|
||||||
req.title = newListName;
|
|
||||||
setRequestBody(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Request{
|
|
||||||
public String title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package org.joinmastodon.android.api.requests.lists;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class RemoveList extends MastodonAPIRequest<Object> {
|
|
||||||
public RemoveList(String listId){
|
|
||||||
super(HttpMethod.DELETE, "/lists/"+listId, Object.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,8 +10,8 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DismissNotification extends MastodonAPIRequest<Object>{
|
public class DismissNotification extends MastodonAPIRequest<Object>{
|
||||||
public DismissNotification(String id){
|
public DismissNotification(String id){
|
||||||
super(HttpMethod.POST, "/notifications/" + (id != null ? id + "/dismiss" : "clear"), Object.class);
|
super(HttpMethod.POST, "/notifications/" + (id != null ? id + "/dismiss" : "clear"), Object.class);
|
||||||
setRequestBody(new Object());
|
setRequestBody(new Object());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ public class CreateOAuthApp extends MastodonAPIRequest<Application>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class Request{
|
private static class Request{
|
||||||
public String clientName="Moshidon";
|
public String clientName="Megalodon";
|
||||||
public String redirectUris=AccountSessionManager.REDIRECT_URI;
|
public String redirectUris=AccountSessionManager.REDIRECT_URI;
|
||||||
public String scopes=AccountSessionManager.SCOPE;
|
public String scopes=AccountSessionManager.SCOPE;
|
||||||
public String website="https://github.com/LucasGGamerM/moshidon";
|
public String website="https://sk22.github.io/megalodon";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import me.grishka.appkit.api.ErrorResponse;
|
|||||||
public class AccountSessionManager{
|
public class AccountSessionManager{
|
||||||
private static final String TAG="AccountSessionManager";
|
private static final String TAG="AccountSessionManager";
|
||||||
public static final String SCOPE="read write follow push";
|
public static final String SCOPE="read write follow push";
|
||||||
public static final String REDIRECT_URI="moshidon-android-auth://callback";
|
public static final String REDIRECT_URI="megalodon-android-auth://callback";
|
||||||
|
|
||||||
private static final AccountSessionManager instance=new AccountSessionManager();
|
private static final AccountSessionManager instance=new AccountSessionManager();
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ public class AccountSessionManager{
|
|||||||
.path("/oauth/authorize")
|
.path("/oauth/authorize")
|
||||||
.appendQueryParameter("response_type", "code")
|
.appendQueryParameter("response_type", "code")
|
||||||
.appendQueryParameter("client_id", result.clientId)
|
.appendQueryParameter("client_id", result.clientId)
|
||||||
.appendQueryParameter("redirect_uri", "moshidon-android-auth://callback")
|
.appendQueryParameter("redirect_uri", "megalodon-android-auth://callback")
|
||||||
.appendQueryParameter("scope", SCOPE)
|
.appendQueryParameter("scope", SCOPE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ public class AccountTimelineFragment extends StatusListFragment{
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
fab = ((ProfileFragment) getParentFragment()).getFab();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -32,12 +32,10 @@ import org.joinmastodon.android.model.Poll;
|
|||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.BetterItemAnimator;
|
import org.joinmastodon.android.ui.BetterItemAnimator;
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.TileGridLayoutManager;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
@@ -45,8 +43,10 @@ import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
|||||||
import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||||
|
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout;
|
import org.joinmastodon.android.ui.views.MediaGridLayout;
|
||||||
|
import org.joinmastodon.android.utils.TypedObjectPool;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -57,7 +57,6 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
@@ -81,8 +80,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
||||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||||
protected Rect tmpRect=new Rect();
|
protected Rect tmpRect=new Rect();
|
||||||
|
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
|
||||||
private final int THRESHOLD = 800;
|
|
||||||
|
|
||||||
public BaseStatusListFragment(){
|
public BaseStatusListFragment(){
|
||||||
super(20);
|
super(20);
|
||||||
@@ -192,21 +190,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex){
|
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex, MediaGridStatusDisplayItem.Holder gridHolder){
|
||||||
final Status status=_status.reblog!=null ? _status.reblog : _status;
|
final Status status=_status.getContentStatus();
|
||||||
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
||||||
private ImageStatusDisplayItem.Holder<?> transitioningHolder;
|
private MediaAttachmentViewController transitioningHolder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPhotoViewVisibility(int index, boolean visible){
|
public void setPhotoViewVisibility(int index, boolean visible){
|
||||||
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
||||||
if(holder!=null)
|
if(holder!=null)
|
||||||
holder.photo.setAlpha(visible ? 1f : 0f);
|
holder.photo.setAlpha(visible ? 1f : 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
||||||
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
||||||
if(holder!=null){
|
if(holder!=null){
|
||||||
transitioningHolder=holder;
|
transitioningHolder=holder;
|
||||||
View view=transitioningHolder.photo;
|
View view=transitioningHolder.photo;
|
||||||
@@ -214,7 +212,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
view.getLocationOnScreen(pos);
|
view.getLocationOnScreen(pos);
|
||||||
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
||||||
list.setClipChildren(false);
|
list.setClipChildren(false);
|
||||||
transitioningHolder.itemView.setElevation(1f);
|
gridHolder.setClipChildren(false);
|
||||||
|
transitioningHolder.view.setElevation(1f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -241,15 +240,16 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
view.setTranslationY(0f);
|
view.setTranslationY(0f);
|
||||||
view.setScaleX(1f);
|
view.setScaleX(1f);
|
||||||
view.setScaleY(1f);
|
view.setScaleY(1f);
|
||||||
transitioningHolder.itemView.setElevation(0f);
|
transitioningHolder.view.setElevation(0f);
|
||||||
if(list!=null)
|
if(list!=null)
|
||||||
list.setClipChildren(true);
|
list.setClipChildren(true);
|
||||||
|
gridHolder.setClipChildren(true);
|
||||||
transitioningHolder=null;
|
transitioningHolder=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Drawable getPhotoViewCurrentDrawable(int index){
|
public Drawable getPhotoViewCurrentDrawable(int index){
|
||||||
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
||||||
if(holder!=null)
|
if(holder!=null)
|
||||||
return holder.photo.getDrawable();
|
return holder.photo.getDrawable();
|
||||||
return null;
|
return null;
|
||||||
@@ -265,23 +265,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
requestPermissions(permissions, PhotoViewer.PERMISSION_REQUEST);
|
requestPermissions(permissions, PhotoViewer.PERMISSION_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageStatusDisplayItem.Holder<?> findPhotoViewHolder(int index){
|
private MediaAttachmentViewController findPhotoViewHolder(int index){
|
||||||
if(list==null)
|
return gridHolder.getViewController(index);
|
||||||
return null;
|
|
||||||
int offset=0;
|
|
||||||
for(StatusDisplayItem item:displayItems){
|
|
||||||
if(item.parentID.equals(parentID)){
|
|
||||||
if(item instanceof ImageStatusDisplayItem){
|
|
||||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(getMainAdapterOffset()+offset+index);
|
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
||||||
return imgHolder;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -290,23 +275,13 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
fab=view.findViewById(R.id.fab);
|
fab=view.findViewById(R.id.fab);
|
||||||
|
|
||||||
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
|
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
|
||||||
@Override
|
@Override
|
||||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
|
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
|
||||||
if(currentPhotoViewer!=null)
|
if(currentPhotoViewer!=null)
|
||||||
currentPhotoViewer.offsetView(-dx, -dy);
|
currentPhotoViewer.offsetView(-dx, -dy);
|
||||||
|
|
||||||
if (fab!=null && GlobalUserPreferences.enableFabAutoHide) {
|
if (fab!=null && GlobalUserPreferences.autoHideFab) {
|
||||||
// This piece of code should make it so that the fab is always visible if the status list scroll view is at the item at the top
|
|
||||||
if(list.getChildAt(0).getTop() == 0){
|
|
||||||
scrollDiff= THRESHOLD +1;
|
|
||||||
}else{
|
|
||||||
if(dy > 0){
|
|
||||||
scrollDiff=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
0,
|
0,
|
||||||
@@ -314,30 +289,29 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
0,
|
0,
|
||||||
fab.getHeight() * 2);
|
fab.getHeight() * 2);
|
||||||
animate.setDuration(300);
|
animate.setDuration(300);
|
||||||
// animate.setFillAfter(true);
|
animate.setFillAfter(true);
|
||||||
fab.startAnimation(animate);
|
fab.startAnimation(animate);
|
||||||
fab.setEnabled(false);
|
|
||||||
fab.setVisibility(View.INVISIBLE);
|
fab.setVisibility(View.INVISIBLE);
|
||||||
scrollDiff = 0;
|
scrollDiff = 0;
|
||||||
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
||||||
if (scrollDiff > THRESHOLD) {
|
if (list.getChildLayoutPosition(list.getChildAt(0)) == 0 || scrollDiff > 400) {
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
fab.getHeight() * 2,
|
fab.getHeight() * 2,
|
||||||
0);
|
0);
|
||||||
animate.setDuration(300);
|
animate.setDuration(300);
|
||||||
// animate.setFillAfter(true);
|
animate.setFillAfter(true);
|
||||||
fab.startAnimation(animate);
|
fab.startAnimation(animate);
|
||||||
fab.setEnabled(true);
|
|
||||||
fab.setVisibility(View.VISIBLE);
|
|
||||||
scrollDiff = 0;
|
scrollDiff = 0;
|
||||||
} else {
|
} else {
|
||||||
scrollDiff += Math.abs(dy);
|
scrollDiff += Math.abs(dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
list.addItemDecoration(new StatusListItemDecoration());
|
list.addItemDecoration(new StatusListItemDecoration());
|
||||||
((UsableRecyclerView)list).setSelectorBoundsProvider(new UsableRecyclerView.SelectorBoundsProvider(){
|
((UsableRecyclerView)list).setSelectorBoundsProvider(new UsableRecyclerView.SelectorBoundsProvider(){
|
||||||
private Rect tmpRect=new Rect();
|
private Rect tmpRect=new Rect();
|
||||||
@@ -373,38 +347,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
updateToolbar();
|
updateToolbar();
|
||||||
|
|
||||||
if (withComposeButton()) {
|
if (withComposeButton()) {
|
||||||
fab = view.findViewById(R.id.fab);
|
|
||||||
fab.setVisibility(View.VISIBLE);
|
fab.setVisibility(View.VISIBLE);
|
||||||
fab.setOnClickListener(this::onFabClick);
|
fab.setOnClickListener(this::onFabClick);
|
||||||
fab.setOnLongClickListener(this::onFabLongClick);
|
fab.setOnLongClickListener(this::onFabLongClick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RecyclerView.LayoutManager onCreateLayoutManager(){
|
|
||||||
GridLayoutManager lm=new TileGridLayoutManager(getActivity(), 1000);
|
|
||||||
lm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){
|
|
||||||
@Override
|
|
||||||
public int getSpanSize(int position){
|
|
||||||
position-=getMainAdapterOffset();
|
|
||||||
if(position>=0 && position<displayItems.size()){
|
|
||||||
StatusDisplayItem item=displayItems.get(position);
|
|
||||||
if(item instanceof ImageStatusDisplayItem imgItem){
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=imgItem.tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgItem.thisTile;
|
|
||||||
int spans=0;
|
|
||||||
for(int i=0;i<tile.colSpan;i++){
|
|
||||||
spans+=layout.columnSizes[tile.startCol+i];
|
|
||||||
}
|
|
||||||
return spans;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return lm;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig){
|
public void onConfigurationChanged(Configuration newConfig){
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
@@ -523,7 +471,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
revealSpoiler(status, holder.getItemID());
|
revealSpoiler(status, holder.getItemID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRevealSpoilerClick(ImageStatusDisplayItem.Holder<?> holder){
|
public void onRevealSpoilerClick(MediaGridStatusDisplayItem.Holder holder){
|
||||||
Status status=holder.getItem().status;
|
Status status=holder.getItem().status;
|
||||||
revealSpoiler(status, holder.getItemID());
|
revealSpoiler(status, holder.getItemID());
|
||||||
}
|
}
|
||||||
@@ -571,13 +519,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
|
|
||||||
protected void updateImagesSpoilerState(Status status, String itemID){
|
protected void updateImagesSpoilerState(Status status, String itemID){
|
||||||
ArrayList<Integer> updatedPositions=new ArrayList<>();
|
ArrayList<Integer> updatedPositions=new ArrayList<>();
|
||||||
for(ImageStatusDisplayItem.Holder photo:(List<ImageStatusDisplayItem.Holder>)findAllHoldersOfType(itemID, ImageStatusDisplayItem.Holder.class)){
|
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(itemID, MediaGridStatusDisplayItem.Holder.class);
|
||||||
photo.setRevealed(status.spoilerRevealed);
|
if(mediaGrid!=null){
|
||||||
updatedPositions.add(photo.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
mediaGrid.setRevealed(status.spoilerRevealed);
|
||||||
|
updatedPositions.add(mediaGrid.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
||||||
}
|
}
|
||||||
int i=0;
|
int i=0;
|
||||||
for(StatusDisplayItem item:displayItems){
|
for(StatusDisplayItem item:displayItems){
|
||||||
if(itemID.equals(item.parentID) && item instanceof ImageStatusDisplayItem && !updatedPositions.contains(i)){
|
if(itemID.equals(item.parentID) && item instanceof MediaGridStatusDisplayItem && !updatedPositions.contains(i)){
|
||||||
adapter.notifyItemChanged(i);
|
adapter.notifyItemChanged(i);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@@ -720,6 +669,15 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
return UiUtils.pickAccountForCompose(getActivity(), accountID);
|
return UiUtils.pickAccountForCompose(getActivity(), accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MediaAttachmentViewController makeNewMediaAttachmentView(MediaGridStatusDisplayItem.GridItemType type){
|
||||||
|
return new MediaAttachmentViewController(getActivity(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> getAttachmentViewsPool(){
|
||||||
|
return attachmentViewsPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
||||||
|
|
||||||
public DisplayItemsAdapter(){
|
public DisplayItemsAdapter(){
|
||||||
@@ -757,16 +715,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
public ImageLoaderRequest getImageRequest(int position, int image){
|
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||||
return displayItems.get(position).getImageRequest(image);
|
return displayItems.get(position).getImageRequest(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onViewDetachedFromWindow(@NonNull BindableViewHolder<StatusDisplayItem> holder){
|
|
||||||
// if(holder instanceof ImageLoaderViewHolder){
|
|
||||||
// int count=holder.getItem().getImageCount();
|
|
||||||
// for(int i=0;i<count;i++){
|
|
||||||
// ((ImageLoaderViewHolder) holder).clearImage(i);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StatusListItemDecoration extends RecyclerView.ItemDecoration{
|
private class StatusListItemDecoration extends RecyclerView.ItemDecoration{
|
||||||
@@ -776,7 +724,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
private int currentMediaHiddenLayoutsWidth=0;
|
private int currentMediaHiddenLayoutsWidth=0;
|
||||||
|
|
||||||
{
|
{
|
||||||
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), GlobalUserPreferences.disableDividers ? R.attr.colorWindowBackground : R.attr.colorPollVoted));
|
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), R.attr.colorPollVoted));
|
||||||
dividerPaint.setStyle(Paint.Style.STROKE);
|
dividerPaint.setStyle(Paint.Style.STROKE);
|
||||||
dividerPaint.setStrokeWidth(V.dp(1));
|
dividerPaint.setStrokeWidth(V.dp(1));
|
||||||
}
|
}
|
||||||
@@ -800,25 +748,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
for(int i=0;i<parent.getChildCount();i++){
|
for(int i=0;i<parent.getChildCount();i++){
|
||||||
View child=parent.getChildAt(i);
|
View child=parent.getChildAt(i);
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
if(holder instanceof MediaGridStatusDisplayItem.Holder imgHolder){
|
||||||
if(!imgHolder.getItem().status.spoilerRevealed && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
if(!imgHolder.getItem().status.spoilerRevealed && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
||||||
hiddenMediaPaint.setColor(0x80000000);
|
hiddenMediaPaint.setColor(0x80000000);
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
c.drawRect(child.getX(), child.getY(), child.getX()+child.getWidth(), child.getY()+child.getHeight(), hiddenMediaPaint);
|
||||||
float hGap=tile.startCol>0 ? V.dp(1) : 0;
|
|
||||||
float vGap=tile.startRow>0 ? V.dp(1) : 0;
|
|
||||||
c.drawRect(child.getX()-hGap, child.getY()-vGap, child.getX()+child.getWidth(), child.getY()+child.getHeight(), hiddenMediaPaint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(int i=0;i<parent.getChildCount();i++){
|
for(int i=0;i<parent.getChildCount();i++){
|
||||||
View child=parent.getChildAt(i);
|
View child=parent.getChildAt(i);
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
if(holder instanceof MediaGridStatusDisplayItem.Holder imgHolder){
|
||||||
if(!imgHolder.getItem().status.spoilerRevealed){
|
if(!imgHolder.getItem().status.spoilerRevealed){
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
if(TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
||||||
if(tile.startCol==0 && tile.startRow==0 && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
|
||||||
int listWidth=getListWidthForMediaLayout();
|
int listWidth=getListWidthForMediaLayout();
|
||||||
int width=Math.min(listWidth, V.dp(ImageAttachmentFrameLayout.MAX_WIDTH));
|
int width=Math.min(listWidth, V.dp(MediaGridLayout.MAX_WIDTH));
|
||||||
if(currentMediaHiddenLayoutsWidth!=width)
|
if(currentMediaHiddenLayoutsWidth!=width)
|
||||||
rebuildMediaHiddenLayouts(width-V.dp(32));
|
rebuildMediaHiddenLayouts(width-V.dp(32));
|
||||||
c.save();
|
c.save();
|
||||||
@@ -843,47 +787,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
|
||||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
|
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder){
|
|
||||||
int listWidth=getListWidthForMediaLayout();
|
|
||||||
int width=Math.min(listWidth, V.dp(ImageAttachmentFrameLayout.MAX_WIDTH));
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=((ImageStatusDisplayItem.Holder<?>) holder).getItem().tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=((ImageStatusDisplayItem.Holder<?>) holder).getItem().thisTile;
|
|
||||||
if(tile.startCol+tile.colSpan<layout.columnSizes.length){
|
|
||||||
outRect.right=V.dp(1);
|
|
||||||
}
|
|
||||||
if(tile.startRow+tile.rowSpan<layout.rowSizes.length){
|
|
||||||
outRect.bottom=V.dp(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For a view that spans rows, compensate its additional height so the row it's in stays the right height
|
|
||||||
if(tile.rowSpan>1){
|
|
||||||
outRect.bottom=-(Math.round(tile.height/1000f*width)-Math.round(layout.rowSizes[tile.startRow]/1000f*width));
|
|
||||||
}
|
|
||||||
// ...and for its siblings, offset those on rows below first to the right where they belong
|
|
||||||
if(tile.startCol>0 && layout.tiles[0].rowSpan>1 && tile.startRow>layout.tiles[0].startRow){
|
|
||||||
int xOffset=Math.round(layout.tiles[0].width/1000f*listWidth);
|
|
||||||
outRect.left=xOffset;
|
|
||||||
outRect.right=-xOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the width of the media block is smaller than that of the RecyclerView, offset the views horizontally to center them
|
|
||||||
if(listWidth>width){
|
|
||||||
outRect.left+=(listWidth-V.dp(ImageAttachmentFrameLayout.MAX_WIDTH))/2;
|
|
||||||
if(tile.startCol>0){
|
|
||||||
int spanOffset=0;
|
|
||||||
for(int i=0;i<tile.startCol;i++){
|
|
||||||
spanOffset+=layout.columnSizes[i];
|
|
||||||
}
|
|
||||||
outRect.left-=Math.round(spanOffset/1000f*listWidth);
|
|
||||||
outRect.left+=Math.round(spanOffset/1000f*width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rebuildMediaHiddenLayouts(int width){
|
private void rebuildMediaHiddenLayouts(int width){
|
||||||
currentMediaHiddenLayoutsWidth=width;
|
currentMediaHiddenLayoutsWidth=width;
|
||||||
String title=getString(R.string.sensitive_content);
|
String title=getString(R.string.sensitive_content);
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import static android.os.ext.SdkExtensions.getExtensionVersion;
|
|
||||||
|
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
|
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
|
||||||
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.DRAFTS_AFTER_INSTANT;
|
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.DRAFTS_AFTER_INSTANT;
|
||||||
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.getDraftInstant;
|
import static org.joinmastodon.android.api.requests.statuses.CreateStatus.getDraftInstant;
|
||||||
@@ -111,7 +109,7 @@ import org.joinmastodon.android.ui.text.ComposeAutocompleteSpan;
|
|||||||
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
|
import org.joinmastodon.android.ui.text.ComposeHashtagOrMentionSpan;
|
||||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||||
import org.joinmastodon.android.ui.utils.TransferSpeedTracker;
|
import org.joinmastodon.android.utils.TransferSpeedTracker;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
import org.joinmastodon.android.ui.views.ComposeEditText;
|
import org.joinmastodon.android.ui.views.ComposeEditText;
|
||||||
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
|
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
|
||||||
@@ -237,14 +235,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
private String language, encoding;
|
private String language, encoding;
|
||||||
private MastodonLanguage.LanguageResolver languageResolver;
|
private MastodonLanguage.LanguageResolver languageResolver;
|
||||||
|
|
||||||
private int navigationBarColorBefore;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
navigationBarColorBefore = getActivity().getWindow().getNavigationBarColor();
|
|
||||||
getActivity().getWindow().setNavigationBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLightest));
|
|
||||||
|
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
@@ -289,7 +283,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
UiUtils.removeCallbacks(updateUploadEtaRunnable);
|
UiUtils.removeCallbacks(updateUploadEtaRunnable);
|
||||||
updateUploadEtaRunnable=null;
|
updateUploadEtaRunnable=null;
|
||||||
}
|
}
|
||||||
getActivity().getWindow().setNavigationBarColor(navigationBarColorBefore);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -307,25 +300,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
emojiKeyboard.setListener(this::onCustomEmojiClick);
|
emojiKeyboard.setListener(this::onCustomEmojiClick);
|
||||||
|
|
||||||
View view=inflater.inflate(R.layout.fragment_compose, container, false);
|
View view=inflater.inflate(R.layout.fragment_compose, container, false);
|
||||||
|
|
||||||
if(GlobalUserPreferences.relocatePublishButton){
|
|
||||||
publishButton=view.findViewById(R.id.publish);
|
|
||||||
// publishButton.setText(editingStatus==null || redraftStatus ? R.string.publish : R.string.save);
|
|
||||||
publishButton.setEllipsize(TextUtils.TruncateAt.END);
|
|
||||||
publishButton.setOnClickListener(this::onPublishClick);
|
|
||||||
publishButton.setSingleLine(true);
|
|
||||||
publishButton.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
draftsBtn=view.findViewById(R.id.drafts_btn);
|
|
||||||
draftsBtn.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
charCounter=view.findViewById(R.id.char_counter);
|
|
||||||
charCounter.setVisibility(View.VISIBLE);
|
|
||||||
charCounter.setText(String.valueOf(charLimit));
|
|
||||||
}
|
|
||||||
|
|
||||||
mainEditText=view.findViewById(R.id.toot_text);
|
mainEditText=view.findViewById(R.id.toot_text);
|
||||||
mainEditTextWrap=view.findViewById(R.id.toot_text_wrap);
|
mainEditTextWrap=view.findViewById(R.id.toot_text_wrap);
|
||||||
|
charCounter=view.findViewById(R.id.char_counter);
|
||||||
|
charCounter.setText(String.valueOf(charLimit));
|
||||||
scrollView=view.findViewById(R.id.scroll_view);
|
scrollView=view.findViewById(R.id.scroll_view);
|
||||||
|
|
||||||
selfName=view.findViewById(R.id.self_name);
|
selfName=view.findViewById(R.id.self_name);
|
||||||
@@ -714,10 +692,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
replyText.setOnClickListener(v->{
|
replyText.setOnClickListener(v->{
|
||||||
scrollView.smoothScrollTo(0, 0);
|
scrollView.smoothScrollTo(0, 0);
|
||||||
});
|
});
|
||||||
replyText.setOnClickListener(v->{
|
|
||||||
scrollView.smoothScrollTo(0, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
ArrayList<String> mentions=new ArrayList<>();
|
ArrayList<String> mentions=new ArrayList<>();
|
||||||
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
|
||||||
@@ -813,20 +787,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
item.setActionView(wrap);
|
item.setActionView(wrap);
|
||||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||||
|
|
||||||
if(!GlobalUserPreferences.relocatePublishButton){
|
draftsBtn = wrap.findViewById(R.id.drafts_btn);
|
||||||
publishButton = wrap.findViewById(R.id.publish_btn);
|
|
||||||
publishButton.setOnClickListener(this::onPublishClick);
|
|
||||||
publishButton.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
draftsBtn = wrap.findViewById(R.id.drafts_btn);
|
|
||||||
draftsBtn.setVisibility(View.VISIBLE);
|
|
||||||
}else{
|
|
||||||
charCounter = wrap.findViewById(R.id.char_counter);
|
|
||||||
charCounter.setVisibility(View.VISIBLE);
|
|
||||||
charCounter.setText(String.valueOf(charLimit));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draftsBtn = wrap.findViewById(R.id.drafts_btn);
|
|
||||||
draftOptionsPopup = new PopupMenu(getContext(), draftsBtn);
|
draftOptionsPopup = new PopupMenu(getContext(), draftsBtn);
|
||||||
draftOptionsPopup.inflate(R.menu.compose_more);
|
draftOptionsPopup.inflate(R.menu.compose_more);
|
||||||
draftMenuItem = draftOptionsPopup.getMenu().findItem(R.id.draft);
|
draftMenuItem = draftOptionsPopup.getMenu().findItem(R.id.draft);
|
||||||
@@ -843,11 +804,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
});
|
});
|
||||||
UiUtils.enablePopupMenuIcons(getContext(), draftOptionsPopup);
|
UiUtils.enablePopupMenuIcons(getContext(), draftOptionsPopup);
|
||||||
|
|
||||||
|
publishButton = wrap.findViewById(R.id.publish_btn);
|
||||||
languageButton = wrap.findViewById(R.id.language_btn);
|
languageButton = wrap.findViewById(R.id.language_btn);
|
||||||
sendProgress = wrap.findViewById(R.id.send_progress);
|
sendProgress = wrap.findViewById(R.id.send_progress);
|
||||||
sendError = wrap.findViewById(R.id.send_error);
|
sendError = wrap.findViewById(R.id.send_error);
|
||||||
|
|
||||||
|
publishButton.setOnClickListener(this::onPublishClick);
|
||||||
draftsBtn.setOnClickListener(v-> draftOptionsPopup.show());
|
draftsBtn.setOnClickListener(v-> draftOptionsPopup.show());
|
||||||
draftsBtn.setOnTouchListener(draftOptionsPopup.getDragToOpenListener());
|
draftsBtn.setOnTouchListener(draftOptionsPopup.getDragToOpenListener());
|
||||||
updateScheduledAt(scheduledAt != null ? scheduledAt : scheduledStatus != null ? scheduledStatus.scheduledAt : null);
|
updateScheduledAt(scheduledAt != null ? scheduledAt : scheduledStatus != null ? scheduledStatus.scheduledAt : null);
|
||||||
@@ -983,9 +945,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
|
|
||||||
private void resetPublishButtonText() {
|
private void resetPublishButtonText() {
|
||||||
int publishText = editingStatus==null || redraftStatus ? R.string.publish : R.string.save;
|
int publishText = editingStatus==null || redraftStatus ? R.string.publish : R.string.save;
|
||||||
if(GlobalUserPreferences.relocatePublishButton){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (publishText == R.string.publish && !GlobalUserPreferences.publishButtonText.isEmpty()) {
|
if (publishText == R.string.publish && !GlobalUserPreferences.publishButtonText.isEmpty()) {
|
||||||
publishButton.setText(GlobalUserPreferences.publishButtonText);
|
publishButton.setText(GlobalUserPreferences.publishButtonText);
|
||||||
} else {
|
} else {
|
||||||
@@ -1008,13 +967,15 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
nonDoneAttachmentCount++;
|
nonDoneAttachmentCount++;
|
||||||
}
|
}
|
||||||
publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && nonDoneAttachmentCount==0 && (pollOptions.isEmpty() || nonEmptyPollOptionsCount>1));
|
publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && nonDoneAttachmentCount==0 && (pollOptions.isEmpty() || nonEmptyPollOptionsCount>1));
|
||||||
// sendError.setVisibility(View.GONE);
|
sendError.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCustomEmojiClick(Emoji emoji){
|
private void onCustomEmojiClick(Emoji emoji){
|
||||||
int start=mainEditText.getSelectionStart();
|
if(getActivity().getCurrentFocus() instanceof EditText edit){
|
||||||
String prefix=start>0 && !Character.isWhitespace(mainEditText.getText().charAt(start-1)) ? " :" : ":";
|
int start=edit.getSelectionStart();
|
||||||
mainEditText.getText().replace(start, mainEditText.getSelectionEnd(), prefix+emoji.shortcode+':');
|
String prefix=start>0 && !Character.isWhitespace(edit.getText().charAt(start-1)) ? " :" : ":";
|
||||||
|
edit.getText().replace(start, edit.getSelectionEnd(), prefix+emoji.shortcode+':');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1024,18 +985,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onPublishClick(View v){
|
private void onPublishClick(View v){
|
||||||
if (!attachments.isEmpty()
|
publish();
|
||||||
&& statusVisibility != StatusPrivacy.DIRECT
|
|
||||||
&& !attachments.stream().allMatch(attachment -> attachment.description != null && !attachment.description.isBlank())) {
|
|
||||||
new M3AlertDialogBuilder(getActivity())
|
|
||||||
.setTitle(R.string.mo_no_image_desc_title)
|
|
||||||
.setMessage(R.string.mo_no_image_desc)
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.publish, (dialog, i)-> publish())
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void publishErrorCallback(ErrorResponse error) {
|
private void publishErrorCallback(ErrorResponse error) {
|
||||||
@@ -1186,7 +1136,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if(editingStatus!=null && !redraftStatus){
|
if(editingStatus!=null && !redraftStatus){
|
||||||
new EditStatus(req, editingStatus.id)
|
new EditStatus(req, editingStatus.id)
|
||||||
.setCallback(resCallback)
|
.setCallback(resCallback)
|
||||||
@@ -1493,7 +1442,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
|
|
||||||
private void uploadMediaAttachment(DraftMediaAttachment attachment){
|
private void uploadMediaAttachment(DraftMediaAttachment attachment){
|
||||||
if(areThereAnyUploadingAttachments()){
|
if(areThereAnyUploadingAttachments()){
|
||||||
throw new IllegalStateException("there is already an attachment being uploaded");
|
throw new IllegalStateException("there is already an attachment being uploaded");
|
||||||
}
|
}
|
||||||
attachment.state=AttachmentUploadState.UPLOADING;
|
attachment.state=AttachmentUploadState.UPLOADING;
|
||||||
attachment.progressBar.setVisibility(View.VISIBLE);
|
attachment.progressBar.setVisibility(View.VISIBLE);
|
||||||
@@ -1691,6 +1640,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
|
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
|
||||||
if(att.serverAttachment==null)
|
if(att.serverAttachment==null)
|
||||||
return;
|
return;
|
||||||
|
editMediaDescription(att);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void editMediaDescription(DraftMediaAttachment att) {
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putString("attachment", att.serverAttachment.id);
|
args.putString("attachment", att.serverAttachment.id);
|
||||||
@@ -1848,15 +1801,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
scheduleDraftText.setText(R.string.sk_compose_draft);
|
scheduleDraftText.setText(R.string.sk_compose_draft);
|
||||||
scheduleDraftText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_drafts_20_regular, 0, 0, 0);
|
scheduleDraftText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_drafts_20_regular, 0, 0, 0);
|
||||||
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_draft));
|
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_draft));
|
||||||
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_drafts_24_regular : R.drawable.ic_fluent_drafts_20_filled, 0, 0, 0);
|
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_drafts_20_filled, 0, 0, 0);
|
||||||
|
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
|
||||||
if(GlobalUserPreferences.relocatePublishButton){
|
? R.string.save : R.string.sk_draft);
|
||||||
publishButton.setCompoundDrawablesWithIntrinsicBounds(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
|
|
||||||
? R.drawable.ic_fluent_save_24_selector : R.drawable.ic_fluent_drafts_24_selector, 0, 0, 0);
|
|
||||||
}else{
|
|
||||||
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
|
|
||||||
? R.string.save : R.string.sk_draft);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
scheduleMenuItem.setVisible(false);
|
scheduleMenuItem.setVisible(false);
|
||||||
unscheduleMenuItem.setVisible(true);
|
unscheduleMenuItem.setVisible(true);
|
||||||
@@ -1866,21 +1813,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
scheduleDraftText.setText(R.string.sk_compose_scheduled);
|
scheduleDraftText.setText(R.string.sk_compose_scheduled);
|
||||||
scheduleDraftText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
scheduleDraftText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||||
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_schedule));
|
scheduleDraftDismiss.setContentDescription(getString(R.string.sk_compose_no_schedule));
|
||||||
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_filled : R.drawable.ic_fluent_clock_20_filled, 0, 0, 0);
|
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_clock_20_filled, 0, 0, 0);
|
||||||
if(GlobalUserPreferences.relocatePublishButton)
|
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.equals(scheduledAt)
|
||||||
{
|
? R.string.save : R.string.sk_schedule);
|
||||||
publishButton.setCompoundDrawablesWithIntrinsicBounds(scheduledStatus != null && scheduledStatus.scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)
|
|
||||||
? R.drawable.ic_fluent_save_24_selector : R.drawable.ic_fluent_clock_24_selector, 0, 0, 0);
|
|
||||||
}else{
|
|
||||||
publishButton.setText(scheduledStatus != null && scheduledStatus.scheduledAt.equals(scheduledAt)
|
|
||||||
? R.string.save : R.string.sk_schedule);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_regular : R.drawable.ic_fluent_clock_20_regular, 0, 0, 0);
|
draftsBtn.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_clock_20_regular, 0, 0, 0);
|
||||||
if(GlobalUserPreferences.relocatePublishButton){
|
|
||||||
publishButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_fluent_send_24_selector, 0, 0, 0);
|
|
||||||
}
|
|
||||||
resetPublishButtonText();
|
resetPublishButtonText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2100,14 +2038,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private void editMediaDescription(DraftMediaAttachment att) {
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
args.putString("account", accountID);
|
|
||||||
args.putString("attachment", att.serverAttachment.id);
|
|
||||||
args.putParcelable("uri", att.uri);
|
|
||||||
args.putString("existingDescription", att.description);
|
|
||||||
Nav.goForResult(getActivity(), ComposeImageDescriptionFragment.class, args, IMAGE_DESCRIPTION_RESULT, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getTitle(){
|
public CharSequence getTitle(){
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountByHandle;
|
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
|
|
||||||
import org.joinmastodon.android.api.requests.search.GetSearchResults;
|
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
|
||||||
import org.joinmastodon.android.model.Account;
|
|
||||||
import org.joinmastodon.android.model.Filter;
|
|
||||||
import org.joinmastodon.android.model.SearchResults;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.joinmastodon.android.model.TimelineDefinition;
|
|
||||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
|
||||||
|
|
||||||
public class CustomLocalTimelineFragment extends StatusListFragment {
|
|
||||||
// private String name;
|
|
||||||
private String domain;
|
|
||||||
|
|
||||||
private String maxID;
|
|
||||||
@Override
|
|
||||||
protected boolean withComposeButton() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity){
|
|
||||||
super.onAttach(activity);
|
|
||||||
domain=getArguments().getString("domain");
|
|
||||||
updateTitle(domain);
|
|
||||||
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTitle(String domain) {
|
|
||||||
this.domain = domain;
|
|
||||||
setTitle(this.domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doLoadData(int offset, int count){
|
|
||||||
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count)
|
|
||||||
.setCallback(new SimpleCallback<>(this){
|
|
||||||
@Override
|
|
||||||
public void onSuccess(List<Status> result){
|
|
||||||
if(!result.isEmpty())
|
|
||||||
maxID=result.get(result.size()-1).id;
|
|
||||||
if (getActivity() == null) return;
|
|
||||||
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
|
|
||||||
result.stream().forEach(status -> {
|
|
||||||
status.account.acct += "@"+domain;
|
|
||||||
status.reloadWhenClicked = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
onDataLoaded(result, !result.isEmpty());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.execNoAuth(domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onShown(){
|
|
||||||
super.onShown();
|
|
||||||
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ import static org.joinmastodon.android.ui.utils.UiUtils.makeBackItem;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -16,7 +15,6 @@ import android.view.SubMenu;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@@ -32,7 +30,6 @@ import org.joinmastodon.android.GlobalUserPreferences;
|
|||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.lists.GetLists;
|
import org.joinmastodon.android.api.requests.lists.GetLists;
|
||||||
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
|
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
|
||||||
import org.joinmastodon.android.model.CustomLocalTimeline;
|
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.model.HeaderPaginationList;
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
import org.joinmastodon.android.model.ListTimeline;
|
import org.joinmastodon.android.model.ListTimeline;
|
||||||
@@ -52,7 +49,6 @@ import me.grishka.appkit.api.Callback;
|
|||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.utils.V;
|
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefinition> implements ScrollableToTop {
|
public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefinition> implements ScrollableToTop {
|
||||||
@@ -64,7 +60,6 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
private final Map<MenuItem, TimelineDefinition> timelineByMenuItem = new HashMap<>();
|
private final Map<MenuItem, TimelineDefinition> timelineByMenuItem = new HashMap<>();
|
||||||
private final List<ListTimeline> listTimelines = new ArrayList<>();
|
private final List<ListTimeline> listTimelines = new ArrayList<>();
|
||||||
private final List<Hashtag> hashtags = new ArrayList<>();
|
private final List<Hashtag> hashtags = new ArrayList<>();
|
||||||
private final List<CustomLocalTimeline> localTimelines = new ArrayList<>();
|
|
||||||
|
|
||||||
public EditTimelinesFragment() {
|
public EditTimelinesFragment() {
|
||||||
super(10);
|
super(10);
|
||||||
@@ -133,10 +128,6 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
optionsMenu.performIdentifierAction(R.id.menu_add_timeline, 0);
|
optionsMenu.performIdentifierAction(R.id.menu_add_timeline, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (item.getItemId() == R.id.menu_add_local_timelines) {
|
|
||||||
addNewLocalTimeline();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
TimelineDefinition tl = timelineByMenuItem.get(item);
|
TimelineDefinition tl = timelineByMenuItem.get(item);
|
||||||
if (tl != null) {
|
if (tl != null) {
|
||||||
data.add(tl.copy());
|
data.add(tl.copy());
|
||||||
@@ -147,26 +138,6 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addNewLocalTimeline() {
|
|
||||||
FrameLayout inputWrap = new FrameLayout(getContext());
|
|
||||||
EditText input = new EditText(getContext());
|
|
||||||
input.setHint(R.string.sk_example_domain);
|
|
||||||
input.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
|
|
||||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.setMargins(V.dp(16), V.dp(4), V.dp(16), V.dp(16));
|
|
||||||
input.setLayoutParams(params);
|
|
||||||
inputWrap.addView(input);
|
|
||||||
new M3AlertDialogBuilder(getContext()).setTitle(R.string.mo_add_custom_server_local_timeline).setView(inputWrap)
|
|
||||||
.setPositiveButton(R.string.save, (d, which) -> {
|
|
||||||
TimelineDefinition tl = TimelineDefinition.ofCustomLocalTimeline(input.getText().toString().trim());
|
|
||||||
data.add(tl);
|
|
||||||
saveTimelines();
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.cancel, (d, which) -> {
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTimelineToOptions(TimelineDefinition tl, Menu menu) {
|
private void addTimelineToOptions(TimelineDefinition tl, Menu menu) {
|
||||||
if (data.contains(tl)) return;
|
if (data.contains(tl)) return;
|
||||||
MenuItem item = menu.add(0, View.generateViewId(), Menu.NONE, tl.getTitle(getContext()));
|
MenuItem item = menu.add(0, View.generateViewId(), Menu.NONE, tl.getTitle(getContext()));
|
||||||
@@ -190,9 +161,6 @@ public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefiniti
|
|||||||
SubMenu hashtagsMenu = menu.addSubMenu(R.string.sk_hashtag);
|
SubMenu hashtagsMenu = menu.addSubMenu(R.string.sk_hashtag);
|
||||||
hashtagsMenu.getItem().setIcon(R.drawable.ic_fluent_number_symbol_24_regular);
|
hashtagsMenu.getItem().setIcon(R.drawable.ic_fluent_number_symbol_24_regular);
|
||||||
|
|
||||||
MenuItem addLocalTimelines = menu.add(0, R.id.menu_add_local_timelines, NONE, R.string.local_timeline);
|
|
||||||
addLocalTimelines.setIcon(R.drawable.ic_fluent_add_24_regular);
|
|
||||||
|
|
||||||
makeBackItem(timelinesMenu);
|
makeBackItem(timelinesMenu);
|
||||||
makeBackItem(listsMenu);
|
makeBackItem(listsMenu);
|
||||||
makeBackItem(hashtagsMenu);
|
makeBackItem(hashtagsMenu);
|
||||||
|
|||||||
@@ -41,11 +41,7 @@ import me.grishka.appkit.views.FragmentRootLinearLayout;
|
|||||||
|
|
||||||
public class HomeFragment extends AppKitFragment implements OnBackPressedListener{
|
public class HomeFragment extends AppKitFragment implements OnBackPressedListener{
|
||||||
private FragmentRootLinearLayout content;
|
private FragmentRootLinearLayout content;
|
||||||
|
|
||||||
private HomeTabFragment homeTabFragment;
|
private HomeTabFragment homeTabFragment;
|
||||||
|
|
||||||
// private HomeTimelineFragment homeTimelineFragment;
|
|
||||||
|
|
||||||
private NotificationsFragment notificationsFragment;
|
private NotificationsFragment notificationsFragment;
|
||||||
private DiscoverFragment searchFragment;
|
private DiscoverFragment searchFragment;
|
||||||
private ProfileFragment profileFragment;
|
private ProfileFragment profileFragment;
|
||||||
@@ -61,7 +57,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
accountID=getArguments().getString("account");
|
accountID=getArguments().getString("account");
|
||||||
setTitle(R.string.mo_app_name);
|
setTitle(R.string.sk_app_name);
|
||||||
|
|
||||||
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
@@ -69,13 +65,8 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
if(savedInstanceState==null){
|
if(savedInstanceState==null){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
|
|
||||||
homeTabFragment=new HomeTabFragment();
|
homeTabFragment=new HomeTabFragment();
|
||||||
homeTabFragment.setArguments(args);
|
homeTabFragment.setArguments(args);
|
||||||
|
|
||||||
// homeTimelineFragment=new HomeTimelineFragment();
|
|
||||||
// homeTimelineFragment.setArguments(args);
|
|
||||||
|
|
||||||
args=new Bundle(args);
|
args=new Bundle(args);
|
||||||
args.putBoolean("noAutoLoad", true);
|
args.putBoolean("noAutoLoad", true);
|
||||||
searchFragment=new DiscoverFragment();
|
searchFragment=new DiscoverFragment();
|
||||||
@@ -125,13 +116,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
.add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
|
.add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
||||||
// getChildFragmentManager().beginTransaction()
|
|
||||||
// .add(R.id.fragment_wrap, homeTimelineFragment)
|
|
||||||
// .add(R.id.fragment_wrap, searchFragment).hide(searchFragment)
|
|
||||||
// .add(R.id.fragment_wrap, notificationsFragment).hide(notificationsFragment)
|
|
||||||
// .add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
|
|
||||||
// .commit();
|
|
||||||
|
|
||||||
String defaultTab=getArguments().getString("tab");
|
String defaultTab=getArguments().getString("tab");
|
||||||
if("notifications".equals(defaultTab)){
|
if("notifications".equals(defaultTab)){
|
||||||
tabBar.selectTab(R.id.tab_notifications);
|
tabBar.selectTab(R.id.tab_notifications);
|
||||||
@@ -152,21 +136,13 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
@Override
|
@Override
|
||||||
public void onViewStateRestored(Bundle savedInstanceState){
|
public void onViewStateRestored(Bundle savedInstanceState){
|
||||||
super.onViewStateRestored(savedInstanceState);
|
super.onViewStateRestored(savedInstanceState);
|
||||||
|
|
||||||
if(savedInstanceState==null) return;
|
if(savedInstanceState==null) return;
|
||||||
|
|
||||||
// if(savedInstanceState==null || homeTimelineFragment!=null)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
homeTabFragment=(HomeTabFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTabFragment");
|
homeTabFragment=(HomeTabFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTabFragment");
|
||||||
|
|
||||||
// homeTimelineFragment=(HomeTimelineFragment) getChildFragmentManager().getFragment(savedInstanceState, "homeTimelineFragment");
|
|
||||||
searchFragment=(DiscoverFragment) getChildFragmentManager().getFragment(savedInstanceState, "searchFragment");
|
searchFragment=(DiscoverFragment) getChildFragmentManager().getFragment(savedInstanceState, "searchFragment");
|
||||||
notificationsFragment=(NotificationsFragment) getChildFragmentManager().getFragment(savedInstanceState, "notificationsFragment");
|
notificationsFragment=(NotificationsFragment) getChildFragmentManager().getFragment(savedInstanceState, "notificationsFragment");
|
||||||
profileFragment=(ProfileFragment) getChildFragmentManager().getFragment(savedInstanceState, "profileFragment");
|
profileFragment=(ProfileFragment) getChildFragmentManager().getFragment(savedInstanceState, "profileFragment");
|
||||||
currentTab=savedInstanceState.getInt("selectedTab");
|
currentTab=savedInstanceState.getInt("selectedTab");
|
||||||
Fragment current=fragmentForTab(currentTab);
|
Fragment current=fragmentForTab(currentTab);
|
||||||
|
|
||||||
getChildFragmentManager().beginTransaction()
|
getChildFragmentManager().beginTransaction()
|
||||||
.hide(homeTabFragment)
|
.hide(homeTabFragment)
|
||||||
.hide(searchFragment)
|
.hide(searchFragment)
|
||||||
@@ -174,14 +150,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
.hide(profileFragment)
|
.hide(profileFragment)
|
||||||
.show(current)
|
.show(current)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
||||||
// getChildFragmentManager().beginTransaction()
|
|
||||||
// .hide(homeTimelineFragment)
|
|
||||||
// .hide(searchFragment)
|
|
||||||
// .hide(notificationsFragment)
|
|
||||||
// .hide(profileFragment)
|
|
||||||
// .show(current)
|
|
||||||
// .commit();
|
|
||||||
maybeTriggerLoading(current);
|
maybeTriggerLoading(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,11 +179,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||||
}
|
}
|
||||||
WindowInsets topOnlyInsets=insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
|
WindowInsets topOnlyInsets=insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
|
||||||
|
|
||||||
homeTabFragment.onApplyWindowInsets(topOnlyInsets);
|
homeTabFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
|
|
||||||
// homeTimelineFragment.onApplyWindowInsets(topOnlyInsets);
|
|
||||||
|
|
||||||
searchFragment.onApplyWindowInsets(topOnlyInsets);
|
searchFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
notificationsFragment.onApplyWindowInsets(topOnlyInsets);
|
notificationsFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
profileFragment.onApplyWindowInsets(topOnlyInsets);
|
profileFragment.onApplyWindowInsets(topOnlyInsets);
|
||||||
@@ -224,9 +188,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
private Fragment fragmentForTab(@IdRes int tab){
|
private Fragment fragmentForTab(@IdRes int tab){
|
||||||
if(tab==R.id.tab_home){
|
if(tab==R.id.tab_home){
|
||||||
return homeTabFragment;
|
return homeTabFragment;
|
||||||
|
|
||||||
// if(tab==R.id.tab_home){
|
|
||||||
// return homeTimelineFragment;
|
|
||||||
}else if(tab==R.id.tab_search){
|
}else if(tab==R.id.tab_search){
|
||||||
return searchFragment;
|
return searchFragment;
|
||||||
}else if(tab==R.id.tab_notifications){
|
}else if(tab==R.id.tab_notifications){
|
||||||
@@ -240,18 +201,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
private void onTabSelected(@IdRes int tab){
|
private void onTabSelected(@IdRes int tab){
|
||||||
Fragment newFragment=fragmentForTab(tab);
|
Fragment newFragment=fragmentForTab(tab);
|
||||||
if(tab==currentTab){
|
if(tab==currentTab){
|
||||||
if(tab == R.id.tab_search){
|
if (tab == R.id.tab_search)
|
||||||
if(newFragment instanceof ScrollableToTop scrollable)
|
searchFragment.onSelect();
|
||||||
scrollable.scrollToTop();
|
else if(newFragment instanceof ScrollableToTop scrollable)
|
||||||
searchFragment.selectSearch();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(newFragment instanceof ScrollableToTop scrollable)
|
|
||||||
scrollable.scrollToTop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(tab==currentTab && tab == R.id.tab_search){
|
|
||||||
if(newFragment instanceof ScrollableToTop scrollable)
|
|
||||||
scrollable.scrollToTop();
|
scrollable.scrollToTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -288,12 +240,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
new AccountSwitcherSheet(getActivity()).show();
|
new AccountSwitcherSheet(getActivity()).show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(tab==R.id.tab_search){
|
|
||||||
onTabSelected(R.id.tab_search);
|
|
||||||
tabBar.selectTab(R.id.tab_search);
|
|
||||||
searchFragment.selectSearch();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,15 +262,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
|||||||
public void onSaveInstanceState(Bundle outState){
|
public void onSaveInstanceState(Bundle outState){
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putInt("selectedTab", currentTab);
|
outState.putInt("selectedTab", currentTab);
|
||||||
|
|
||||||
if (homeTabFragment.isAdded()) getChildFragmentManager().putFragment(outState, "homeTabFragment", homeTabFragment);
|
if (homeTabFragment.isAdded()) getChildFragmentManager().putFragment(outState, "homeTabFragment", homeTabFragment);
|
||||||
if (searchFragment.isAdded()) getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
|
if (searchFragment.isAdded()) getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
|
||||||
if (notificationsFragment.isAdded()) getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
if (notificationsFragment.isAdded()) getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
||||||
if (profileFragment.isAdded()) getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
if (profileFragment.isAdded()) getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
||||||
|
|
||||||
// getChildFragmentManager().putFragment(outState, "homeTimelineFragment", homeTimelineFragment);
|
|
||||||
// getChildFragmentManager().putFragment(outState, "searchFragment", searchFragment);
|
|
||||||
// getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
|
||||||
// getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
|||||||
addListsToOverflowMenu();
|
addListsToOverflowMenu();
|
||||||
addHashtagsToOverflowMenu();
|
addHashtagsToOverflowMenu();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !UiUtils.isEMUI()) {
|
||||||
m.setGroupDividerEnabled(true);
|
m.setGroupDividerEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Status> filterPosts(List<Status> items) {
|
private List<Status> filterPosts(List<Status> items) {
|
||||||
// This is the function I must use to solve the filters thing for real
|
|
||||||
return items.stream().filter(i ->
|
return items.stream().filter(i ->
|
||||||
(GlobalUserPreferences.showReplies || i.inReplyToId == null) &&
|
(GlobalUserPreferences.showReplies || i.inReplyToId == null) &&
|
||||||
(GlobalUserPreferences.showBoosts || i.reblog == null)
|
(GlobalUserPreferences.showBoosts || i.reblog == null)
|
||||||
@@ -103,24 +102,24 @@ public class HomeTimelineFragment extends StatusListFragment {
|
|||||||
@Override
|
@Override
|
||||||
protected void onHidden(){
|
protected void onHidden(){
|
||||||
super.onHidden();
|
super.onHidden();
|
||||||
// if(!data.isEmpty()){
|
if(!data.isEmpty()){
|
||||||
// String topPostID=displayItems.get(list.getChildAdapterPosition(list.getChildAt(0))-getMainAdapterOffset()).parentID;
|
String topPostID=displayItems.get(Math.max(0, list.getChildAdapterPosition(list.getChildAt(0))-getMainAdapterOffset())).parentID;
|
||||||
// if(!topPostID.equals(lastSavedMarkerID)){
|
if(!topPostID.equals(lastSavedMarkerID)){
|
||||||
// lastSavedMarkerID=topPostID;
|
lastSavedMarkerID=topPostID;
|
||||||
// new SaveMarkers(topPostID, null)
|
new SaveMarkers(topPostID, null)
|
||||||
// .setCallback(new Callback<>(){
|
.setCallback(new Callback<>(){
|
||||||
// @Override
|
@Override
|
||||||
// public void onSuccess(SaveMarkers.Response result){
|
public void onSuccess(SaveMarkers.Response result){
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Override
|
@Override
|
||||||
// public void onError(ErrorResponse error){
|
public void onError(ErrorResponse error){
|
||||||
// lastSavedMarkerID=null;
|
lastSavedMarkerID=null;
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// .exec(accountID);
|
.exec(accountID);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onStatusCreated(StatusCreatedEvent ev){
|
public void onStatusCreated(StatusCreatedEvent ev){
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
private FrameLayout[] tabViews;
|
private FrameLayout[] tabViews;
|
||||||
private TabLayoutMediator tabLayoutMediator;
|
private TabLayoutMediator tabLayoutMediator;
|
||||||
|
|
||||||
private NotificationsListFragment allNotificationsFragment, mentionsFragment, postsFragment;
|
private NotificationsListFragment allNotificationsFragment, mentionsFragment;
|
||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
|
|
||||||
@@ -102,14 +102,14 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
|
|
||||||
tabLayout=view.findViewById(R.id.tabbar);
|
tabLayout=view.findViewById(R.id.tabbar);
|
||||||
pager=view.findViewById(R.id.pager);
|
pager=view.findViewById(R.id.pager);
|
||||||
|
UiUtils.reduceSwipeSensitivity(pager);
|
||||||
|
|
||||||
tabViews=new FrameLayout[3];
|
tabViews=new FrameLayout[2];
|
||||||
for(int i=0;i<tabViews.length;i++){
|
for(int i=0;i<tabViews.length;i++){
|
||||||
FrameLayout tabView=new FrameLayout(getActivity());
|
FrameLayout tabView=new FrameLayout(getActivity());
|
||||||
tabView.setId(switch(i){
|
tabView.setId(switch(i){
|
||||||
case 0 -> R.id.notifications_all;
|
case 0 -> R.id.notifications_all;
|
||||||
case 1 -> R.id.notifications_mentions;
|
case 1 -> R.id.notifications_mentions;
|
||||||
case 2 -> R.id.notifications_posts;
|
|
||||||
default -> throw new IllegalStateException("Unexpected value: "+i);
|
default -> throw new IllegalStateException("Unexpected value: "+i);
|
||||||
});
|
});
|
||||||
tabView.setVisibility(View.GONE);
|
tabView.setVisibility(View.GONE);
|
||||||
@@ -119,6 +119,18 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
|
|
||||||
tabLayout.setTabTextSize(V.dp(16));
|
tabLayout.setTabTextSize(V.dp(16));
|
||||||
tabLayout.setTabTextColors(UiUtils.getThemeColor(getActivity(), R.attr.colorTabInactive), UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary));
|
tabLayout.setTabTextColors(UiUtils.getThemeColor(getActivity(), R.attr.colorTabInactive), UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary));
|
||||||
|
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onTabSelected(TabLayout.Tab tab) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(TabLayout.Tab tab) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(TabLayout.Tab tab) {
|
||||||
|
scrollToTop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
pager.setOffscreenPageLimit(4);
|
pager.setOffscreenPageLimit(4);
|
||||||
pager.setUserInputEnabled(!GlobalUserPreferences.disableSwipe);
|
pager.setUserInputEnabled(!GlobalUserPreferences.disableSwipe);
|
||||||
@@ -149,15 +161,9 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
mentionsFragment=new NotificationsListFragment();
|
mentionsFragment=new NotificationsListFragment();
|
||||||
mentionsFragment.setArguments(args);
|
mentionsFragment.setArguments(args);
|
||||||
|
|
||||||
args=new Bundle(args);
|
|
||||||
args.putBoolean("onlyPosts", true);
|
|
||||||
postsFragment=new NotificationsListFragment();
|
|
||||||
postsFragment.setArguments(args);
|
|
||||||
|
|
||||||
getChildFragmentManager().beginTransaction()
|
getChildFragmentManager().beginTransaction()
|
||||||
.add(R.id.notifications_all, allNotificationsFragment)
|
.add(R.id.notifications_all, allNotificationsFragment)
|
||||||
.add(R.id.notifications_mentions, mentionsFragment)
|
.add(R.id.notifications_mentions, mentionsFragment)
|
||||||
.add(R.id.notifications_posts, postsFragment)
|
|
||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +173,6 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
tab.setText(switch(position){
|
tab.setText(switch(position){
|
||||||
case 0 -> R.string.all_notifications;
|
case 0 -> R.string.all_notifications;
|
||||||
case 1 -> R.string.mentions;
|
case 1 -> R.string.mentions;
|
||||||
case 2 -> R.string.posts;
|
|
||||||
default -> throw new IllegalStateException("Unexpected value: "+position);
|
default -> throw new IllegalStateException("Unexpected value: "+position);
|
||||||
});
|
});
|
||||||
tab.view.textView.setAllCaps(true);
|
tab.view.textView.setAllCaps(true);
|
||||||
@@ -182,6 +187,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
new GetFollowRequests(null, 1).setCallback(new Callback<>() {
|
new GetFollowRequests(null, 1).setCallback(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(HeaderPaginationList<Account> accounts) {
|
public void onSuccess(HeaderPaginationList<Account> accounts) {
|
||||||
|
if (getActivity() == null) return;
|
||||||
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
|
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,13 +216,13 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
protected void updateToolbar(){
|
protected void updateToolbar(){
|
||||||
super.updateToolbar();
|
super.updateToolbar();
|
||||||
getToolbar().setOutlineProvider(null);
|
getToolbar().setOutlineProvider(null);
|
||||||
|
getToolbar().setOnClickListener(v->scrollToTop());
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotificationsListFragment getFragmentForPage(int page){
|
private NotificationsListFragment getFragmentForPage(int page){
|
||||||
return switch(page){
|
return switch(page){
|
||||||
case 0 -> allNotificationsFragment;
|
case 0 -> allNotificationsFragment;
|
||||||
case 1 -> mentionsFragment;
|
case 1 -> mentionsFragment;
|
||||||
case 2 -> postsFragment;
|
|
||||||
default -> throw new IllegalStateException("Unexpected value: "+page);
|
default -> throw new IllegalStateException("Unexpected value: "+page);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -237,7 +243,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount(){
|
public int getItemCount(){
|
||||||
return 3;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -245,4 +251,4 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ import org.joinmastodon.android.model.Notification;
|
|||||||
import org.joinmastodon.android.model.PaginatedResponse;
|
import org.joinmastodon.android.model.PaginatedResponse;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||||
@@ -40,7 +38,6 @@ import java.util.stream.Stream;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
import me.grishka.appkit.utils.V;
|
|
||||||
|
|
||||||
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
|
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
|
||||||
private boolean onlyMentions;
|
private boolean onlyMentions;
|
||||||
@@ -97,14 +94,9 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
};
|
};
|
||||||
HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, n.status, extraText, n, null) : null;
|
HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, n.status, extraText, n, null) : null;
|
||||||
if(n.status!=null){
|
if(n.status!=null){
|
||||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS, titleItem);
|
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS);
|
||||||
if(titleItem!=null){
|
if(titleItem!=null)
|
||||||
for(StatusDisplayItem item:items){
|
items.add(0, titleItem);
|
||||||
if(item instanceof ImageStatusDisplayItem imgItem){
|
|
||||||
imgItem.horizontalInset=V.dp(32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items;
|
return items;
|
||||||
}else if(titleItem!=null){
|
}else if(titleItem!=null){
|
||||||
AccountCardStatusDisplayItem card=new AccountCardStatusDisplayItem(n.id, this,
|
AccountCardStatusDisplayItem card=new AccountCardStatusDisplayItem(n.id, this,
|
||||||
@@ -125,6 +117,8 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||||||
knownAccounts.put(s.account.id, s.account);
|
knownAccounts.put(s.account.id, s.account);
|
||||||
if(s.status!=null && !knownAccounts.containsKey(s.status.account.id))
|
if(s.status!=null && !knownAccounts.containsKey(s.status.account.id))
|
||||||
knownAccounts.put(s.status.account.id, s.status.account);
|
knownAccounts.put(s.status.account.id, s.status.account);
|
||||||
|
if(s.status!=null && s.status.reblog!=null && !knownAccounts.containsKey(s.status.reblog.account.id))
|
||||||
|
knownAccounts.put(s.status.reblog.account.id, s.status.reblog.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class PinnableStatusListFragment extends StatusListFragment {
|
public abstract class PinnableStatusListFragment extends StatusListFragment {
|
||||||
protected boolean pinnedUpdated;
|
|
||||||
protected List<TimelineDefinition> pinnedTimelines;
|
protected List<TimelineDefinition> pinnedTimelines;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -54,7 +53,7 @@ public abstract class PinnableStatusListFragment extends StatusListFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void togglePin(MenuItem pin) {
|
protected void togglePin(MenuItem pin) {
|
||||||
pinnedUpdated = true;
|
onPinnedUpdated(true);
|
||||||
getToolbar().performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
|
getToolbar().performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
|
||||||
TimelineDefinition def = makeTimelineDefinition();
|
TimelineDefinition def = makeTimelineDefinition();
|
||||||
boolean pinned = isPinned();
|
boolean pinned = isPinned();
|
||||||
@@ -66,17 +65,5 @@ public abstract class PinnableStatusListFragment extends StatusListFragment {
|
|||||||
updatePinButton(pin);
|
updatePinButton(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Bundle getResultArgs() {
|
public void onPinnedUpdated(boolean pinned) {}
|
||||||
return new Bundle();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
Bundle resultArgs = getResultArgs();
|
|
||||||
if (pinnedUpdated) {
|
|
||||||
resultArgs.putBoolean("pinnedUpdated", true);
|
|
||||||
setResult(true, resultArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.joinmastodon.android.fragments;
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
@@ -13,23 +12,11 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.SetPrivateNote;
|
|
||||||
import org.joinmastodon.android.model.AccountField;
|
import org.joinmastodon.android.model.AccountField;
|
||||||
import org.joinmastodon.android.model.Relationship;
|
|
||||||
import org.joinmastodon.android.ui.BetterItemAnimator;
|
import org.joinmastodon.android.ui.BetterItemAnimator;
|
||||||
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
|
||||||
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
|
||||||
@@ -39,8 +26,11 @@ import org.joinmastodon.android.ui.views.LinkedTextView;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.grishka.appkit.api.Callback;
|
import androidx.annotation.NonNull;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.fragments.WindowInsetsAwareFragment;
|
import me.grishka.appkit.fragments.WindowInsetsAwareFragment;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
@@ -56,11 +46,6 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
|
|||||||
private static final int MAX_FIELDS=4;
|
private static final int MAX_FIELDS=4;
|
||||||
|
|
||||||
public UsableRecyclerView list;
|
public UsableRecyclerView list;
|
||||||
public FrameLayout noteWrap;
|
|
||||||
public EditText noteEdit;
|
|
||||||
private String accountID;
|
|
||||||
private String profileAccountID;
|
|
||||||
private String note;
|
|
||||||
private List<AccountField> fields=Collections.emptyList();
|
private List<AccountField> fields=Collections.emptyList();
|
||||||
private AboutAdapter adapter;
|
private AboutAdapter adapter;
|
||||||
private Paint dividerPaint=new Paint();
|
private Paint dividerPaint=new Paint();
|
||||||
@@ -79,49 +64,11 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
|
|||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNote(String note, String accountID, String profileAccountID){
|
|
||||||
this.note=note;
|
|
||||||
this.accountID=accountID;
|
|
||||||
this.profileAccountID=profileAccountID;
|
|
||||||
// noteWrap.setVisibility(View.VISIBLE);
|
|
||||||
// noteEdit.setVisibility(View.VISIBLE);
|
|
||||||
// noteEdit.setText(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
|
||||||
View view = inflater.inflate(R.layout.fragment_profile_about, null);
|
list=new UsableRecyclerView(getActivity());
|
||||||
|
list.setId(R.id.list);
|
||||||
noteEdit = view.findViewById(R.id.note_edit);
|
|
||||||
noteWrap = view.findViewById(R.id.note_edit_wrap);
|
|
||||||
ImageButton noteEditConfirm = view.findViewById(R.id.note_edit_confirm);
|
|
||||||
|
|
||||||
|
|
||||||
noteEdit.setOnFocusChangeListener((v, hasFocus) -> {
|
|
||||||
if (hasFocus) {
|
|
||||||
noteEditConfirm.setVisibility(View.VISIBLE);
|
|
||||||
noteEditConfirm.animate()
|
|
||||||
.alpha(1.0f)
|
|
||||||
.setDuration(700);
|
|
||||||
} else {
|
|
||||||
noteEditConfirm.animate()
|
|
||||||
.alpha(0.0f)
|
|
||||||
.setDuration(700);
|
|
||||||
noteEditConfirm.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
noteEditConfirm.setOnClickListener((v -> {
|
|
||||||
if (!noteEdit.getText().toString().trim().equals(note)) {
|
|
||||||
savePrivateNote();
|
|
||||||
}
|
|
||||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
|
|
||||||
imm.hideSoftInputFromWindow(this.getView().getRootView().getWindowToken(), 0);
|
|
||||||
noteEdit.clearFocus();
|
|
||||||
}));
|
|
||||||
|
|
||||||
list = view.findViewById(R.id.list);
|
|
||||||
list.setItemAnimator(new BetterItemAnimator());
|
list.setItemAnimator(new BetterItemAnimator());
|
||||||
list.setDrawSelectorOnTop(true);
|
list.setDrawSelectorOnTop(true);
|
||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
@@ -148,20 +95,8 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return view;
|
return list;
|
||||||
}
|
}
|
||||||
private void savePrivateNote(){
|
|
||||||
new SetPrivateNote(profileAccountID, noteEdit.getText().toString()).setCallback(new Callback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Relationship result) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse result) {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.mo_personal_note_update_failed), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}).exec(accountID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void enterEditMode(List<AccountField> editableFields){
|
public void enterEditMode(List<AccountField> editableFields){
|
||||||
isInEditMode=true;
|
isInEditMode=true;
|
||||||
|
|||||||
@@ -45,11 +45,6 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.widget.Toolbar;
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
|
||||||
@@ -57,7 +52,6 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||||
import org.joinmastodon.android.api.requests.accounts.SetPrivateNote;
|
|
||||||
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
|
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
|
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
|
||||||
@@ -143,9 +137,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
private TextView followsYouView;
|
private TextView followsYouView;
|
||||||
private ViewGroup rolesView;
|
private ViewGroup rolesView;
|
||||||
|
|
||||||
public FrameLayout noteWrap;
|
|
||||||
public EditText noteEdit;
|
|
||||||
private String note;
|
|
||||||
private Account account;
|
private Account account;
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Relationship relationship;
|
private Relationship relationship;
|
||||||
@@ -227,7 +218,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
followingCount=content.findViewById(R.id.following_count);
|
followingCount=content.findViewById(R.id.following_count);
|
||||||
followingLabel=content.findViewById(R.id.following_label);
|
followingLabel=content.findViewById(R.id.following_label);
|
||||||
followingBtn=content.findViewById(R.id.following_btn);
|
followingBtn=content.findViewById(R.id.following_btn);
|
||||||
|
|
||||||
postsCount=content.findViewById(R.id.posts_count);
|
postsCount=content.findViewById(R.id.posts_count);
|
||||||
postsLabel=content.findViewById(R.id.posts_label);
|
postsLabel=content.findViewById(R.id.posts_label);
|
||||||
postsBtn=content.findViewById(R.id.posts_btn);
|
postsBtn=content.findViewById(R.id.posts_btn);
|
||||||
@@ -246,10 +236,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
list=content.findViewById(R.id.metadata);
|
list=content.findViewById(R.id.metadata);
|
||||||
rolesView=content.findViewById(R.id.roles);
|
rolesView=content.findViewById(R.id.roles);
|
||||||
|
|
||||||
noteEdit = content.findViewById(R.id.note_edit);
|
|
||||||
noteWrap = content.findViewById(R.id.note_edit_wrap);
|
|
||||||
Button noteEditConfirm = content.findViewById(R.id.note_edit_confirm);
|
|
||||||
|
|
||||||
avatar.setOutlineProvider(new ViewOutlineProvider(){
|
avatar.setOutlineProvider(new ViewOutlineProvider(){
|
||||||
@Override
|
@Override
|
||||||
public void getOutline(View view, Outline outline){
|
public void getOutline(View view, Outline outline){
|
||||||
@@ -258,49 +244,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
});
|
});
|
||||||
avatar.setClipToOutline(true);
|
avatar.setClipToOutline(true);
|
||||||
|
|
||||||
noteEdit.setOnFocusChangeListener((v, hasFocus) -> {
|
|
||||||
if (hasFocus) {
|
|
||||||
fab.setVisibility(View.INVISIBLE);
|
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
fab.getHeight() * 2);
|
|
||||||
animate.setDuration(300);
|
|
||||||
animate.setFillAfter(true);
|
|
||||||
fab.startAnimation(animate);
|
|
||||||
|
|
||||||
noteEditConfirm.setVisibility(View.VISIBLE);
|
|
||||||
noteEditConfirm.animate()
|
|
||||||
.alpha(1.0f)
|
|
||||||
.setDuration(700);
|
|
||||||
} else {
|
|
||||||
fab.setVisibility(View.VISIBLE);
|
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
fab.getHeight() * 2,
|
|
||||||
0);
|
|
||||||
animate.setDuration(300);
|
|
||||||
animate.setFillAfter(true);
|
|
||||||
fab.startAnimation(animate);
|
|
||||||
|
|
||||||
noteEditConfirm.animate()
|
|
||||||
.alpha(0.0f)
|
|
||||||
.setDuration(700);
|
|
||||||
noteEditConfirm.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
noteEditConfirm.setOnClickListener((v -> {
|
|
||||||
if (!noteEdit.getText().toString().trim().equals(note)) {
|
|
||||||
savePrivateNote();
|
|
||||||
}
|
|
||||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
|
|
||||||
imm.hideSoftInputFromWindow(this.getView().getRootView().getWindowToken(), 0);
|
|
||||||
noteEdit.clearFocus();
|
|
||||||
}));
|
|
||||||
|
|
||||||
FrameLayout sizeWrapper=new FrameLayout(getActivity()){
|
FrameLayout sizeWrapper=new FrameLayout(getActivity()){
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
||||||
@@ -401,25 +344,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
return sizeWrapper;
|
return sizeWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNote(String note){
|
|
||||||
this.note=note;
|
|
||||||
noteWrap.setVisibility(View.VISIBLE);
|
|
||||||
noteEdit.setVisibility(View.VISIBLE);
|
|
||||||
noteEdit.setText(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void savePrivateNote(){
|
|
||||||
new SetPrivateNote(profileAccountID, noteEdit.getText().toString()).setCallback(new Callback<>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Relationship result) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(ErrorResponse result) {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.mo_personal_note_update_failed), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}).exec(accountID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doLoadData(){
|
protected void doLoadData(){
|
||||||
currentRequest=new GetAccountByID(profileAccountID)
|
currentRequest=new GetAccountByID(profileAccountID)
|
||||||
@@ -457,11 +381,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh(){
|
public void onRefresh(){
|
||||||
if(isInEditMode){
|
|
||||||
refreshing=false;
|
|
||||||
refreshLayout.setRefreshing(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(refreshing)
|
if(refreshing)
|
||||||
return;
|
return;
|
||||||
refreshing=true;
|
refreshing=true;
|
||||||
@@ -588,7 +507,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
boolean isSelf=AccountSessionManager.getInstance().isSelf(accountID, account);
|
boolean isSelf=AccountSessionManager.getInstance().isSelf(accountID, account);
|
||||||
|
|
||||||
|
|
||||||
if(account.locked){
|
if(account.locked){
|
||||||
ssb=new SpannableStringBuilder("@");
|
ssb=new SpannableStringBuilder("@");
|
||||||
ssb.append(account.acct);
|
ssb.append(account.acct);
|
||||||
@@ -602,19 +520,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
lock.setTint(username.getCurrentTextColor());
|
lock.setTint(username.getCurrentTextColor());
|
||||||
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(lock, ImageSpan.ALIGN_BASELINE), 0);
|
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(lock, ImageSpan.ALIGN_BASELINE), 0);
|
||||||
username.setText(ssb);
|
username.setText(ssb);
|
||||||
}else if(account.bot){
|
|
||||||
ssb=new SpannableStringBuilder("@");
|
|
||||||
ssb.append(account.acct);
|
|
||||||
if(isSelf){
|
|
||||||
ssb.append('@');
|
|
||||||
ssb.append(AccountSessionManager.getInstance().getAccount(accountID).domain);
|
|
||||||
}
|
|
||||||
ssb.append(" ");
|
|
||||||
Drawable botIcon=username.getResources().getDrawable(R.drawable.ic_bot, getActivity().getTheme()).mutate();
|
|
||||||
botIcon.setBounds(0, 0, botIcon.getIntrinsicWidth(), botIcon.getIntrinsicHeight());
|
|
||||||
botIcon.setTint(username.getCurrentTextColor());
|
|
||||||
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(botIcon, ImageSpan.ALIGN_BASELINE), 0);
|
|
||||||
username.setText(ssb);
|
|
||||||
}else{
|
}else{
|
||||||
// noinspection SetTextI18n
|
// noinspection SetTextI18n
|
||||||
username.setText('@'+account.acct+(isSelf ? ('@'+AccountSessionManager.getInstance().getAccount(accountID).domain) : ""));
|
username.setText('@'+account.acct+(isSelf ? ('@'+AccountSessionManager.getInstance().getAccount(accountID).domain) : ""));
|
||||||
@@ -626,8 +531,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
bio.setVisibility(View.VISIBLE);
|
bio.setVisibility(View.VISIBLE);
|
||||||
bio.setText(parsedBio);
|
bio.setText(parsedBio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
followersCount.setText(UiUtils.abbreviateNumber(account.followersCount));
|
followersCount.setText(UiUtils.abbreviateNumber(account.followersCount));
|
||||||
followingCount.setText(UiUtils.abbreviateNumber(account.followingCount));
|
followingCount.setText(UiUtils.abbreviateNumber(account.followingCount));
|
||||||
postsCount.setText(UiUtils.abbreviateNumber(account.statusesCount));
|
postsCount.setText(UiUtils.abbreviateNumber(account.statusesCount));
|
||||||
@@ -705,11 +608,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
if(relationship==null && !isOwnProfile)
|
if(relationship==null && !isOwnProfile)
|
||||||
return;
|
return;
|
||||||
inflater.inflate(isOwnProfile ? R.menu.profile_own : R.menu.profile, menu);
|
inflater.inflate(isOwnProfile ? R.menu.profile_own : R.menu.profile, menu);
|
||||||
if(isOwnProfile){
|
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags);
|
||||||
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.scheduled, R.id.bookmarks, R.id.favorites);
|
|
||||||
}else{
|
|
||||||
UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags, R.id.favorites, R.id.scheduled);
|
|
||||||
}
|
|
||||||
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
||||||
MenuItem openWithAccounts = menu.findItem(R.id.open_with_account);
|
MenuItem openWithAccounts = menu.findItem(R.id.open_with_account);
|
||||||
openWithAccounts.setVisible(hasMultipleAccounts);
|
openWithAccounts.setVisible(hasMultipleAccounts);
|
||||||
@@ -852,10 +751,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
notifyProgress.setIndeterminateTintList(notifyButton.getTextColors());
|
notifyProgress.setIndeterminateTintList(notifyButton.getTextColors());
|
||||||
followsYouView.setVisibility(relationship.followedBy ? View.VISIBLE : View.GONE);
|
followsYouView.setVisibility(relationship.followedBy ? View.VISIBLE : View.GONE);
|
||||||
notifyButton.setSelected(relationship.notifying);
|
notifyButton.setSelected(relationship.notifying);
|
||||||
if (!isOwnProfile) {
|
|
||||||
setNote(relationship.note);
|
|
||||||
// aboutFragment.setNote(relationship.note, accountID, profileAccountID);
|
|
||||||
}
|
|
||||||
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
|
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -894,9 +789,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
currentPhotoViewer.offsetView(0, oldScrollY-scrollY);
|
currentPhotoViewer.offsetView(0, oldScrollY-scrollY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GlobalUserPreferences.enableFabAutoHide){
|
if (GlobalUserPreferences.autoHideFab) {
|
||||||
int dy = scrollY - oldScrollY;
|
int dy = scrollY - oldScrollY;
|
||||||
|
|
||||||
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
0,
|
0,
|
||||||
@@ -904,11 +798,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
0,
|
0,
|
||||||
fab.getHeight() * 2);
|
fab.getHeight() * 2);
|
||||||
animate.setDuration(300);
|
animate.setDuration(300);
|
||||||
|
animate.setFillAfter(true);
|
||||||
fab.startAnimation(animate);
|
fab.startAnimation(animate);
|
||||||
fab.setVisibility(View.INVISIBLE);
|
fab.setVisibility(View.INVISIBLE);
|
||||||
scrollDiff = 0;
|
scrollDiff = 0;
|
||||||
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
|
||||||
if (scrollDiff > 400) {
|
if (v.getScrollY() == 0 || scrollDiff > 400) {
|
||||||
fab.setVisibility(View.VISIBLE);
|
fab.setVisibility(View.VISIBLE);
|
||||||
TranslateAnimation animate = new TranslateAnimation(
|
TranslateAnimation animate = new TranslateAnimation(
|
||||||
0,
|
0,
|
||||||
@@ -916,6 +811,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
fab.getHeight() * 2,
|
fab.getHeight() * 2,
|
||||||
0);
|
0);
|
||||||
animate.setDuration(300);
|
animate.setDuration(300);
|
||||||
|
animate.setFillAfter(true);
|
||||||
fab.startAnimation(animate);
|
fab.startAnimation(animate);
|
||||||
scrollDiff = 0;
|
scrollDiff = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -1141,9 +1037,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onBackPressed(){
|
public boolean onBackPressed(){
|
||||||
if(noteEdit.hasFocus()) {
|
|
||||||
savePrivateNote();
|
|
||||||
}
|
|
||||||
if(isInEditMode){
|
if(isInEditMode){
|
||||||
exitEditMode();
|
exitEditMode();
|
||||||
return true;
|
return true;
|
||||||
@@ -1394,7 +1287,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
private class EditableAboutViewHolder extends BaseViewHolder {
|
private class EditableAboutViewHolder extends BaseViewHolder {
|
||||||
private EditText title;
|
private EditText title;
|
||||||
private boolean titleHasFocus, valueHasFocus;
|
|
||||||
private EditText value;
|
private EditText value;
|
||||||
|
|
||||||
public EditableAboutViewHolder(){
|
public EditableAboutViewHolder(){
|
||||||
@@ -1406,19 +1298,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
title.addTextChangedListener(new SimpleTextWatcher(e->item.name=e.toString()));
|
title.addTextChangedListener(new SimpleTextWatcher(e->item.name=e.toString()));
|
||||||
title.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
|
||||||
titleHasFocus = hasFocus;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
value.addTextChangedListener(new SimpleTextWatcher(e->item.value=e.toString()));
|
value.addTextChangedListener(new SimpleTextWatcher(e->item.value=e.toString()));
|
||||||
value.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
|
||||||
valueHasFocus = hasFocus;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
findViewById(R.id.remove_row_btn).setOnClickListener(this::onRemoveRowClick);
|
findViewById(R.id.remove_row_btn).setOnClickListener(this::onRemoveRowClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1429,10 +1309,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onRemoveRowClick(View v){
|
private void onRemoveRowClick(View v){
|
||||||
if(titleHasFocus || valueHasFocus){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos=getAbsoluteAdapterPosition();
|
int pos=getAbsoluteAdapterPosition();
|
||||||
metadataListData.remove(pos);
|
metadataListData.remove(pos);
|
||||||
adapter.notifyItemRemoved(pos);
|
adapter.notifyItemRemoved(pos);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
|||||||
import org.joinmastodon.android.api.requests.statuses.GetScheduledStatuses;
|
import org.joinmastodon.android.api.requests.statuses.GetScheduledStatuses;
|
||||||
import org.joinmastodon.android.events.ScheduledStatusCreatedEvent;
|
import org.joinmastodon.android.events.ScheduledStatusCreatedEvent;
|
||||||
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
|
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
|
||||||
import org.joinmastodon.android.model.Filter;
|
|
||||||
import org.joinmastodon.android.model.HeaderPaginationList;
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
import org.joinmastodon.android.model.ScheduledStatus;
|
import org.joinmastodon.android.model.ScheduledStatus;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
@@ -80,7 +79,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<StatusDisplayItem> buildDisplayItems(ScheduledStatus s) {
|
protected List<StatusDisplayItem> buildDisplayItems(ScheduledStatus s) {
|
||||||
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null, true, Filter.FilterContext.HOME);
|
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import android.view.WindowInsets;
|
|||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.animation.LinearInterpolator;
|
import android.view.animation.LinearInterpolator;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@@ -57,6 +55,7 @@ import org.joinmastodon.android.model.PushSubscription;
|
|||||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||||
import org.joinmastodon.android.ui.OutlineProviders;
|
import org.joinmastodon.android.ui.OutlineProviders;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.joinmastodon.android.ui.views.TextInputFrameLayout;
|
||||||
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
import org.joinmastodon.android.updater.GithubSelfUpdater;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
@@ -114,21 +113,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
items.add(new HeaderItem(R.string.settings_theme));
|
items.add(new HeaderItem(R.string.settings_theme));
|
||||||
items.add(themeItem=new ThemeItem());
|
items.add(themeItem=new ThemeItem());
|
||||||
items.add(new SwitchItem(R.string.theme_true_black, R.drawable.ic_fluent_dark_theme_24_regular, GlobalUserPreferences.trueBlackTheme, this::onTrueBlackThemeChanged));
|
items.add(new SwitchItem(R.string.theme_true_black, R.drawable.ic_fluent_dark_theme_24_regular, GlobalUserPreferences.trueBlackTheme, this::onTrueBlackThemeChanged));
|
||||||
items.add(new SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i->{
|
|
||||||
GlobalUserPreferences.disableMarquee=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i->{
|
|
||||||
GlobalUserPreferences.uniformNotificationIcon=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i->{
|
|
||||||
GlobalUserPreferences.reduceMotion=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
items.add(new ButtonItem(R.string.sk_settings_color_palette, R.drawable.ic_fluent_color_24_regular, b->{
|
items.add(new ButtonItem(R.string.sk_settings_color_palette, R.drawable.ic_fluent_color_24_regular, b->{
|
||||||
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
|
||||||
popupMenu.inflate(R.menu.color_palettes);
|
popupMenu.inflate(R.menu.color_palettes);
|
||||||
@@ -145,41 +129,43 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
case BROWN -> R.string.sk_color_palette_brown;
|
case BROWN -> R.string.sk_color_palette_brown;
|
||||||
case RED -> R.string.sk_color_palette_red;
|
case RED -> R.string.sk_color_palette_red;
|
||||||
case YELLOW -> R.string.sk_color_palette_yellow;
|
case YELLOW -> R.string.sk_color_palette_yellow;
|
||||||
case NORD -> R.string.mo_color_palette_nord;
|
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
items.add(new ButtonItem(R.string.sk_settings_publish_button_text, R.drawable.ic_fluent_send_24_regular, b-> {
|
items.add(new ButtonItem(R.string.sk_settings_publish_button_text, R.drawable.ic_fluent_send_24_regular, b->{
|
||||||
updatePublishText(b);
|
updatePublishText(b);
|
||||||
if (GlobalUserPreferences.relocatePublishButton) {
|
|
||||||
b.setOnClickListener(l -> {
|
b.setOnClickListener(l->{
|
||||||
Toast.makeText(getActivity(), R.string.mo_disable_relocate_publish_button_to_enable_customization,
|
TextInputFrameLayout input = new TextInputFrameLayout(
|
||||||
Toast.LENGTH_LONG).show();
|
getContext(),
|
||||||
});
|
getString(R.string.publish),
|
||||||
} else {
|
GlobalUserPreferences.publishButtonText.trim()
|
||||||
b.setOnClickListener(l -> {
|
);
|
||||||
FrameLayout inputWrap = new FrameLayout(getContext());
|
new M3AlertDialogBuilder(getContext()).setTitle(R.string.sk_settings_publish_button_text_title).setView(input)
|
||||||
EditText input = new EditText(getContext());
|
.setPositiveButton(R.string.save, (d, which) -> {
|
||||||
input.setHint(R.string.publish);
|
GlobalUserPreferences.publishButtonText = input.getEditText().getText().toString().trim();
|
||||||
input.setText(GlobalUserPreferences.publishButtonText.trim());
|
GlobalUserPreferences.save();
|
||||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
updatePublishText(b);
|
||||||
params.setMargins(V.dp(16), V.dp(4), V.dp(16), V.dp(16));
|
})
|
||||||
input.setLayoutParams(params);
|
.setNeutralButton(R.string.clear, (d, which) -> {
|
||||||
inputWrap.addView(input);
|
GlobalUserPreferences.publishButtonText = "";
|
||||||
new M3AlertDialogBuilder(getContext()).setTitle(R.string.sk_settings_publish_button_text_title).setView(inputWrap)
|
GlobalUserPreferences.save();
|
||||||
.setPositiveButton(R.string.save, (d, which) -> {
|
updatePublishText(b);
|
||||||
GlobalUserPreferences.publishButtonText = input.getText().toString().trim();
|
})
|
||||||
GlobalUserPreferences.save();
|
.setNegativeButton(R.string.cancel, (d, which) -> {})
|
||||||
updatePublishText(b);
|
.show();
|
||||||
})
|
});
|
||||||
.setNeutralButton(R.string.clear, (d, which) -> {
|
}));
|
||||||
GlobalUserPreferences.publishButtonText = "";
|
items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.uniformNotificationIcon, i->{
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.uniformNotificationIcon=i.checked;
|
||||||
updatePublishText(b);
|
GlobalUserPreferences.save();
|
||||||
})
|
}));
|
||||||
.setNegativeButton(R.string.cancel, (d, which) -> {
|
items.add(new SwitchItem(R.string.sk_disable_marquee, R.drawable.ic_fluent_text_more_24_regular, GlobalUserPreferences.disableMarquee, i->{
|
||||||
})
|
GlobalUserPreferences.disableMarquee=i.checked;
|
||||||
.show();
|
GlobalUserPreferences.save();
|
||||||
});}
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_reduce_motion, R.drawable.ic_fluent_star_emphasis_24_regular, GlobalUserPreferences.reduceMotion, i->{
|
||||||
|
GlobalUserPreferences.reduceMotion=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.settings_behavior));
|
items.add(new HeaderItem(R.string.settings_behavior));
|
||||||
@@ -209,19 +195,8 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
needAppRestart=true;
|
needAppRestart=true;
|
||||||
}));
|
}));
|
||||||
// items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged));
|
items.add(new SwitchItem(R.string.sk_settings_disable_alt_text_reminder, R.drawable.ic_fluent_image_alt_text_24_regular, GlobalUserPreferences.disableAltTextReminder, i->{
|
||||||
items.add(new SwitchItem(R.string.mo_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{
|
GlobalUserPreferences.disableAltTextReminder=i.checked;
|
||||||
GlobalUserPreferences.disableDividers=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.mo_hide_compose_button_while_scrolling_setting, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.enableFabAutoHide, i->{
|
|
||||||
GlobalUserPreferences.enableFabAutoHide =i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
items.add(new SwitchItem(R.string.mo_relocate_publish_button, R.drawable.ic_fluent_arrow_autofit_down_24_regular, GlobalUserPreferences.relocatePublishButton, i->{
|
|
||||||
GlobalUserPreferences.relocatePublishButton=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
|
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
|
||||||
@@ -232,13 +207,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
|
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.mo_disable_reminder_to_add_alt_text, R.drawable.ic_fluent_image_alt_text_24_regular, GlobalUserPreferences.disableAltTextReminder, i->{
|
|
||||||
GlobalUserPreferences.showNoAltIndicator=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.sk_timelines));
|
items.add(new HeaderItem(R.string.sk_timelines));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_show_replies, R.drawable.ic_fluent_chat_multiple_24_regular, GlobalUserPreferences.showReplies, i->{
|
items.add(new SwitchItem(R.string.sk_settings_show_replies, R.drawable.ic_fluent_chat_multiple_24_regular, GlobalUserPreferences.showReplies, i->{
|
||||||
@@ -259,20 +227,17 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
if (list.findViewHolderForAdapterPosition(items.indexOf(showNewPostsButtonItem)) instanceof SwitchViewHolder svh) svh.rebind();
|
if (list.findViewHolderForAdapterPosition(items.indexOf(showNewPostsButtonItem)) instanceof SwitchViewHolder svh) svh.rebind();
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
items.add(showNewPostsButtonItem = new SwitchItem(R.string.sk_settings_show_new_posts_button, R.drawable.ic_fluent_arrow_up_24_regular, GlobalUserPreferences.showNewPostsButton, i->{
|
items.add(showNewPostsButtonItem = new SwitchItem(R.string.sk_settings_see_new_posts_button, R.drawable.ic_fluent_arrow_up_24_regular, GlobalUserPreferences.showNewPostsButton, i->{
|
||||||
GlobalUserPreferences.showNewPostsButton=i.checked;
|
GlobalUserPreferences.showNewPostsButton=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
items.add(new SwitchItem(R.string.sk_settings_show_alt_indicator, R.drawable.ic_fluent_scan_text_24_regular, GlobalUserPreferences.showAltIndicator, i->{
|
items.add(new SwitchItem(R.string.sk_settings_show_alt_indicator, R.drawable.ic_fluent_scan_text_24_regular, GlobalUserPreferences.showAltIndicator, i->{
|
||||||
GlobalUserPreferences.showAltIndicator=i.checked;
|
GlobalUserPreferences.showAltIndicator=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_show_no_alt_indicator, R.drawable.ic_fluent_important_24_regular, GlobalUserPreferences.showNoAltIndicator, i->{
|
items.add(new SwitchItem(R.string.sk_settings_show_no_alt_indicator, R.drawable.ic_fluent_important_24_regular, GlobalUserPreferences.showNoAltIndicator, i->{
|
||||||
GlobalUserPreferences.showNoAltIndicator=i.checked;
|
GlobalUserPreferences.showNoAltIndicator=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
needAppRestart=true;
|
|
||||||
}));
|
}));
|
||||||
items.add(new SwitchItem(R.string.sk_settings_collapse_long_posts, R.drawable.ic_fluent_chevron_down_24_regular, GlobalUserPreferences.collapseLongPosts, i->{
|
items.add(new SwitchItem(R.string.sk_settings_collapse_long_posts, R.drawable.ic_fluent_chevron_down_24_regular, GlobalUserPreferences.collapseLongPosts, i->{
|
||||||
GlobalUserPreferences.collapseLongPosts=i.checked;
|
GlobalUserPreferences.collapseLongPosts=i.checked;
|
||||||
@@ -283,12 +248,20 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
needAppRestart=true;
|
needAppRestart=true;
|
||||||
}));
|
}));
|
||||||
// items.add(new SwitchItem(R.string.sk_settings_translate_only_opened, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
|
items.add(new SwitchItem(R.string.sk_settings_hide_fab, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.autoHideFab, i->{
|
||||||
// GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
|
GlobalUserPreferences.autoHideFab=i.checked;
|
||||||
// GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
// needAppRestart=true;
|
needAppRestart=true;
|
||||||
// }));
|
}));
|
||||||
|
items.add(new SwitchItem(R.string.sk_settings_translate_only_opened, R.drawable.ic_fluent_translate_24_regular, GlobalUserPreferences.translateButtonOpenedOnly, i->{
|
||||||
|
GlobalUserPreferences.translateButtonOpenedOnly=i.checked;
|
||||||
|
GlobalUserPreferences.save();
|
||||||
|
needAppRestart=true;
|
||||||
|
}));
|
||||||
|
boolean translationAvailable = instance.v2 != null && instance.v2.configuration.translation != null && instance.v2.configuration.translation.enabled;
|
||||||
|
items.add(new SmallTextItem(getString(translationAvailable ?
|
||||||
|
R.string.sk_settings_translation_availability_note_available :
|
||||||
|
R.string.sk_settings_translation_availability_note_unavailable, instanceName)));
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.settings_notifications));
|
items.add(new HeaderItem(R.string.settings_notifications));
|
||||||
items.add(notificationPolicyItem=new NotificationPolicyItem());
|
items.add(notificationPolicyItem=new NotificationPolicyItem());
|
||||||
@@ -347,27 +320,9 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
glitchModeItem.enabled = GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID);
|
glitchModeItem.enabled = GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID);
|
||||||
items.add(new SmallTextItem(getString(R.string.sk_settings_glitch_mode_explanation)));
|
items.add(new SmallTextItem(getString(R.string.sk_settings_glitch_mode_explanation)));
|
||||||
|
|
||||||
|
|
||||||
boolean translationAvailable = instance.v2 != null && instance.v2.configuration.translation != null && instance.v2.configuration.translation.enabled;
|
|
||||||
items.add(new SmallTextItem(getString(translationAvailable ?
|
|
||||||
R.string.sk_settings_translation_availability_note_available :
|
|
||||||
R.string.sk_settings_translation_availability_note_unavailable, instance.title)));
|
|
||||||
|
|
||||||
|
|
||||||
items.add(new HeaderItem(R.string.sk_settings_about));
|
items.add(new HeaderItem(R.string.sk_settings_about));
|
||||||
|
items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon"), R.drawable.ic_fluent_open_24_regular));
|
||||||
if (GithubSelfUpdater.needSelfUpdating()) {
|
items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://ko-fi.com/xsk22"), R.drawable.ic_fluent_heart_24_regular));
|
||||||
checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
|
|
||||||
items.add(checkForUpdateItem);
|
|
||||||
items.add(new SwitchItem(R.string.sk_updater_enable_pre_releases, 0, GlobalUserPreferences.enablePreReleases, i->{
|
|
||||||
GlobalUserPreferences.enablePreReleases=i.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
items.add(new TextItem(R.string.mo_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon"), R.drawable.ic_fluent_open_24_regular));
|
|
||||||
items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sponsors/LucasGGamerM"), R.drawable.ic_fluent_heart_24_regular));
|
|
||||||
|
|
||||||
LruCache<?, ?> cache = imageCache == null ? null : imageCache.getLruCache();
|
LruCache<?, ?> cache = imageCache == null ? null : imageCache.getLruCache();
|
||||||
clearImageCacheItem = new TextItem(R.string.settings_clear_cache, UiUtils.formatFileSize(getContext(), cache != null ? cache.size() : 0, true), this::clearImageCache, 0);
|
clearImageCacheItem = new TextItem(R.string.settings_clear_cache, UiUtils.formatFileSize(getContext(), cache != null ? cache.size() : 0, true), this::clearImageCache, 0);
|
||||||
items.add(clearImageCacheItem);
|
items.add(clearImageCacheItem);
|
||||||
@@ -375,12 +330,14 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
GlobalUserPreferences.recentLanguages.remove(accountID);
|
GlobalUserPreferences.recentLanguages.remove(accountID);
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
})));
|
})));
|
||||||
|
if (GithubSelfUpdater.needSelfUpdating()) {
|
||||||
items.add(new TextItem(R.string.mo_clear_recent_emoji, ()-> {
|
items.add(new SwitchItem(R.string.sk_updater_enable_pre_releases, 0, GlobalUserPreferences.enablePreReleases, i->{
|
||||||
GlobalUserPreferences.recentEmojis.clear();
|
GlobalUserPreferences.enablePreReleases=i.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
}));
|
}));
|
||||||
// items.add(new TextItem(R.string.log_out, this::confirmLogOut));
|
checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
|
||||||
|
items.add(checkForUpdateItem);
|
||||||
|
}
|
||||||
|
|
||||||
if(BuildConfig.DEBUG){
|
if(BuildConfig.DEBUG){
|
||||||
items.add(new RedHeaderItem("Debug options"));
|
items.add(new RedHeaderItem("Debug options"));
|
||||||
@@ -395,7 +352,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.add(new FooterItem(getString(R.string.mo_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
|
items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePublishText(Button btn) {
|
private void updatePublishText(Button btn) {
|
||||||
@@ -483,7 +440,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
else if (id == R.id.brown_color) pref = ColorPreference.BROWN;
|
else if (id == R.id.brown_color) pref = ColorPreference.BROWN;
|
||||||
else if (id == R.id.red_color) pref = ColorPreference.RED;
|
else if (id == R.id.red_color) pref = ColorPreference.RED;
|
||||||
else if (id == R.id.yellow_color) pref = ColorPreference.YELLOW;
|
else if (id == R.id.yellow_color) pref = ColorPreference.YELLOW;
|
||||||
else if (id == R.id.nord_color) pref = ColorPreference.NORD;
|
|
||||||
|
|
||||||
if (pref == null) return false;
|
if (pref == null) return false;
|
||||||
|
|
||||||
@@ -493,7 +449,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void onTrueBlackThemeChanged(SwitchItem item){
|
private void onTrueBlackThemeChanged(SwitchItem item){
|
||||||
GlobalUserPreferences.trueBlackTheme=item.checked;
|
GlobalUserPreferences.trueBlackTheme=item.checked;
|
||||||
GlobalUserPreferences.save();
|
GlobalUserPreferences.save();
|
||||||
@@ -560,12 +515,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
needUpdateNotificationSettings=true;
|
needUpdateNotificationSettings=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNotificationStyleChanged(SwitchItem item){
|
|
||||||
GlobalUserPreferences.uniformNotificationIcon=item.checked;
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void onNotificationsPolicyChanged(PushSubscription.Policy policy){
|
private void onNotificationsPolicyChanged(PushSubscription.Policy policy){
|
||||||
PushSubscription subscription=getPushSubscription();
|
PushSubscription subscription=getPushSubscription();
|
||||||
PushSubscription.Policy prevPolicy=subscription.policy;
|
PushSubscription.Policy prevPolicy=subscription.policy;
|
||||||
@@ -735,13 +684,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ColorPicker extends Item{
|
|
||||||
@Override
|
|
||||||
public int getViewType(){
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ThemeItem extends Item{
|
private static class ThemeItem extends Item{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -995,7 +937,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ButtonViewHolder extends BindableViewHolder<ButtonItem>{
|
private class ButtonViewHolder extends BindableViewHolder<ButtonItem>{
|
||||||
private final Button button;
|
private final Button button;
|
||||||
private final ImageView icon;
|
private final ImageView icon;
|
||||||
@@ -1159,10 +1100,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
if (state == GithubSelfUpdater.UpdateState.CHECKING) return;
|
if (state == GithubSelfUpdater.UpdateState.CHECKING) return;
|
||||||
GithubSelfUpdater.UpdateInfo info=updater.getUpdateInfo();
|
GithubSelfUpdater.UpdateInfo info=updater.getUpdateInfo();
|
||||||
if(state!=GithubSelfUpdater.UpdateState.DOWNLOADED){
|
if(state!=GithubSelfUpdater.UpdateState.DOWNLOADED){
|
||||||
text.setText(getString(R.string.mo_update_available, info.version));
|
text.setText(getString(R.string.sk_update_available, info.version));
|
||||||
button.setText(getString(R.string.download_update, UiUtils.formatFileSize(getActivity(), info.size, false)));
|
button.setText(getString(R.string.download_update, UiUtils.formatFileSize(getActivity(), info.size, false)));
|
||||||
}else{
|
}else{
|
||||||
text.setText(getString(R.string.mo_update_ready, info.version));
|
text.setText(getString(R.string.sk_update_ready, info.version));
|
||||||
button.setText(R.string.install_update);
|
button.setText(R.string.install_update);
|
||||||
}
|
}
|
||||||
if(state==GithubSelfUpdater.UpdateState.DOWNLOADING){
|
if(state==GithubSelfUpdater.UpdateState.DOWNLOADING){
|
||||||
@@ -1179,7 +1120,6 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
|||||||
progress.removeCallbacks(progressUpdater);
|
progress.removeCallbacks(progressUpdater);
|
||||||
}
|
}
|
||||||
changelog.setText(info.changelog);
|
changelog.setText(info.changelog);
|
||||||
// changelog.setText(getString(R.string.sk_changelog, info.changelog));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProgress(){
|
private void updateProgress(){
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.view.View;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusEditHistory;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusEditHistory;
|
||||||
import org.joinmastodon.android.model.Filter;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
@@ -56,7 +55,7 @@ public class StatusEditHistoryFragment extends StatusListFragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||||
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null, Filter.FilterContext.HOME);
|
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null);
|
||||||
int idx=data.indexOf(s);
|
int idx=data.indexOf(s);
|
||||||
if(idx>=0){
|
if(idx>=0){
|
||||||
String date=UiUtils.DATE_TIME_FORMATTER.format(s.createdAt.atZone(ZoneId.systemDefault()));
|
String date=UiUtils.DATE_TIME_FORMATTER.format(s.createdAt.atZone(ZoneId.systemDefault()));
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.joinmastodon.android.model.Status;
|
|||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -42,6 +41,8 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
protected void addAccountToKnown(Status s){
|
protected void addAccountToKnown(Status s){
|
||||||
if(!knownAccounts.containsKey(s.account.id))
|
if(!knownAccounts.containsKey(s.account.id))
|
||||||
knownAccounts.put(s.account.id, s.account);
|
knownAccounts.put(s.account.id, s.account);
|
||||||
|
if(s.reblog!=null && !knownAccounts.containsKey(s.reblog.account.id))
|
||||||
|
knownAccounts.put(s.reblog.account.id, s.reblog.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -61,18 +62,6 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
Status status=getContentStatusByID(id);
|
Status status=getContentStatusByID(id);
|
||||||
if(status==null)
|
if(status==null)
|
||||||
return;
|
return;
|
||||||
if(status.reloadWhenClicked){
|
|
||||||
UiUtils.lookupStatus(getContext(), status, accountID, null, status1 -> {
|
|
||||||
status1.filterRevealed = true;
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
args.putString("account", accountID);
|
|
||||||
args.putParcelable("status", Parcels.wrap(status1));
|
|
||||||
if(status1.inReplyToAccountId!=null && knownAccounts.containsKey(status1.inReplyToAccountId))
|
|
||||||
args.putParcelable("inReplyToAccount", Parcels.wrap(knownAccounts.get(status1.inReplyToAccountId)));
|
|
||||||
Nav.go(getActivity(), ThreadFragment.class, args);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
status.filterRevealed = true;
|
status.filterRevealed = true;
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.joinmastodon.android.fragments.discover;
|
package org.joinmastodon.android.fragments.discover;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.FragmentTransaction;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
@@ -18,11 +17,10 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.BuildConfig;
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.fragments.IsOnTop;
|
||||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||||
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
|
||||||
import org.joinmastodon.android.ui.SimpleViewHolder;
|
import org.joinmastodon.android.ui.SimpleViewHolder;
|
||||||
import org.joinmastodon.android.ui.tabs.TabLayout;
|
import org.joinmastodon.android.ui.tabs.TabLayout;
|
||||||
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
|
||||||
@@ -38,7 +36,7 @@ import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
|||||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener{
|
public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener, IsOnTop {
|
||||||
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ViewPager2 pager;
|
private ViewPager2 pager;
|
||||||
@@ -55,15 +53,10 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
private DiscoverNewsFragment newsFragment;
|
private DiscoverNewsFragment newsFragment;
|
||||||
private DiscoverAccountsFragment accountsFragment;
|
private DiscoverAccountsFragment accountsFragment;
|
||||||
private SearchFragment searchFragment;
|
private SearchFragment searchFragment;
|
||||||
private LocalTimelineFragment localTimelineFragment;
|
|
||||||
private FederatedTimelineFragment federatedTimelineFragment;
|
|
||||||
private ListTimelinesFragment listTimelinesFragment;
|
|
||||||
|
|
||||||
private String accountID;
|
private String accountID;
|
||||||
private Runnable searchDebouncer=this::onSearchChangedDebounced;
|
private Runnable searchDebouncer=this::onSearchChangedDebounced;
|
||||||
|
|
||||||
// private final boolean noFederated = !GlobalUserPreferences.showFederatedTimeline;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -81,22 +74,9 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
tabLayout=view.findViewById(R.id.tabbar);
|
tabLayout=view.findViewById(R.id.tabbar);
|
||||||
pager=view.findViewById(R.id.pager);
|
pager=view.findViewById(R.id.pager);
|
||||||
|
|
||||||
// tabViews=new FrameLayout[noFederated ? 5 : 6];
|
|
||||||
tabViews=new FrameLayout[4];
|
tabViews=new FrameLayout[4];
|
||||||
for(int i=0;i<tabViews.length;i++){
|
for(int i=0;i<tabViews.length;i++){
|
||||||
FrameLayout tabView=new FrameLayout(getActivity());
|
FrameLayout tabView=new FrameLayout(getActivity());
|
||||||
|
|
||||||
/// int switchIndex = noFederated && i > 0 ? i + 1 : i;
|
|
||||||
// tabView.setId(switch(switchIndex){
|
|
||||||
// case 0 -> R.id.discover_local_timeline;
|
|
||||||
// case 1 -> R.id.discover_federated_timeline;
|
|
||||||
// case 2 -> R.id.discover_hashtags;
|
|
||||||
// case 3 -> R.id.discover_posts;
|
|
||||||
// case 4 -> R.id.discover_news;
|
|
||||||
// case 5 -> R.id.discover_users;
|
|
||||||
// default -> throw new IllegalStateException("Unexpected value: "+switchIndex);
|
|
||||||
// });
|
|
||||||
|
|
||||||
tabView.setId(switch(i){
|
tabView.setId(switch(i){
|
||||||
case 0 -> R.id.discover_hashtags;
|
case 0 -> R.id.discover_hashtags;
|
||||||
case 1 -> R.id.discover_posts;
|
case 1 -> R.id.discover_posts;
|
||||||
@@ -104,7 +84,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
case 3 -> R.id.discover_users;
|
case 3 -> R.id.discover_users;
|
||||||
default -> throw new IllegalStateException("Unexpected value: "+i);
|
default -> throw new IllegalStateException("Unexpected value: "+i);
|
||||||
});
|
});
|
||||||
|
|
||||||
tabView.setVisibility(View.GONE);
|
tabView.setVisibility(View.GONE);
|
||||||
view.addView(tabView); // needed so the fragment manager will have somewhere to restore the tab fragment
|
view.addView(tabView); // needed so the fragment manager will have somewhere to restore the tab fragment
|
||||||
tabViews[i]=tabView;
|
tabViews[i]=tabView;
|
||||||
@@ -130,7 +109,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(localTimelineFragment==null || hashtagsFragment==null){
|
if(hashtagsFragment==null){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
args.putBoolean("__is_tab", true);
|
args.putBoolean("__is_tab", true);
|
||||||
@@ -147,27 +126,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
accountsFragment=new DiscoverAccountsFragment();
|
accountsFragment=new DiscoverAccountsFragment();
|
||||||
accountsFragment.setArguments(args);
|
accountsFragment.setArguments(args);
|
||||||
|
|
||||||
localTimelineFragment=new LocalTimelineFragment();
|
|
||||||
localTimelineFragment.setArguments(args);
|
|
||||||
|
|
||||||
// listTimelinesFragment=new ListTimelinesFragment();
|
|
||||||
// listTimelinesFragment.setArguments(args);
|
|
||||||
//
|
|
||||||
// FragmentTransaction transaction = getChildFragmentManager().beginTransaction()
|
|
||||||
// .add(R.id.discover_posts, postsFragment)
|
|
||||||
// .add(R.id.discover_local_timeline, localTimelineFragment)
|
|
||||||
// .add(R.id.discover_hashtags, hashtagsFragment)
|
|
||||||
// .add(R.id.discover_news, newsFragment)
|
|
||||||
// .add(R.id.discover_users, accountsFragment)
|
|
||||||
// .add(R.id.discover_lists, listTimelinesFragment);
|
|
||||||
//
|
|
||||||
// if (!noFederated) {
|
|
||||||
// federatedTimelineFragment=new FederatedTimelineFragment();
|
|
||||||
// federatedTimelineFragment.setArguments(args);
|
|
||||||
// transaction.add(R.id.discover_federated_timeline, federatedTimelineFragment);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// transaction.commit();
|
|
||||||
|
|
||||||
getChildFragmentManager().beginTransaction()
|
getChildFragmentManager().beginTransaction()
|
||||||
.add(R.id.discover_posts, postsFragment)
|
.add(R.id.discover_posts, postsFragment)
|
||||||
@@ -180,21 +138,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
tabLayoutMediator=new TabLayoutMediator(tabLayout, pager, new TabLayoutMediator.TabConfigurationStrategy(){
|
tabLayoutMediator=new TabLayoutMediator(tabLayout, pager, new TabLayoutMediator.TabConfigurationStrategy(){
|
||||||
@Override
|
@Override
|
||||||
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position){
|
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position){
|
||||||
|
|
||||||
// if (noFederated && position > 0) position++;
|
|
||||||
|
|
||||||
// tab.setText(switch(position){
|
|
||||||
// case 0 -> R.string.local_timeline;
|
|
||||||
// case 1 -> R.string.sk_federated_timeline;
|
|
||||||
// case 2 -> R.string.sk_list_timelines;
|
|
||||||
// case 3 -> R.string.hashtags;
|
|
||||||
// case 4 -> R.string.posts;
|
|
||||||
// case 5 -> R.string.news;
|
|
||||||
// case 6 -> R.string.for_you;
|
|
||||||
//
|
|
||||||
// default -> throw new IllegalStateException("Unexpected value: "+position);
|
|
||||||
// });
|
|
||||||
|
|
||||||
tab.setText(switch(position){
|
tab.setText(switch(position){
|
||||||
case 0 -> R.string.hashtags;
|
case 0 -> R.string.hashtags;
|
||||||
case 1 -> R.string.posts;
|
case 1 -> R.string.posts;
|
||||||
@@ -284,12 +227,26 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnTop() {
|
||||||
|
return searchActive ? searchFragment.isOnTop()
|
||||||
|
: ((IsOnTop)getFragmentForPage(pager.getCurrentItem())).isOnTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSelect() {
|
||||||
|
if (isOnTop()) selectSearch();
|
||||||
|
else scrollToTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectSearch() {
|
||||||
|
searchEdit.requestFocus();
|
||||||
|
onSearchEditFocusChanged(searchEdit, true);
|
||||||
|
getActivity().getSystemService(InputMethodManager.class).showSoftInput(searchEdit, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public void loadData(){
|
public void loadData(){
|
||||||
if(hashtagsFragment!=null && !hashtagsFragment.loaded && !hashtagsFragment.dataLoading)
|
if(hashtagsFragment!=null && !hashtagsFragment.loaded && !hashtagsFragment.dataLoading)
|
||||||
hashtagsFragment.loadData();
|
hashtagsFragment.loadData();
|
||||||
|
|
||||||
// if(localTimelineFragment!=null && !localTimelineFragment.loaded && !localTimelineFragment.dataLoading)
|
|
||||||
// localTimelineFragment.loadData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSearchEditFocusChanged(View v, boolean hasFocus){
|
private void onSearchEditFocusChanged(View v, boolean hasFocus){
|
||||||
@@ -324,19 +281,6 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Fragment getFragmentForPage(int page){
|
private Fragment getFragmentForPage(int page){
|
||||||
// if (noFederated && page > 0) page++;
|
|
||||||
|
|
||||||
// return switch(page){
|
|
||||||
// case 0 -> localTimelineFragment;
|
|
||||||
// case 1 -> federatedTimelineFragment;
|
|
||||||
// case 2 -> hashtagsFragment;
|
|
||||||
// case 3 -> postsFragment;
|
|
||||||
// case 4 -> newsFragment;
|
|
||||||
// case 5 -> accountsFragment;
|
|
||||||
// case 6 -> listTimelinesFragment;
|
|
||||||
// default -> throw new IllegalStateException("Unexpected value: "+page);
|
|
||||||
// };
|
|
||||||
|
|
||||||
return switch(page){
|
return switch(page){
|
||||||
case 0 -> hashtagsFragment;
|
case 0 -> hashtagsFragment;
|
||||||
case 1 -> postsFragment;
|
case 1 -> postsFragment;
|
||||||
@@ -398,10 +342,4 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectSearch(){
|
|
||||||
searchEdit.requestFocus();
|
|
||||||
onSearchEditFocusChanged(searchEdit, true);
|
|
||||||
getActivity().getSystemService(InputMethodManager.class).showSoftInput(searchEdit, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,6 @@ public class FederatedTimelineFragment extends StatusListFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
// bannerHelper.maybeAddBanner(contentWrap);
|
bannerHelper.maybeAddBanner(contentWrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.search.GetSearchResults;
|
import org.joinmastodon.android.api.requests.search.GetSearchResults;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
|
import org.joinmastodon.android.fragments.IsOnTop;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Filter;
|
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
import org.joinmastodon.android.model.Hashtag;
|
||||||
import org.joinmastodon.android.model.SearchResult;
|
import org.joinmastodon.android.model.SearchResult;
|
||||||
import org.joinmastodon.android.model.SearchResults;
|
import org.joinmastodon.android.model.SearchResults;
|
||||||
@@ -38,11 +38,10 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.Callback;
|
import me.grishka.appkit.api.Callback;
|
||||||
import me.grishka.appkit.api.ErrorResponse;
|
import me.grishka.appkit.api.ErrorResponse;
|
||||||
import me.grishka.appkit.api.SimpleCallback;
|
|
||||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
public class SearchFragment extends BaseStatusListFragment<SearchResult> implements IsOnTop {
|
||||||
private String currentQuery;
|
private String currentQuery;
|
||||||
private List<StatusDisplayItem> prevDisplayItems;
|
private List<StatusDisplayItem> prevDisplayItems;
|
||||||
private EnumSet<SearchResult.Type> currentFilter=EnumSet.allOf(SearchResult.Type.class);
|
private EnumSet<SearchResult.Type> currentFilter=EnumSet.allOf(SearchResult.Type.class);
|
||||||
@@ -81,7 +80,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
return switch(s.type){
|
return switch(s.type){
|
||||||
case ACCOUNT -> Collections.singletonList(new AccountStatusDisplayItem(s.id, this, s.account));
|
case ACCOUNT -> Collections.singletonList(new AccountStatusDisplayItem(s.id, this, s.account));
|
||||||
case HASHTAG -> Collections.singletonList(new HashtagStatusDisplayItem(s.id, this, s.hashtag));
|
case HASHTAG -> Collections.singletonList(new HashtagStatusDisplayItem(s.id, this, s.hashtag));
|
||||||
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, false, true, null, Filter.FilterContext.PUBLIC);
|
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, false, true, null);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +184,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UiUtils.updateList(prevDisplayItems, displayItems, list, adapter, (i1, i2)->i1.parentID.equals(i2.parentID) && i1.index==i2.index && i1.getType()==i2.getType());
|
UiUtils.updateList(prevDisplayItems, displayItems, list, adapter, (i1, i2)->i1.parentID.equals(i2.parentID) && i1.index==i2.index && i1.getType()==i2.getType());
|
||||||
boolean recent=isInRecentMode();
|
boolean recent=isInRecentMode() && !displayItems.isEmpty();
|
||||||
if(recent!=headerAdapter.isVisible())
|
if(recent!=headerAdapter.isVisible())
|
||||||
headerAdapter.setVisible(recent);
|
headerAdapter.setVisible(recent);
|
||||||
imgLoader.forceUpdateImages();
|
imgLoader.forceUpdateImages();
|
||||||
@@ -311,6 +310,11 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnTop() {
|
||||||
|
return isRecyclerViewOnTop(list);
|
||||||
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface ProgressVisibilityListener{
|
public interface ProgressVisibilityListener{
|
||||||
void onProgressVisibilityChanged(boolean visible);
|
void onProgressVisibilityChanged(boolean visible);
|
||||||
|
|||||||
@@ -96,9 +96,9 @@ public class AccountActivationFragment extends ToolbarFragment{
|
|||||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
@Override
|
||||||
protected void onUpdateToolbar(){
|
protected void onUpdateToolbar(){
|
||||||
// super.onUpdateToolbar();
|
super.onUpdateToolbar();
|
||||||
getToolbar().setBackground(null);
|
getToolbar().setBackground(null);
|
||||||
getToolbar().setElevation(0);
|
getToolbar().setElevation(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,8 +140,8 @@ public class CustomWelcomeFragment extends InstanceCatalogFragment {
|
|||||||
headerView.findViewById(R.id.separator).setVisibility(View.GONE);
|
headerView.findViewById(R.id.separator).setVisibility(View.GONE);
|
||||||
headerView.findViewById(R.id.timestamp).setVisibility(View.GONE);
|
headerView.findViewById(R.id.timestamp).setVisibility(View.GONE);
|
||||||
headerView.findViewById(R.id.unread_indicator).setVisibility(View.GONE);
|
headerView.findViewById(R.id.unread_indicator).setVisibility(View.GONE);
|
||||||
((TextView) headerView.findViewById(R.id.username)).setText(R.string.mo_app_username);
|
((TextView) headerView.findViewById(R.id.username)).setText(R.string.sk_app_username);
|
||||||
((TextView) headerView.findViewById(R.id.name)).setText(R.string.mo_app_name);
|
((TextView) headerView.findViewById(R.id.name)).setText(R.string.sk_app_name);
|
||||||
((ImageView) headerView.findViewById(R.id.avatar)).setImageDrawable(getActivity().getDrawable(R.mipmap.ic_launcher));
|
((ImageView) headerView.findViewById(R.id.avatar)).setImageDrawable(getActivity().getDrawable(R.mipmap.ic_launcher));
|
||||||
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(this);
|
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(this);
|
||||||
|
|
||||||
|
|||||||
@@ -106,13 +106,13 @@ public class InstanceChooserLoginFragment extends InstanceCatalogFragment{
|
|||||||
.execNoAuth("");
|
.execNoAuth("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
@Override
|
||||||
// protected void onUpdateToolbar(){
|
protected void onUpdateToolbar(){
|
||||||
// super.onUpdateToolbar();
|
super.onUpdateToolbar();
|
||||||
// Toolbar toolbar=getToolbar();
|
Toolbar toolbar=getToolbar();
|
||||||
// toolbar.setElevation(0);
|
toolbar.setElevation(0);
|
||||||
// toolbar.setBackground(null);
|
toolbar.setBackground(null);
|
||||||
// }
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected RecyclerView.Adapter getAdapter(){
|
protected RecyclerView.Adapter getAdapter(){
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class InstanceRulesFragment extends ToolbarFragment{
|
|||||||
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||||
adapter.addAdapter(new ItemsAdapter());
|
adapter.addAdapter(new ItemsAdapter());
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorM3SurfaceVariant, 1, 56, 0, DividerItemDecoration.NOT_FIRST));
|
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 56, 0, DividerItemDecoration.NOT_FIRST));
|
||||||
|
|
||||||
btn=view.findViewById(R.id.btn_next);
|
btn=view.findViewById(R.id.btn_next);
|
||||||
btn.setOnClickListener(v->onButtonClick());
|
btn.setOnClickListener(v->onButtonClick());
|
||||||
@@ -90,8 +90,8 @@ public class InstanceRulesFragment extends ToolbarFragment{
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
// setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
// view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
|
||||||
list.addOnScrollListener(onScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, buttonBar, getToolbar()));
|
list.addOnScrollListener(onScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, buttonBar, getToolbar()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,9 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
|||||||
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
||||||
import org.joinmastodon.android.fragments.StatusListFragment;
|
import org.joinmastodon.android.fragments.StatusListFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Filter;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
@@ -133,22 +130,7 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
if(holder.getAbsoluteAdapterPosition()==0)
|
if(holder.getAbsoluteAdapterPosition()==0)
|
||||||
return;
|
return;
|
||||||
outRect.left=V.dp(40);
|
outRect.left=V.dp(40);
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
if(holder instanceof AudioStatusDisplayItem.Holder){
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=imgHolder.getItem().tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
|
||||||
String siblingID;
|
|
||||||
if(holder.getAbsoluteAdapterPosition()<parent.getAdapter().getItemCount()-1){
|
|
||||||
siblingID=displayItems.get(holder.getAbsoluteAdapterPosition()-getMainAdapterOffset()+1).parentID;
|
|
||||||
}else{
|
|
||||||
siblingID=null;
|
|
||||||
}
|
|
||||||
if(tile.startCol>0)
|
|
||||||
outRect.left=0;
|
|
||||||
outRect.left+=V.dp(16);
|
|
||||||
outRect.right=V.dp(16);
|
|
||||||
if(!imgHolder.getItemID().equals(siblingID) || tile.startRow+tile.rowSpan==layout.rowSizes.length)
|
|
||||||
outRect.bottom=V.dp(16);
|
|
||||||
}else if(holder instanceof AudioStatusDisplayItem.Holder){
|
|
||||||
outRect.bottom=V.dp(16);
|
outRect.bottom=V.dp(16);
|
||||||
}else if(holder instanceof LinkCardStatusDisplayItem.Holder){
|
}else if(holder instanceof LinkCardStatusDisplayItem.Holder){
|
||||||
outRect.bottom=V.dp(16);
|
outRect.bottom=V.dp(16);
|
||||||
@@ -167,10 +149,6 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||||
String id=sdiHolder.getItemID();
|
String id=sdiHolder.getItemID();
|
||||||
int height=tmpRect.height();
|
int height=tmpRect.height();
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
||||||
if(imgHolder.getItem().thisTile.startCol+imgHolder.getItem().thisTile.colSpan<imgHolder.getItem().tiledLayout.columnSizes.length)
|
|
||||||
height=0;
|
|
||||||
}
|
|
||||||
if(!(holder instanceof HeaderStatusDisplayItem.Holder) && !(holder instanceof ReblogOrReplyLineStatusDisplayItem.Holder))
|
if(!(holder instanceof HeaderStatusDisplayItem.Holder) && !(holder instanceof ReblogOrReplyLineStatusDisplayItem.Holder))
|
||||||
postsWithKnownNonHeaderHeights.add(id);
|
postsWithKnownNonHeaderHeights.add(id);
|
||||||
knownDisplayItemHeights.put(holder.getAbsoluteAdapterPosition(), height);
|
knownDisplayItemHeights.put(holder.getAbsoluteAdapterPosition(), height);
|
||||||
@@ -237,17 +215,6 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
|||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
|
||||||
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null, Filter.FilterContext.HOME);
|
|
||||||
for(StatusDisplayItem item:items){
|
|
||||||
if(item instanceof ImageStatusDisplayItem isdi){
|
|
||||||
isdi.horizontalInset=V.dp(40+32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void drawDivider(View child, View bottomSibling, RecyclerView.ViewHolder holder, RecyclerView.ViewHolder siblingHolder, RecyclerView parent, Canvas c, Paint paint){
|
protected void drawDivider(View child, View bottomSibling, RecyclerView.ViewHolder holder, RecyclerView.ViewHolder siblingHolder, RecyclerView parent, Canvas c, Paint paint){
|
||||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||||
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package org.joinmastodon.android.model;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.api.RequiredField;
|
|
||||||
import org.parceler.Parcel;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Parcel
|
|
||||||
public class CustomLocalTimeline extends BaseModel{
|
|
||||||
@RequiredField
|
|
||||||
public String domain;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return "Hashtag{"+
|
|
||||||
", url='"+domain+'\''+
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,9 +18,8 @@ public class Filter extends BaseModel{
|
|||||||
@RequiredField
|
@RequiredField
|
||||||
public String id;
|
public String id;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public String title;
|
|
||||||
@RequiredField
|
|
||||||
public String phrase;
|
public String phrase;
|
||||||
|
public String title;
|
||||||
public transient EnumSet<FilterContext> context=EnumSet.noneOf(FilterContext.class);
|
public transient EnumSet<FilterContext> context=EnumSet.noneOf(FilterContext.class);
|
||||||
public Instant expiresAt;
|
public Instant expiresAt;
|
||||||
public boolean irreversible;
|
public boolean irreversible;
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ public class Poll extends BaseModel{
|
|||||||
private boolean expired;
|
private boolean expired;
|
||||||
public boolean multiple;
|
public boolean multiple;
|
||||||
public int votersCount;
|
public int votersCount;
|
||||||
|
public int votesCount;
|
||||||
public boolean voted;
|
public boolean voted;
|
||||||
// @RequiredField
|
@RequiredField
|
||||||
public List<Integer> ownVotes;
|
public List<Integer> ownVotes;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public List<Option> options;
|
public List<Option> options;
|
||||||
@@ -41,10 +42,12 @@ public class Poll extends BaseModel{
|
|||||||
", expired="+expired+
|
", expired="+expired+
|
||||||
", multiple="+multiple+
|
", multiple="+multiple+
|
||||||
", votersCount="+votersCount+
|
", votersCount="+votersCount+
|
||||||
|
", votesCount="+votesCount+
|
||||||
", voted="+voted+
|
", voted="+voted+
|
||||||
", ownVotes="+ownVotes+
|
", ownVotes="+ownVotes+
|
||||||
", options="+options+
|
", options="+options+
|
||||||
", emojis="+emojis+
|
", emojis="+emojis+
|
||||||
|
", selectedOptions="+selectedOptions+
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
|||||||
public Instant createdAt;
|
public Instant createdAt;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public Account account;
|
public Account account;
|
||||||
// @RequiredField
|
// @RequiredField
|
||||||
public String content;
|
public String content;
|
||||||
@RequiredField
|
@RequiredField
|
||||||
public StatusPrivacy visibility;
|
public StatusPrivacy visibility;
|
||||||
@@ -62,7 +62,6 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
|||||||
public transient boolean spoilerRevealed;
|
public transient boolean spoilerRevealed;
|
||||||
public transient boolean textExpanded, textExpandable;
|
public transient boolean textExpanded, textExpandable;
|
||||||
public transient boolean hasGapAfter;
|
public transient boolean hasGapAfter;
|
||||||
public boolean reloadWhenClicked;
|
|
||||||
private transient String strippedText;
|
private transient String strippedText;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import androidx.annotation.StringRes;
|
|||||||
|
|
||||||
import org.joinmastodon.android.BuildConfig;
|
import org.joinmastodon.android.BuildConfig;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.CustomLocalTimelineFragment;
|
|
||||||
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.HomeTimelineFragment;
|
import org.joinmastodon.android.fragments.HomeTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
||||||
@@ -28,7 +27,7 @@ public class TimelineDefinition {
|
|||||||
|
|
||||||
private @Nullable String listId;
|
private @Nullable String listId;
|
||||||
private @Nullable String listTitle;
|
private @Nullable String listTitle;
|
||||||
private @Nullable String domain;
|
|
||||||
private @Nullable String hashtagName;
|
private @Nullable String hashtagName;
|
||||||
|
|
||||||
public static TimelineDefinition ofList(String listId, String listTitle) {
|
public static TimelineDefinition ofList(String listId, String listTitle) {
|
||||||
@@ -48,12 +47,6 @@ public class TimelineDefinition {
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TimelineDefinition ofCustomLocalTimeline(String domain) {
|
|
||||||
TimelineDefinition def = new TimelineDefinition(TimelineType.CUSTOM_LOCAL_TIMELINE);
|
|
||||||
def.domain = domain;
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TimelineDefinition ofHashtag(Hashtag hashtag) {
|
public static TimelineDefinition ofHashtag(Hashtag hashtag) {
|
||||||
return ofHashtag(hashtag.name);
|
return ofHashtag(hashtag.name);
|
||||||
}
|
}
|
||||||
@@ -85,7 +78,6 @@ public class TimelineDefinition {
|
|||||||
case POST_NOTIFICATIONS -> ctx.getString(R.string.sk_timeline_posts);
|
case POST_NOTIFICATIONS -> ctx.getString(R.string.sk_timeline_posts);
|
||||||
case LIST -> listTitle;
|
case LIST -> listTitle;
|
||||||
case HASHTAG -> hashtagName;
|
case HASHTAG -> hashtagName;
|
||||||
case CUSTOM_LOCAL_TIMELINE -> domain;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +89,6 @@ public class TimelineDefinition {
|
|||||||
case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS;
|
case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS;
|
||||||
case LIST -> Icon.LIST;
|
case LIST -> Icon.LIST;
|
||||||
case HASHTAG -> Icon.HASHTAG;
|
case HASHTAG -> Icon.HASHTAG;
|
||||||
case CUSTOM_LOCAL_TIMELINE -> Icon.CUSTOM_LOCAL_TIMELINE;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +100,6 @@ public class TimelineDefinition {
|
|||||||
case LIST -> new ListTimelineFragment();
|
case LIST -> new ListTimelineFragment();
|
||||||
case HASHTAG -> new HashtagTimelineFragment();
|
case HASHTAG -> new HashtagTimelineFragment();
|
||||||
case POST_NOTIFICATIONS -> new NotificationsListFragment();
|
case POST_NOTIFICATIONS -> new NotificationsListFragment();
|
||||||
case CUSTOM_LOCAL_TIMELINE -> new CustomLocalTimelineFragment();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +125,6 @@ public class TimelineDefinition {
|
|||||||
if (type != that.type) return false;
|
if (type != that.type) return false;
|
||||||
if (type == TimelineType.LIST) return Objects.equals(listId, that.listId);
|
if (type == TimelineType.LIST) return Objects.equals(listId, that.listId);
|
||||||
if (type == TimelineType.HASHTAG) return Objects.equals(hashtagName.toLowerCase(), that.hashtagName.toLowerCase());
|
if (type == TimelineType.HASHTAG) return Objects.equals(hashtagName.toLowerCase(), that.hashtagName.toLowerCase());
|
||||||
if (type == TimelineType.CUSTOM_LOCAL_TIMELINE) return Objects.equals(domain.toLowerCase(), that.domain.toLowerCase());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +133,6 @@ public class TimelineDefinition {
|
|||||||
int result = type.ordinal();
|
int result = type.ordinal();
|
||||||
result = 31 * result + (listId != null ? listId.hashCode() : 0);
|
result = 31 * result + (listId != null ? listId.hashCode() : 0);
|
||||||
result = 31 * result + (hashtagName.toLowerCase() != null ? hashtagName.toLowerCase().hashCode() : 0);
|
result = 31 * result + (hashtagName.toLowerCase() != null ? hashtagName.toLowerCase().hashCode() : 0);
|
||||||
result = 31 * result + (domain.toLowerCase() != null ? domain.toLowerCase().hashCode() : 0);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +142,6 @@ public class TimelineDefinition {
|
|||||||
def.listId = listId;
|
def.listId = listId;
|
||||||
def.listTitle = listTitle;
|
def.listTitle = listTitle;
|
||||||
def.hashtagName = hashtagName;
|
def.hashtagName = hashtagName;
|
||||||
def.domain = domain;
|
|
||||||
def.icon = icon == null ? null : Icon.values()[icon.ordinal()];
|
def.icon = icon == null ? null : Icon.values()[icon.ordinal()];
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
@@ -166,13 +152,11 @@ public class TimelineDefinition {
|
|||||||
args.putString("listID", listId);
|
args.putString("listID", listId);
|
||||||
} else if (type == TimelineType.HASHTAG) {
|
} else if (type == TimelineType.HASHTAG) {
|
||||||
args.putString("hashtag", hashtagName);
|
args.putString("hashtag", hashtagName);
|
||||||
} else if (type == TimelineType.CUSTOM_LOCAL_TIMELINE) {
|
|
||||||
args.putString("domain", domain);
|
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG, CUSTOM_LOCAL_TIMELINE }
|
public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG }
|
||||||
|
|
||||||
public enum Icon {
|
public enum Icon {
|
||||||
HEART(R.drawable.ic_fluent_heart_24_regular, R.string.sk_icon_heart),
|
HEART(R.drawable.ic_fluent_heart_24_regular, R.string.sk_icon_heart),
|
||||||
@@ -235,8 +219,7 @@ public class TimelineDefinition {
|
|||||||
FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true),
|
FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true),
|
||||||
POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true),
|
POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true),
|
||||||
LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true),
|
LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true),
|
||||||
HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true),
|
HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true);
|
||||||
CUSTOM_LOCAL_TIMELINE(R.drawable.ic_fluent_people_community_24_regular, R.string.sk_timeline_local, true);
|
|
||||||
|
|
||||||
public final int iconRes, nameRes;
|
public final int iconRes, nameRes;
|
||||||
public final boolean hidden;
|
public final boolean hidden;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.joinmastodon.android.model;
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
public class TranslatedStatus extends BaseModel {
|
public class TranslatedStatus extends BaseModel {
|
||||||
public String content;
|
public String content;
|
||||||
public String detectedSourceLanguage;
|
public String detectedSourceLanguage;
|
||||||
public String provider;
|
public String provider;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
|
|||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
||||||
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package org.joinmastodon.android.ui;
|
package org.joinmastodon.android.ui;
|
||||||
|
|
||||||
import static org.joinmastodon.android.GlobalUserPreferences.recentEmojis;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Animatable;
|
import android.graphics.drawable.Animatable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -13,13 +12,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.squareup.otto.Subscribe;
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
||||||
@@ -27,13 +21,13 @@ import org.joinmastodon.android.model.Emoji;
|
|||||||
import org.joinmastodon.android.model.EmojiCategory;
|
import org.joinmastodon.android.model.EmojiCategory;
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
|
||||||
@@ -46,9 +40,6 @@ import me.grishka.appkit.utils.V;
|
|||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class CustomEmojiPopupKeyboard extends PopupKeyboard{
|
public class CustomEmojiPopupKeyboard extends PopupKeyboard{
|
||||||
//determines how many emoji need to be clicked, before it disappears from the recent emojis
|
|
||||||
private static final int NEW_RECENT_VALUE=15;
|
|
||||||
|
|
||||||
private List<EmojiCategory> emojis;
|
private List<EmojiCategory> emojis;
|
||||||
private UsableRecyclerView list;
|
private UsableRecyclerView list;
|
||||||
private ListImageLoaderWrapper imgLoader;
|
private ListImageLoaderWrapper imgLoader;
|
||||||
@@ -91,17 +82,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
|
|||||||
list.setLayoutManager(lm);
|
list.setLayoutManager(lm);
|
||||||
imgLoader=new ListImageLoaderWrapper(activity, list, new RecyclerViewDelegate(list), null);
|
imgLoader=new ListImageLoaderWrapper(activity, list, new RecyclerViewDelegate(list), null);
|
||||||
|
|
||||||
// inject category with last used emojis
|
|
||||||
if (!recentEmojis.isEmpty()) {
|
|
||||||
List<Emoji> allAvailableEmojis = emojis.stream().flatMap(category -> category.emojis.stream()).collect(Collectors.toList());
|
|
||||||
List<Emoji> recentEmojiList = new ArrayList<>();
|
|
||||||
for (String emojiCode : recentEmojis.keySet().stream().sorted(Comparator.comparingInt(GlobalUserPreferences.recentEmojis::get).reversed()).collect(Collectors.toList())) {
|
|
||||||
Optional<Emoji> element = allAvailableEmojis.stream().filter(e -> e.shortcode.equals(emojiCode)).findFirst();
|
|
||||||
element.ifPresent(recentEmojiList::add);
|
|
||||||
}
|
|
||||||
emojis.add(0, new EmojiCategory(activity.getString(R.string.mo_emoji_recent), recentEmojiList));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(EmojiCategory category:emojis)
|
for(EmojiCategory category:emojis)
|
||||||
adapter.addAdapter(new SingleCategoryAdapter(category));
|
adapter.addAdapter(new SingleCategoryAdapter(category));
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
@@ -120,11 +100,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
|
|||||||
list.setBackgroundColor(UiUtils.getThemeColor(activity, android.R.attr.colorBackground));
|
list.setBackgroundColor(UiUtils.getThemeColor(activity, android.R.attr.colorBackground));
|
||||||
list.setSelector(null);
|
list.setSelector(null);
|
||||||
|
|
||||||
//remove recently used afterwards, it would get duplicated otherwise
|
|
||||||
if (!recentEmojis.isEmpty()) {
|
|
||||||
emojis.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,19 +107,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
|
|||||||
this.listener=listener;
|
this.listener=listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void increaseEmojiCount(Emoji emoji) {
|
|
||||||
Integer usageCount = recentEmojis.get(emoji.shortcode);
|
|
||||||
if (usageCount != null) {
|
|
||||||
recentEmojis.put(emoji.shortcode, usageCount + 1);
|
|
||||||
} else {
|
|
||||||
recentEmojis.put(emoji.shortcode, NEW_RECENT_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
recentEmojis.entrySet().removeIf(e -> e.getValue() <= 0);
|
|
||||||
recentEmojis.replaceAll((k, v) -> v - 1);
|
|
||||||
GlobalUserPreferences.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onEmojiUpdated(EmojiUpdatedEvent ev){
|
public void onEmojiUpdated(EmojiUpdatedEvent ev){
|
||||||
@@ -241,7 +203,6 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(){
|
public void onClick(){
|
||||||
increaseEmojiCount(item);
|
|
||||||
listener.accept(item);
|
listener.accept(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.AlertDialog;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
@@ -31,8 +32,16 @@ public class M3AlertDialogBuilder extends AlertDialog.Builder{
|
|||||||
if(titleID!=0){
|
if(titleID!=0){
|
||||||
View title=alert.findViewById(titleID);
|
View title=alert.findViewById(titleID);
|
||||||
if(title!=null){
|
if(title!=null){
|
||||||
|
int iconID=getContext().getResources().getIdentifier("icon", "id", "android");
|
||||||
|
int alertTitleID=getContext().getResources().getIdentifier("alertTitle", "id", "android");
|
||||||
|
if (alertTitleID != 0 && iconID != 0) {
|
||||||
|
ImageView icon = title.findViewById(iconID);
|
||||||
|
if (icon.getDrawable() != null) {
|
||||||
|
title.findViewById(alertTitleID).setPadding(V.dp(8), 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
int pad=V.dp(24);
|
int pad=V.dp(24);
|
||||||
title.setPadding(pad, pad, pad, V.dp(18));
|
title.setPadding(pad, pad, pad, V.dp(12));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int titleDividerID=getContext().getResources().getIdentifier("titleDividerNoCustom", "id", "android");
|
int titleDividerID=getContext().getResources().getIdentifier("titleDividerNoCustom", "id", "android");
|
||||||
|
|||||||
@@ -11,8 +11,14 @@ import java.util.List;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class PhotoLayoutHelper{
|
public class PhotoLayoutHelper{
|
||||||
|
public static final int MAX_WIDTH=1000;
|
||||||
|
public static final int MAX_HEIGHT=1910;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static TiledLayoutResult processThumbs(int _maxW, int _maxH, List<Attachment> thumbs){
|
public static TiledLayoutResult processThumbs(List<Attachment> thumbs){
|
||||||
|
int _maxW=MAX_WIDTH;
|
||||||
|
int _maxH=MAX_HEIGHT;
|
||||||
|
|
||||||
TiledLayoutResult result=new TiledLayoutResult();
|
TiledLayoutResult result=new TiledLayoutResult();
|
||||||
if(thumbs.size()==1){
|
if(thumbs.size()==1){
|
||||||
Attachment att=thumbs.get(0);
|
Attachment att=thumbs.get(0);
|
||||||
@@ -45,13 +51,8 @@ public class PhotoLayoutHelper{
|
|||||||
float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f;
|
float avgRatio=!ratios.isEmpty() ? sum(ratios)/ratios.size() : 1.0f;
|
||||||
|
|
||||||
float maxW, maxH, marginW=0, marginH=0;
|
float maxW, maxH, marginW=0, marginH=0;
|
||||||
if(_maxW>0){
|
maxW=_maxW;
|
||||||
maxW=_maxW;
|
maxH=_maxH;
|
||||||
maxH=_maxH;
|
|
||||||
}else{
|
|
||||||
maxW=510;
|
|
||||||
maxH=510;
|
|
||||||
}
|
|
||||||
|
|
||||||
float maxRatio=maxW/maxH;
|
float maxRatio=maxW/maxH;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -10,7 +9,6 @@ import android.widget.SeekBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.joinmastodon.android.AudioPlayerService;
|
import org.joinmastodon.android.AudioPlayerService;
|
||||||
import org.joinmastodon.android.MastodonApp;
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
@@ -105,7 +103,6 @@ public class AudioStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}else{
|
}else{
|
||||||
seekBar.setEnabled(false);
|
seekBar.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPlayPauseClick(View v){
|
private void onPlayPauseClick(View v){
|
||||||
@@ -129,10 +126,6 @@ public class AudioStatusDisplayItem extends StatusDisplayItem{
|
|||||||
lastKnownPositionTime=SystemClock.uptimeMillis();
|
lastKnownPositionTime=SystemClock.uptimeMillis();
|
||||||
this.playing=playing;
|
this.playing=playing;
|
||||||
playPauseBtn.setImageResource(playing ? R.drawable.ic_fluent_pause_circle_24_filled : R.drawable.ic_fluent_play_circle_24_filled);
|
playPauseBtn.setImageResource(playing ? R.drawable.ic_fluent_pause_circle_24_filled : R.drawable.ic_fluent_play_circle_24_filled);
|
||||||
playPauseBtn.setContentDescription(MastodonApp.context.getResources().getString(playing ? R.string.pause : R.string.play));
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
playPauseBtn.setTooltipText(playPauseBtn.getContentDescription());
|
|
||||||
}
|
|
||||||
if(!playing){
|
if(!playing){
|
||||||
lastRemainingSeconds=-1;
|
lastRemainingSeconds=-1;
|
||||||
time.setText(formatDuration((int) item.attachment.getDuration()));
|
time.setText(formatDuration((int) item.attachment.getDuration()));
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
editHistory.setVisibility(View.GONE);
|
editHistory.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
String timeStr=TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault()));
|
String timeStr=TIME_FORMATTER.format(item.status.createdAt.atZone(ZoneId.systemDefault()));
|
||||||
|
|
||||||
if (item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)) {
|
if (item.status.application!=null && !TextUtils.isEmpty(item.status.application.name)) {
|
||||||
time.setText(item.parentFragment.getString(R.string.timestamp_via_app, timeStr, ""));
|
time.setText(item.parentFragment.getString(R.string.timestamp_via_app, timeStr, ""));
|
||||||
applicationName.setText(item.status.application.name);
|
applicationName.setText(item.status.application.name);
|
||||||
@@ -134,4 +134,4 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
Nav.go(item.parentFragment.getActivity(), StatusEditHistoryFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), StatusEditHistoryFragment.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ import android.view.ViewGroup;
|
|||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.view.animation.AlphaAnimation;
|
import android.view.animation.AlphaAnimation;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationSet;
|
|
||||||
import android.view.animation.BounceInterpolator;
|
|
||||||
import android.view.animation.RotateAnimation;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -61,8 +58,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private final TextView reply, boost, favorite, bookmark;
|
private final TextView reply, boost, favorite, bookmark;
|
||||||
private final ImageView share;
|
private final ImageView share;
|
||||||
private static final Animation opacityOut, opacityIn;
|
private static final Animation opacityOut, opacityIn;
|
||||||
private static AnimationSet animSet;
|
|
||||||
|
|
||||||
|
|
||||||
private View touchingView = null;
|
private View touchingView = null;
|
||||||
private boolean longClickPerformed = false;
|
private boolean longClickPerformed = false;
|
||||||
@@ -91,15 +86,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
opacityIn = new AlphaAnimation(0.55f, 1);
|
opacityIn = new AlphaAnimation(0.55f, 1);
|
||||||
opacityIn.setDuration(400);
|
opacityIn.setDuration(400);
|
||||||
opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||||
Animation spin = new RotateAnimation(0, 360,
|
|
||||||
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
|
|
||||||
0.5f);
|
|
||||||
|
|
||||||
animSet = new AnimationSet(true);
|
|
||||||
animSet.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
||||||
animSet.addAnimation(spin);
|
|
||||||
animSet.addAnimation(opacityIn);
|
|
||||||
animSet.setDuration(400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
public Holder(Activity activity, ViewGroup parent){
|
||||||
@@ -153,7 +139,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
bookmark.setSelected(item.status.bookmarked);
|
bookmark.setSelected(item.status.bookmarked);
|
||||||
boost.setEnabled(item.status.visibility==StatusPrivacy.PUBLIC || item.status.visibility==StatusPrivacy.UNLISTED || item.status.visibility==StatusPrivacy.LOCAL
|
boost.setEnabled(item.status.visibility==StatusPrivacy.PUBLIC || item.status.visibility==StatusPrivacy.UNLISTED || item.status.visibility==StatusPrivacy.LOCAL
|
||||||
|| (item.status.visibility==StatusPrivacy.PRIVATE && item.status.account.id.equals(AccountSessionManager.getInstance().getAccount(item.accountID).self.id)));
|
|| (item.status.visibility==StatusPrivacy.PRIVATE && item.status.account.id.equals(AccountSessionManager.getInstance().getAccount(item.accountID).self.id)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindButton(TextView btn, long count){
|
private void bindButton(TextView btn, long count){
|
||||||
@@ -191,19 +176,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onReplyClick(View v){
|
private void onReplyClick(View v){
|
||||||
if(item.status.reloadWhenClicked){
|
|
||||||
UiUtils.lookupStatus(v.getContext(),
|
|
||||||
item.status, item.accountID, null,
|
|
||||||
status -> {
|
|
||||||
v.startAnimation(opacityIn);
|
|
||||||
Bundle args=new Bundle();
|
|
||||||
args.putString("account", item.accountID);
|
|
||||||
args.putParcelable("replyTo", Parcels.wrap(status));
|
|
||||||
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
v.startAnimation(opacityIn);
|
v.startAnimation(opacityIn);
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
@@ -227,16 +199,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onBoostClick(View v){
|
private void onBoostClick(View v){
|
||||||
if(item.status.reloadWhenClicked){
|
|
||||||
UiUtils.lookupStatus(v.getContext(),
|
|
||||||
item.status, item.accountID, null,
|
|
||||||
status -> {
|
|
||||||
boost.setSelected(!status.reblogged);
|
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(status, !status.reblogged, null, r->boostConsumer(v, r));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boost.setSelected(!item.status.reblogged);
|
boost.setSelected(!item.status.reblogged);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r));
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r));
|
||||||
}
|
}
|
||||||
@@ -333,30 +295,9 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onFavoriteClick(View v){
|
private void onFavoriteClick(View v){
|
||||||
if(item.status.reloadWhenClicked){
|
|
||||||
UiUtils.lookupStatus(v.getContext(),
|
|
||||||
item.status, item.accountID, null,
|
|
||||||
status -> {
|
|
||||||
favorite.setSelected(!status.favourited);
|
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(status, !status.favourited, r->{
|
|
||||||
if (status.favourited) {
|
|
||||||
v.startAnimation(GlobalUserPreferences.reduceMotion ? opacityIn : animSet);
|
|
||||||
} else {
|
|
||||||
v.startAnimation(opacityIn);
|
|
||||||
}
|
|
||||||
bindButton(favorite, r.favouritesCount);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
favorite.setSelected(!item.status.favourited);
|
favorite.setSelected(!item.status.favourited);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
||||||
if (item.status.favourited) {
|
v.startAnimation(opacityIn);
|
||||||
v.startAnimation(GlobalUserPreferences.reduceMotion ? opacityIn : animSet);
|
|
||||||
} else {
|
|
||||||
v.startAnimation(opacityIn);
|
|
||||||
}
|
|
||||||
bindButton(favorite, r.favouritesCount);
|
bindButton(favorite, r.favouritesCount);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -376,18 +317,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onBookmarkClick(View v){
|
private void onBookmarkClick(View v){
|
||||||
if(item.status.reloadWhenClicked){
|
|
||||||
UiUtils.lookupStatus(v.getContext(),
|
|
||||||
item.status, item.accountID, null,
|
|
||||||
status -> {
|
|
||||||
bookmark.setSelected(!status.bookmarked);
|
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(status, !status.bookmarked, r->{
|
|
||||||
v.startAnimation(opacityIn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bookmark.setSelected(!item.status.bookmarked);
|
bookmark.setSelected(!item.status.bookmarked);
|
||||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
|
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
|
||||||
v.startAnimation(opacityIn);
|
v.startAnimation(opacityIn);
|
||||||
@@ -435,4 +364,4 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.Outline;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewOutlineProvider;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
|
||||||
import org.joinmastodon.android.model.Attachment;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
|
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|
||||||
|
|
||||||
public class GifVStatusDisplayItem extends ImageStatusDisplayItem{
|
|
||||||
public GifVStatusDisplayItem(String parentID, Status status, Attachment attachment, BaseStatusListFragment parentFragment, int index, int totalPhotos, PhotoLayoutHelper.TiledLayoutResult tiledLayout, PhotoLayoutHelper.TiledLayoutResult.Tile thisTile){
|
|
||||||
super(parentID, parentFragment, attachment, status, index, totalPhotos, tiledLayout, thisTile);
|
|
||||||
request=new UrlImageLoaderRequest(attachment.previewUrl, 1000, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type getType(){
|
|
||||||
return Type.GIFV;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Holder extends ImageStatusDisplayItem.Holder<GifVStatusDisplayItem>{
|
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
|
||||||
super(activity, R.layout.display_item_gifv, parent);
|
|
||||||
View play=findViewById(R.id.play_button);
|
|
||||||
play.setOutlineProvider(new ViewOutlineProvider(){
|
|
||||||
@Override
|
|
||||||
public void getOutline(View view, Outline outline){
|
|
||||||
outline.setOval(0, 0, view.getWidth(), view.getHeight());
|
|
||||||
outline.setAlpha(.99f); // fixes shadow rendering
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,9 +9,6 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.ImageSpan;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.SubMenu;
|
import android.view.SubMenu;
|
||||||
@@ -143,7 +140,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
private final TextView name, username, timestamp, extraText, separator;
|
private final TextView name, username, timestamp, extraText, separator;
|
||||||
private final View collapseBtn;
|
private final View collapseBtn;
|
||||||
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, collapseBtnIcon,botIcon;
|
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, collapseBtnIcon;
|
||||||
private final PopupMenu optionsMenu;
|
private final PopupMenu optionsMenu;
|
||||||
private Relationship relationship;
|
private Relationship relationship;
|
||||||
private APIRequest<?> currentRelationshipRequest;
|
private APIRequest<?> currentRelationshipRequest;
|
||||||
@@ -168,7 +165,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
unreadIndicator=findViewById(R.id.unread_indicator);
|
unreadIndicator=findViewById(R.id.unread_indicator);
|
||||||
collapseBtn=findViewById(R.id.collapse_btn);
|
collapseBtn=findViewById(R.id.collapse_btn);
|
||||||
collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
|
collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
|
||||||
botIcon=findViewById(R.id.bot_icon);
|
|
||||||
extraText=findViewById(R.id.extra_text);
|
extraText=findViewById(R.id.extra_text);
|
||||||
avatar.setOnClickListener(this::onAvaClick);
|
avatar.setOnClickListener(this::onAvaClick);
|
||||||
avatar.setOutlineProvider(roundCornersOutline);
|
avatar.setOutlineProvider(roundCornersOutline);
|
||||||
@@ -183,9 +179,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
collapseBtn.setOnClickListener(l -> item.parentFragment.onToggleExpanded(item.status, getItemID()));
|
collapseBtn.setOnClickListener(l -> item.parentFragment.onToggleExpanded(item.status, getItemID()));
|
||||||
|
|
||||||
optionsMenu=new PopupMenu(activity, more);
|
optionsMenu=new PopupMenu(activity, more);
|
||||||
|
|
||||||
optionsMenu.inflate(R.menu.post);
|
optionsMenu.inflate(R.menu.post);
|
||||||
|
|
||||||
optionsMenu.setOnMenuItemClickListener(menuItem->{
|
optionsMenu.setOnMenuItemClickListener(menuItem->{
|
||||||
Account account=item.user;
|
Account account=item.user;
|
||||||
int id=menuItem.getItemId();
|
int id=menuItem.getItemId();
|
||||||
@@ -283,29 +277,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
args.putString("profileDisplayUsername", account.getDisplayUsername());
|
||||||
Nav.go(item.parentFragment.getActivity(), ListTimelinesFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ListTimelinesFragment.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!item.status.filterRevealed){
|
|
||||||
this.itemView.setVisibility(View.GONE);
|
|
||||||
ViewGroup.LayoutParams params = this.itemView.getLayoutParams();
|
|
||||||
params.height = 0;
|
|
||||||
params.width = 0;
|
|
||||||
this.itemView.setLayoutParams(params);
|
|
||||||
// item.parentFragment.notifyItemsChanged(this.getAbsoluteAdapterPosition());
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
UiUtils.enablePopupMenuIcons(activity, optionsMenu);
|
UiUtils.enablePopupMenuIcons(activity, optionsMenu);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setFilteredShown(){
|
|
||||||
// this.itemView.setVisibility(View.VISIBLE);
|
|
||||||
// params = this.itemView.getLayoutParams();
|
|
||||||
// params.height = 0;
|
|
||||||
// params.width = 0;
|
|
||||||
// this.itemView.setLayoutParams(params);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private void populateAccountsMenu(Menu menu) {
|
private void populateAccountsMenu(Menu menu) {
|
||||||
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
|
||||||
sessions.stream().filter(s -> !s.getID().equals(item.accountID)).forEach(s -> {
|
sessions.stream().filter(s -> !s.getID().equals(item.accountID)).forEach(s -> {
|
||||||
@@ -321,8 +297,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
public void onBind(HeaderStatusDisplayItem item){
|
public void onBind(HeaderStatusDisplayItem item){
|
||||||
name.setText(item.parsedName);
|
name.setText(item.parsedName);
|
||||||
username.setText('@'+item.user.acct);
|
username.setText('@'+item.user.acct);
|
||||||
botIcon.setVisibility(item.user.bot ? View.VISIBLE : View.GONE);
|
|
||||||
botIcon.setColorFilter(username.getCurrentTextColor());
|
|
||||||
separator.setVisibility(View.VISIBLE);
|
separator.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
if (item.scheduledStatus!=null)
|
if (item.scheduledStatus!=null)
|
||||||
@@ -441,14 +415,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
if(item.status.reloadWhenClicked){
|
|
||||||
UiUtils.lookupAccount(v.getContext(), item.status.account, item.accountID, null, account -> {
|
|
||||||
args.putString("account", item.accountID);
|
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(account));
|
|
||||||
Nav.go(item.parentFragment.getActivity(), ProfileFragment.class, args);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(item.user));
|
args.putParcelable("profileAccount", Parcels.wrap(item.user));
|
||||||
Nav.go(item.parentFragment.getActivity(), ProfileFragment.class, args);
|
Nav.go(item.parentFragment.getActivity(), ProfileFragment.class, args);
|
||||||
|
|||||||
@@ -1,244 +0,0 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.animation.AnimatorSet;
|
|
||||||
import android.animation.ObjectAnimator;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
|
||||||
import org.joinmastodon.android.R;
|
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
|
||||||
import org.joinmastodon.android.model.Attachment;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
|
||||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
|
||||||
import org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout;
|
|
||||||
|
|
||||||
import androidx.annotation.LayoutRes;
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
|
||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
|
||||||
|
|
||||||
public abstract class ImageStatusDisplayItem extends StatusDisplayItem{
|
|
||||||
public final int index;
|
|
||||||
public final int totalPhotos;
|
|
||||||
protected Attachment attachment;
|
|
||||||
protected ImageLoaderRequest request;
|
|
||||||
public final Status status;
|
|
||||||
public final PhotoLayoutHelper.TiledLayoutResult tiledLayout;
|
|
||||||
public final PhotoLayoutHelper.TiledLayoutResult.Tile thisTile;
|
|
||||||
public int horizontalInset;
|
|
||||||
|
|
||||||
public ImageStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Attachment photo, Status status, int index, int totalPhotos, PhotoLayoutHelper.TiledLayoutResult tiledLayout, PhotoLayoutHelper.TiledLayoutResult.Tile thisTile){
|
|
||||||
super(parentID, parentFragment);
|
|
||||||
this.attachment=photo;
|
|
||||||
this.status=status;
|
|
||||||
this.index=index;
|
|
||||||
this.totalPhotos=totalPhotos;
|
|
||||||
this.tiledLayout=tiledLayout;
|
|
||||||
this.thisTile=thisTile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getImageCount(){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImageLoaderRequest getImageRequest(int index){
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static abstract class Holder<T extends ImageStatusDisplayItem> extends StatusDisplayItem.Holder<T> implements ImageLoaderViewHolder{
|
|
||||||
public final ImageView photo;
|
|
||||||
private ImageAttachmentFrameLayout layout;
|
|
||||||
private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable();
|
|
||||||
private boolean didClear;
|
|
||||||
|
|
||||||
private AnimatorSet currentAnim;
|
|
||||||
private final FrameLayout altTextWrapper;
|
|
||||||
private final TextView altTextButton;
|
|
||||||
private final ImageView noAltTextButton;
|
|
||||||
private final View altTextScroller;
|
|
||||||
private final ImageButton altTextClose;
|
|
||||||
private final TextView altText, noAltText;
|
|
||||||
|
|
||||||
private View altOrNoAltButton;
|
|
||||||
private boolean altTextShown;
|
|
||||||
|
|
||||||
public Holder(Activity activity, @LayoutRes int layout, ViewGroup parent){
|
|
||||||
super(activity, layout, parent);
|
|
||||||
photo=findViewById(R.id.photo);
|
|
||||||
photo.setOnClickListener(this::onViewClick);
|
|
||||||
this.layout=(ImageAttachmentFrameLayout)itemView;
|
|
||||||
|
|
||||||
altTextWrapper=findViewById(R.id.alt_text_wrapper);
|
|
||||||
altTextButton=findViewById(R.id.alt_button);
|
|
||||||
noAltTextButton=findViewById(R.id.no_alt_button);
|
|
||||||
altTextScroller=findViewById(R.id.alt_text_scroller);
|
|
||||||
altTextClose=findViewById(R.id.alt_text_close);
|
|
||||||
altText=findViewById(R.id.alt_text);
|
|
||||||
noAltText=findViewById(R.id.no_alt_text);
|
|
||||||
|
|
||||||
altTextButton.setOnClickListener(this::onShowHideClick);
|
|
||||||
noAltTextButton.setOnClickListener(this::onShowHideClick);
|
|
||||||
altTextClose.setOnClickListener(this::onShowHideClick);
|
|
||||||
// altTextScroller.setNestedScrollingEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBind(ImageStatusDisplayItem item){
|
|
||||||
layout.setLayout(item.tiledLayout, item.thisTile, item.horizontalInset);
|
|
||||||
crossfadeDrawable.setSize(item.attachment.getWidth(), item.attachment.getHeight());
|
|
||||||
crossfadeDrawable.setBlurhashDrawable(item.attachment.blurhashPlaceholder);
|
|
||||||
crossfadeDrawable.setCrossfadeAlpha(item.status.spoilerRevealed ? 0f : 1f);
|
|
||||||
photo.setImageDrawable(null);
|
|
||||||
photo.setImageDrawable(crossfadeDrawable);
|
|
||||||
photo.setContentDescription(TextUtils.isEmpty(item.attachment.description) ? item.parentFragment.getString(R.string.media_no_description) : item.attachment.description);
|
|
||||||
didClear=false;
|
|
||||||
|
|
||||||
if (currentAnim != null) currentAnim.cancel();
|
|
||||||
|
|
||||||
boolean altTextMissing = TextUtils.isEmpty(item.attachment.description);
|
|
||||||
altOrNoAltButton = altTextMissing ? noAltTextButton : altTextButton;
|
|
||||||
altTextShown=false;
|
|
||||||
|
|
||||||
altTextScroller.setVisibility(View.GONE);
|
|
||||||
altTextClose.setVisibility(View.GONE);
|
|
||||||
altTextButton.setVisibility(View.VISIBLE);
|
|
||||||
noAltTextButton.setVisibility(View.VISIBLE);
|
|
||||||
altTextButton.setAlpha(1f);
|
|
||||||
noAltTextButton.setAlpha(1f);
|
|
||||||
altTextWrapper.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
if (altTextMissing){
|
|
||||||
if (GlobalUserPreferences.showNoAltIndicator) {
|
|
||||||
noAltTextButton.setVisibility(View.VISIBLE);
|
|
||||||
noAltText.setVisibility(View.VISIBLE);
|
|
||||||
altTextWrapper.setBackgroundResource(R.drawable.bg_image_no_alt_overlay);
|
|
||||||
altTextButton.setVisibility(View.GONE);
|
|
||||||
altText.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
altTextWrapper.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
if (GlobalUserPreferences.showAltIndicator) {
|
|
||||||
noAltTextButton.setVisibility(View.GONE);
|
|
||||||
noAltText.setVisibility(View.GONE);
|
|
||||||
altTextWrapper.setBackgroundResource(R.drawable.bg_image_alt_overlay);
|
|
||||||
altTextButton.setVisibility(View.VISIBLE);
|
|
||||||
altTextButton.setText(R.string.sk_alt_button);
|
|
||||||
altText.setVisibility(View.VISIBLE);
|
|
||||||
altText.setText(item.attachment.description);
|
|
||||||
altText.setPadding(0, 0, 0, 0);
|
|
||||||
} else {
|
|
||||||
altTextWrapper.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onShowHideClick(View v){
|
|
||||||
boolean show=v.getId()==R.id.alt_button || v.getId()==R.id.no_alt_button;
|
|
||||||
|
|
||||||
if(altTextShown==show)
|
|
||||||
return;
|
|
||||||
if(currentAnim!=null)
|
|
||||||
currentAnim.cancel();
|
|
||||||
|
|
||||||
altTextShown=show;
|
|
||||||
if(show){
|
|
||||||
altTextScroller.setVisibility(View.VISIBLE);
|
|
||||||
altTextClose.setVisibility(View.VISIBLE);
|
|
||||||
}else{
|
|
||||||
altOrNoAltButton.setVisibility(View.VISIBLE);
|
|
||||||
// Hide these views temporarily so FrameLayout measures correctly
|
|
||||||
altTextScroller.setVisibility(View.GONE);
|
|
||||||
altTextClose.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the current size...
|
|
||||||
int prevLeft=altTextWrapper.getLeft();
|
|
||||||
int prevRight=altTextWrapper.getRight();
|
|
||||||
int prevTop=altTextWrapper.getTop();
|
|
||||||
altTextWrapper.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
|
||||||
@Override
|
|
||||||
public boolean onPreDraw(){
|
|
||||||
altTextWrapper.getViewTreeObserver().removeOnPreDrawListener(this);
|
|
||||||
|
|
||||||
// ...and this is after the layout pass, right now the FrameLayout has its final size, but we animate that change
|
|
||||||
if(!show){
|
|
||||||
// Show these views again so they're visible for the duration of the animation.
|
|
||||||
// No one would notice they were missing during measure/layout.
|
|
||||||
altTextScroller.setVisibility(View.VISIBLE);
|
|
||||||
altTextClose.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
AnimatorSet set=new AnimatorSet();
|
|
||||||
set.playTogether(
|
|
||||||
ObjectAnimator.ofInt(altTextWrapper, "left", prevLeft, altTextWrapper.getLeft()),
|
|
||||||
ObjectAnimator.ofInt(altTextWrapper, "right", prevRight, altTextWrapper.getRight()),
|
|
||||||
ObjectAnimator.ofInt(altTextWrapper, "top", prevTop, altTextWrapper.getTop()),
|
|
||||||
ObjectAnimator.ofFloat(altOrNoAltButton, View.ALPHA, show ? 1f : 0f, show ? 0f : 1f),
|
|
||||||
ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f),
|
|
||||||
ObjectAnimator.ofFloat(altTextClose, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f)
|
|
||||||
);
|
|
||||||
set.setDuration(300);
|
|
||||||
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
||||||
set.addListener(new AnimatorListenerAdapter(){
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation){
|
|
||||||
if(show){
|
|
||||||
altOrNoAltButton.setVisibility(View.GONE);
|
|
||||||
}else{
|
|
||||||
altTextScroller.setVisibility(View.GONE);
|
|
||||||
altTextClose.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
currentAnim=null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
set.start();
|
|
||||||
currentAnim=set;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setImage(int index, Drawable drawable){
|
|
||||||
crossfadeDrawable.setImageDrawable(drawable);
|
|
||||||
if(didClear && item.status.spoilerRevealed)
|
|
||||||
crossfadeDrawable.animateAlpha(0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearImage(int index){
|
|
||||||
crossfadeDrawable.setCrossfadeAlpha(1f);
|
|
||||||
crossfadeDrawable.setImageDrawable(null);
|
|
||||||
didClear=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onViewClick(View v){
|
|
||||||
if(!item.status.spoilerRevealed){
|
|
||||||
item.parentFragment.onRevealSpoilerClick(this);
|
|
||||||
}else if(item.parentFragment instanceof PhotoViewerHost){
|
|
||||||
Status contentStatus=item.status.reblog!=null ? item.status.reblog : item.status;
|
|
||||||
((PhotoViewerHost) item.parentFragment).openPhotoViewer(item.parentID, item.status, contentStatus.mediaAttachments.indexOf(item.attachment));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRevealed(boolean revealed){
|
|
||||||
crossfadeDrawable.animateAlpha(revealed ? 0f : 1f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -73,7 +73,6 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
|
|||||||
|
|
||||||
photo.setImageDrawable(null);
|
photo.setImageDrawable(null);
|
||||||
if(item.imgRequest!=null){
|
if(item.imgRequest!=null){
|
||||||
crossfadeDrawable.setSize(card.width, card.height);
|
|
||||||
if (card.width > 0) {
|
if (card.width > 0) {
|
||||||
// akkoma servers don't provide width and height
|
// akkoma servers don't provide width and height
|
||||||
crossfadeDrawable.setSize(card.width, card.height);
|
crossfadeDrawable.setSize(card.width, card.height);
|
||||||
@@ -105,4 +104,3 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,311 @@
|
|||||||
|
package org.joinmastodon.android.ui.displayitems;
|
||||||
|
|
||||||
|
import static org.joinmastodon.android.ui.utils.MediaAttachmentViewController.altWrapPadding;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
|
import org.joinmastodon.android.model.Attachment;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
||||||
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||||
|
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
|
||||||
|
import org.joinmastodon.android.ui.views.FrameLayoutThatOnlyMeasuresFirstChild;
|
||||||
|
import org.joinmastodon.android.ui.views.MediaGridLayout;
|
||||||
|
import org.joinmastodon.android.utils.TypedObjectPool;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
|
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||||
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
|
|
||||||
|
public class MediaGridStatusDisplayItem extends StatusDisplayItem{
|
||||||
|
private static final String TAG="MediaGridDisplayItem";
|
||||||
|
|
||||||
|
private final PhotoLayoutHelper.TiledLayoutResult tiledLayout;
|
||||||
|
private final TypedObjectPool<GridItemType, MediaAttachmentViewController> viewPool;
|
||||||
|
private final List<Attachment> attachments;
|
||||||
|
private final ArrayList<ImageLoaderRequest> requests=new ArrayList<>();
|
||||||
|
public final Status status;
|
||||||
|
|
||||||
|
public MediaGridStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, PhotoLayoutHelper.TiledLayoutResult tiledLayout, List<Attachment> attachments, Status status){
|
||||||
|
super(parentID, parentFragment);
|
||||||
|
this.tiledLayout=tiledLayout;
|
||||||
|
this.viewPool=parentFragment.getAttachmentViewsPool();
|
||||||
|
this.attachments=attachments;
|
||||||
|
this.status=status;
|
||||||
|
for(Attachment att:attachments){
|
||||||
|
requests.add(new UrlImageLoaderRequest(switch(att.type){
|
||||||
|
case IMAGE -> att.url;
|
||||||
|
case VIDEO, GIFV -> att.previewUrl;
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: "+att.type);
|
||||||
|
}, 1000, 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType(){
|
||||||
|
return Type.MEDIA_GRID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getImageCount(){
|
||||||
|
return requests.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageLoaderRequest getImageRequest(int index){
|
||||||
|
return requests.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GridItemType{
|
||||||
|
PHOTO,
|
||||||
|
VIDEO,
|
||||||
|
GIFV
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Holder extends StatusDisplayItem.Holder<MediaGridStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
|
private final FrameLayout wrapper;
|
||||||
|
private final MediaGridLayout layout;
|
||||||
|
private final View.OnClickListener clickListener=this::onViewClick, altTextClickListener=this::onAltTextClick;
|
||||||
|
private final ArrayList<MediaAttachmentViewController> controllers=new ArrayList<>();
|
||||||
|
|
||||||
|
private final FrameLayout altTextWrapper;
|
||||||
|
private final TextView altTextButton;
|
||||||
|
private final ImageView noAltTextButton;
|
||||||
|
private final View altTextScroller;
|
||||||
|
private final ImageButton altTextClose;
|
||||||
|
private final TextView altText, noAltText;
|
||||||
|
|
||||||
|
private int altTextIndex=-1;
|
||||||
|
private Animator altTextAnimator;
|
||||||
|
|
||||||
|
public Holder(Activity activity, ViewGroup parent){
|
||||||
|
super(new FrameLayoutThatOnlyMeasuresFirstChild(activity));
|
||||||
|
wrapper=(FrameLayout)itemView;
|
||||||
|
layout=new MediaGridLayout(activity);
|
||||||
|
wrapper.addView(layout);
|
||||||
|
|
||||||
|
activity.getLayoutInflater().inflate(R.layout.overlay_image_alt_text, wrapper);
|
||||||
|
altTextWrapper=findViewById(R.id.alt_text_wrapper);
|
||||||
|
altTextButton=findViewById(R.id.alt_button);
|
||||||
|
noAltTextButton=findViewById(R.id.no_alt_button);
|
||||||
|
altTextScroller=findViewById(R.id.alt_text_scroller);
|
||||||
|
altTextClose=findViewById(R.id.alt_text_close);
|
||||||
|
altText=findViewById(R.id.alt_text);
|
||||||
|
noAltText=findViewById(R.id.no_alt_text);
|
||||||
|
altTextClose.setOnClickListener(this::onAltTextCloseClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBind(MediaGridStatusDisplayItem item){
|
||||||
|
if(altTextAnimator!=null)
|
||||||
|
altTextAnimator.cancel();
|
||||||
|
|
||||||
|
layout.setTiledLayout(item.tiledLayout);
|
||||||
|
for(MediaAttachmentViewController c:controllers){
|
||||||
|
item.viewPool.reuse(c.type, c);
|
||||||
|
}
|
||||||
|
layout.removeAllViews();
|
||||||
|
controllers.clear();
|
||||||
|
int i=0;
|
||||||
|
for(Attachment att:item.attachments){
|
||||||
|
MediaAttachmentViewController c=item.viewPool.obtain(switch(att.type){
|
||||||
|
case IMAGE -> GridItemType.PHOTO;
|
||||||
|
case VIDEO -> GridItemType.VIDEO;
|
||||||
|
case GIFV -> GridItemType.GIFV;
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: "+att.type);
|
||||||
|
});
|
||||||
|
if(c.view.getLayoutParams()==null)
|
||||||
|
c.view.setLayoutParams(new MediaGridLayout.LayoutParams(item.tiledLayout.tiles[i]));
|
||||||
|
else
|
||||||
|
((MediaGridLayout.LayoutParams) c.view.getLayoutParams()).tile=item.tiledLayout.tiles[i];
|
||||||
|
layout.addView(c.view);
|
||||||
|
c.view.setOnClickListener(clickListener);
|
||||||
|
c.view.setTag(i);
|
||||||
|
if(c.btnsWrap!=null){
|
||||||
|
c.btnsWrap.setOnClickListener(altTextClickListener);
|
||||||
|
c.btnsWrap.setTag(i);
|
||||||
|
c.btnsWrap.setAlpha(1f);
|
||||||
|
}
|
||||||
|
controllers.add(c);
|
||||||
|
c.bind(att, item.status);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
altTextButton.setVisibility(View.VISIBLE);
|
||||||
|
noAltTextButton.setVisibility(View.VISIBLE);
|
||||||
|
altTextWrapper.setVisibility(View.GONE);
|
||||||
|
altTextIndex=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setImage(int index, Drawable drawable){
|
||||||
|
controllers.get(index).setImage(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearImage(int index){
|
||||||
|
controllers.get(index).clearImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onViewClick(View v){
|
||||||
|
int index=(Integer)v.getTag();
|
||||||
|
if(!item.status.spoilerRevealed){
|
||||||
|
item.parentFragment.onRevealSpoilerClick(this);
|
||||||
|
}else if(item.parentFragment instanceof PhotoViewerHost){
|
||||||
|
((PhotoViewerHost) item.parentFragment).openPhotoViewer(item.parentID, item.status, index, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAltTextClick(View v){
|
||||||
|
if(altTextAnimator!=null)
|
||||||
|
altTextAnimator.cancel();
|
||||||
|
v.setVisibility(View.INVISIBLE);
|
||||||
|
int index=(Integer)v.getTag();
|
||||||
|
altTextIndex=index;
|
||||||
|
Attachment att=item.attachments.get(index);
|
||||||
|
boolean hasAltText = !TextUtils.isEmpty(att.description);
|
||||||
|
altTextButton.setVisibility(hasAltText && GlobalUserPreferences.showAltIndicator ? View.VISIBLE : View.GONE);
|
||||||
|
noAltTextButton.setVisibility(!hasAltText && GlobalUserPreferences.showNoAltIndicator ? View.VISIBLE : View.GONE);
|
||||||
|
altText.setVisibility(hasAltText && GlobalUserPreferences.showAltIndicator ? View.VISIBLE : View.GONE);
|
||||||
|
noAltText.setVisibility(!hasAltText && GlobalUserPreferences.showNoAltIndicator ? View.VISIBLE : View.GONE);
|
||||||
|
altText.setText(att.description);
|
||||||
|
altTextWrapper.setVisibility(View.VISIBLE);
|
||||||
|
altTextWrapper.setBackgroundResource(hasAltText ? R.drawable.bg_image_alt_overlay : R.drawable.bg_image_no_alt_overlay);
|
||||||
|
altTextWrapper.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw(){
|
||||||
|
altTextWrapper.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
|
|
||||||
|
int[] loc={0, 0};
|
||||||
|
v.getLocationInWindow(loc);
|
||||||
|
int btnL=loc[0], btnT=loc[1];
|
||||||
|
wrapper.getLocationInWindow(loc);
|
||||||
|
btnL-=loc[0];
|
||||||
|
btnT-=loc[1];
|
||||||
|
|
||||||
|
ArrayList<Animator> anims=new ArrayList<>();
|
||||||
|
anims.add(ObjectAnimator.ofFloat(altTextButton, View.ALPHA, 1, 0));
|
||||||
|
anims.add(ObjectAnimator.ofFloat(noAltTextButton, View.ALPHA, 1, 0));
|
||||||
|
anims.add(ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, 0, 1));
|
||||||
|
anims.add(ObjectAnimator.ofFloat(altTextClose, View.ALPHA, 0, 1));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "left", btnL+altWrapPadding[0], altTextWrapper.getLeft()));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "top", btnT+altWrapPadding[1], altTextWrapper.getTop()));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "right", btnL+v.getWidth()-altWrapPadding[2], altTextWrapper.getRight()));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "bottom", btnT+v.getHeight()-altWrapPadding[3], altTextWrapper.getBottom()));
|
||||||
|
for(Animator a:anims)
|
||||||
|
a.setDuration(300);
|
||||||
|
|
||||||
|
for(MediaAttachmentViewController c:controllers){
|
||||||
|
if(c.btnsWrap!=null && c.btnsWrap!=v){
|
||||||
|
anims.add(ObjectAnimator.ofFloat(c.btnsWrap, View.ALPHA, 1, 0).setDuration(150));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatorSet set=new AnimatorSet();
|
||||||
|
set.playTogether(anims);
|
||||||
|
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||||
|
set.addListener(new AnimatorListenerAdapter(){
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation){
|
||||||
|
altTextAnimator=null;
|
||||||
|
for(MediaAttachmentViewController c:controllers){
|
||||||
|
if(c.btnsWrap!=null){
|
||||||
|
c.btnsWrap.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
altTextAnimator=set;
|
||||||
|
set.start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAltTextCloseClick(View v){
|
||||||
|
if(altTextAnimator!=null)
|
||||||
|
altTextAnimator.cancel();
|
||||||
|
|
||||||
|
View btn=controllers.get(altTextIndex).btnsWrap;
|
||||||
|
for(MediaAttachmentViewController c:controllers){
|
||||||
|
if(c.btnsWrap!=null && c.btnsWrap!=btn) {
|
||||||
|
c.btnsWrap.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] loc={0, 0};
|
||||||
|
btn.getLocationInWindow(loc);
|
||||||
|
int btnL=loc[0], btnT=loc[1];
|
||||||
|
wrapper.getLocationInWindow(loc);
|
||||||
|
btnL-=loc[0];
|
||||||
|
btnT-=loc[1];
|
||||||
|
|
||||||
|
ArrayList<Animator> anims=new ArrayList<>();
|
||||||
|
anims.add(ObjectAnimator.ofFloat(altTextButton, View.ALPHA, 1));
|
||||||
|
anims.add(ObjectAnimator.ofFloat(noAltTextButton, View.ALPHA, 1));
|
||||||
|
anims.add(ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, 0));
|
||||||
|
anims.add(ObjectAnimator.ofFloat(altTextClose, View.ALPHA, 0));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "left", btnL+altWrapPadding[0]));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "top", btnT+altWrapPadding[1]));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "right", btnL+btn.getWidth()-altWrapPadding[2]));
|
||||||
|
anims.add(ObjectAnimator.ofInt(altTextWrapper, "bottom", btnT+btn.getHeight()-altWrapPadding[3]));
|
||||||
|
for(Animator a:anims)
|
||||||
|
a.setDuration(300);
|
||||||
|
|
||||||
|
for(MediaAttachmentViewController c:controllers){
|
||||||
|
// if(c.btnsWrap!=null && c.btnsWrap!=btn){
|
||||||
|
anims.add(ObjectAnimator.ofFloat(c.btnsWrap, View.ALPHA, 1).setDuration(150));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatorSet set=new AnimatorSet();
|
||||||
|
set.playTogether(anims);
|
||||||
|
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
||||||
|
set.addListener(new AnimatorListenerAdapter(){
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation){
|
||||||
|
altTextAnimator=null;
|
||||||
|
altTextWrapper.setVisibility(View.GONE);
|
||||||
|
btn.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
altTextAnimator=set;
|
||||||
|
set.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRevealed(boolean revealed){
|
||||||
|
for(MediaAttachmentViewController c:controllers){
|
||||||
|
c.setRevealed(revealed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaAttachmentViewController getViewController(int index){
|
||||||
|
return controllers.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClipChildren(boolean clip){
|
||||||
|
layout.setClipChildren(clip);
|
||||||
|
wrapper.setClipChildren(clip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.animation.AnimatorSet;
|
|
||||||
import android.animation.ObjectAnimator;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ScrollView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
|
||||||
import org.joinmastodon.android.R;
|
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
|
||||||
import org.joinmastodon.android.model.Attachment;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
|
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|
||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
|
||||||
import me.grishka.appkit.utils.V;
|
|
||||||
|
|
||||||
public class PhotoStatusDisplayItem extends ImageStatusDisplayItem{
|
|
||||||
public PhotoStatusDisplayItem(String parentID, Status status, Attachment photo, BaseStatusListFragment parentFragment, int index, int totalPhotos, PhotoLayoutHelper.TiledLayoutResult tiledLayout, PhotoLayoutHelper.TiledLayoutResult.Tile thisTile){
|
|
||||||
super(parentID, parentFragment, photo, status, index, totalPhotos, tiledLayout, thisTile);
|
|
||||||
request=new UrlImageLoaderRequest(photo.url, 1000, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type getType(){
|
|
||||||
return Type.PHOTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Holder extends ImageStatusDisplayItem.Holder<PhotoStatusDisplayItem> {
|
|
||||||
public Holder(Activity activity, ViewGroup parent) {
|
|
||||||
super(activity, R.layout.display_item_photo, parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,8 +35,9 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
|||||||
text=HtmlParser.parseCustomEmoji(option.title, poll.emojis);
|
text=HtmlParser.parseCustomEmoji(option.title, poll.emojis);
|
||||||
emojiHelper.setText(text);
|
emojiHelper.setText(text);
|
||||||
showResults=poll.isExpired() || poll.voted;
|
showResults=poll.isExpired() || poll.voted;
|
||||||
if(showResults && option.votesCount!=null && poll.votersCount>0){
|
int total=poll.votersCount>0 ? poll.votersCount : poll.votesCount;
|
||||||
votesFraction=(float)option.votesCount/(float)poll.votersCount;
|
if(showResults && option.votesCount!=null && total>0){
|
||||||
|
votesFraction=(float)option.votesCount/(float)total;
|
||||||
int mostVotedCount=0;
|
int mostVotedCount=0;
|
||||||
for(Poll.Option opt:poll.options)
|
for(Poll.Option opt:poll.options)
|
||||||
mostVotedCount=Math.max(mostVotedCount, opt.votesCount);
|
mostVotedCount=Math.max(mostVotedCount, opt.votesCount);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||||
private CharSequence text;
|
private CharSequence text;
|
||||||
@@ -37,6 +38,8 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
private int iconEnd;
|
private int iconEnd;
|
||||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||||
private View.OnClickListener handleClick;
|
private View.OnClickListener handleClick;
|
||||||
|
private boolean isLastLine = true;
|
||||||
|
private int lineNo = 0;
|
||||||
|
|
||||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick){
|
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick){
|
||||||
super(parentID, parentFragment);
|
super(parentID, parentFragment);
|
||||||
@@ -51,6 +54,14 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
updateVisibility(visibility);
|
updateVisibility(visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setIsLastLine(boolean isLastLine) {
|
||||||
|
this.isLastLine = isLastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLineNo(int lineNo) {
|
||||||
|
this.lineNo = lineNo;
|
||||||
|
}
|
||||||
|
|
||||||
public void updateVisibility(StatusPrivacy visibility) {
|
public void updateVisibility(StatusPrivacy visibility) {
|
||||||
this.visibility = visibility;
|
this.visibility = visibility;
|
||||||
this.iconEnd = visibility != null ? switch (visibility) {
|
this.iconEnd = visibility != null ? switch (visibility) {
|
||||||
@@ -78,18 +89,21 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
|
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
private final TextView text;
|
private final TextView text;
|
||||||
|
private final View frame;
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
public Holder(Activity activity, ViewGroup parent){
|
||||||
super(activity, R.layout.display_item_reblog_or_reply_line, parent);
|
super(activity, R.layout.display_item_reblog_or_reply_line, parent);
|
||||||
text=findViewById(R.id.text);
|
text=findViewById(R.id.text);
|
||||||
|
frame=findViewById(R.id.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBind(ReblogOrReplyLineStatusDisplayItem item){
|
public void onBind(ReblogOrReplyLineStatusDisplayItem item){
|
||||||
text.setText(item.text);
|
text.setText(item.text);
|
||||||
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, item.iconEnd, 0);
|
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, item.iconEnd, 0);
|
||||||
if(item.handleClick!=null) text.setOnClickListener(item.handleClick);
|
text.setOnClickListener(item.handleClick);
|
||||||
text.setEnabled(!item.inset);
|
text.setEnabled(!item.inset && item.handleClick != null);
|
||||||
text.setClickable(!item.inset);
|
text.setClickable(!item.inset && item.handleClick != null);
|
||||||
Context ctx = itemView.getContext();
|
Context ctx = itemView.getContext();
|
||||||
int visibilityText = item.visibility != null ? switch (item.visibility) {
|
int visibilityText = item.visibility != null ? switch (item.visibility) {
|
||||||
case PUBLIC -> R.string.visibility_public;
|
case PUBLIC -> R.string.visibility_public;
|
||||||
@@ -100,7 +114,10 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||||||
if (visibilityText != 0) text.setContentDescription(item.text + " (" + ctx.getString(visibilityText) + ")");
|
if (visibilityText != 0) text.setContentDescription(item.text + " (" + ctx.getString(visibilityText) + ")");
|
||||||
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
|
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
|
||||||
UiUtils.fixCompoundDrawableTintOnAndroid6(text);
|
UiUtils.fixCompoundDrawableTintOnAndroid6(text);
|
||||||
|
ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
params.bottomMargin = V.dp(item.isLastLine ? -12 : -18);
|
||||||
|
params.leftMargin = V.dp(13) * item.lineNo;
|
||||||
|
frame.setLayoutParams(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.HomeTabFragment;
|
import org.joinmastodon.android.fragments.HomeTabFragment;
|
||||||
import org.joinmastodon.android.fragments.HomeTimelineFragment;
|
|
||||||
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
import org.joinmastodon.android.fragments.ListTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
@@ -21,7 +19,6 @@ import org.joinmastodon.android.model.Account;
|
|||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Hashtag;
|
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.Poll;
|
import org.joinmastodon.android.model.Poll;
|
||||||
import org.joinmastodon.android.model.ScheduledStatus;
|
import org.joinmastodon.android.model.ScheduledStatus;
|
||||||
@@ -32,11 +29,8 @@ import org.joinmastodon.android.utils.StatusFilterPredicate;
|
|||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
@@ -70,10 +64,7 @@ public abstract class StatusDisplayItem{
|
|||||||
case HEADER -> new HeaderStatusDisplayItem.Holder(activity, parent);
|
case HEADER -> new HeaderStatusDisplayItem.Holder(activity, parent);
|
||||||
case REBLOG_OR_REPLY_LINE -> new ReblogOrReplyLineStatusDisplayItem.Holder(activity, parent);
|
case REBLOG_OR_REPLY_LINE -> new ReblogOrReplyLineStatusDisplayItem.Holder(activity, parent);
|
||||||
case TEXT -> new TextStatusDisplayItem.Holder(activity, parent);
|
case TEXT -> new TextStatusDisplayItem.Holder(activity, parent);
|
||||||
case PHOTO -> new PhotoStatusDisplayItem.Holder(activity, parent);
|
|
||||||
case GIFV -> new GifVStatusDisplayItem.Holder(activity, parent);
|
|
||||||
case AUDIO -> new AudioStatusDisplayItem.Holder(activity, parent);
|
case AUDIO -> new AudioStatusDisplayItem.Holder(activity, parent);
|
||||||
case VIDEO -> new VideoStatusDisplayItem.Holder(activity, parent);
|
|
||||||
case POLL_OPTION -> new PollOptionStatusDisplayItem.Holder(activity, parent);
|
case POLL_OPTION -> new PollOptionStatusDisplayItem.Holder(activity, parent);
|
||||||
case POLL_FOOTER -> new PollFooterStatusDisplayItem.Holder(activity, parent);
|
case POLL_FOOTER -> new PollFooterStatusDisplayItem.Holder(activity, parent);
|
||||||
case CARD -> new LinkCardStatusDisplayItem.Holder(activity, parent);
|
case CARD -> new LinkCardStatusDisplayItem.Holder(activity, parent);
|
||||||
@@ -83,6 +74,7 @@ public abstract class StatusDisplayItem{
|
|||||||
case HASHTAG -> new HashtagStatusDisplayItem.Holder(activity, parent);
|
case HASHTAG -> new HashtagStatusDisplayItem.Holder(activity, parent);
|
||||||
case GAP -> new GapStatusDisplayItem.Holder(activity, parent);
|
case GAP -> new GapStatusDisplayItem.Holder(activity, parent);
|
||||||
case EXTENDED_FOOTER -> new ExtendedFooterStatusDisplayItem.Holder(activity, parent);
|
case EXTENDED_FOOTER -> new ExtendedFooterStatusDisplayItem.Holder(activity, parent);
|
||||||
|
case MEDIA_GRID -> new MediaGridStatusDisplayItem.Holder(activity, parent);
|
||||||
case WARNING -> new WarningFilteredStatusDisplayItem.Holder(activity, parent);
|
case WARNING -> new WarningFilteredStatusDisplayItem.Holder(activity, parent);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -100,10 +92,6 @@ public abstract class StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate, Filter.FilterContext filterContext){
|
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate, Filter.FilterContext filterContext){
|
||||||
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, disableTranslate, filterContext, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate, Filter.FilterContext filterContext, StatusDisplayItem titleItem){
|
|
||||||
String parentID=parentObject.getID();
|
String parentID=parentObject.getID();
|
||||||
ArrayList<StatusDisplayItem> items=new ArrayList<>();
|
ArrayList<StatusDisplayItem> items=new ArrayList<>();
|
||||||
|
|
||||||
@@ -126,18 +114,10 @@ public abstract class StatusDisplayItem{
|
|||||||
args.putParcelable("profileAccount", Parcels.wrap(status.account));
|
args.putParcelable("profileAccount", Parcels.wrap(status.account));
|
||||||
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
|
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
|
||||||
}));
|
}));
|
||||||
}else if(status.inReplyToAccountId!=null && knownAccounts.containsKey(status.inReplyToAccountId)){
|
} else if (!(status.tags.isEmpty() ||
|
||||||
Account account=Objects.requireNonNull(knownAccounts.get(status.inReplyToAccountId));
|
fragment instanceof HashtagTimelineFragment ||
|
||||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.in_reply_to, account.displayName), account.emojis, R.drawable.ic_fluent_arrow_reply_20_filled, null, i->{
|
fragment instanceof ListTimelineFragment
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(account));
|
) && fragment.getParentFragment() instanceof HomeTabFragment home) {
|
||||||
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
|
|
||||||
}));
|
|
||||||
} else if (
|
|
||||||
!(status.tags.isEmpty() ||
|
|
||||||
fragment instanceof HashtagTimelineFragment ||
|
|
||||||
fragment instanceof ListTimelineFragment
|
|
||||||
) && fragment.getParentFragment() instanceof HomeTabFragment home
|
|
||||||
) {
|
|
||||||
home.getHashtags().stream()
|
home.getHashtags().stream()
|
||||||
.filter(followed -> status.tags.stream()
|
.filter(followed -> status.tags.stream()
|
||||||
.anyMatch(hashtag -> followed.name.equalsIgnoreCase(hashtag.name)))
|
.anyMatch(hashtag -> followed.name.equalsIgnoreCase(hashtag.name)))
|
||||||
@@ -153,28 +133,41 @@ public abstract class StatusDisplayItem{
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(statusForContent.inReplyToAccountId!=null){
|
||||||
|
Account account = knownAccounts.get(statusForContent.inReplyToAccountId);
|
||||||
|
View.OnClickListener handleClick = account == null ? null : i -> {
|
||||||
|
args.putParcelable("profileAccount", Parcels.wrap(account));
|
||||||
|
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
|
||||||
|
};
|
||||||
|
String text = account != null ? fragment.getString(R.string.in_reply_to, account.displayName) : fragment.getString(R.string.sk_in_reply);
|
||||||
|
items.add(new ReblogOrReplyLineStatusDisplayItem(
|
||||||
|
parentID, fragment, text, account == null ? List.of() : account.emojis,
|
||||||
|
R.drawable.ic_fluent_arrow_reply_20_filled, null, handleClick
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
int l = 0;
|
||||||
|
ReblogOrReplyLineStatusDisplayItem lastLine = null;
|
||||||
|
for (StatusDisplayItem item : items) {
|
||||||
|
if (item instanceof ReblogOrReplyLineStatusDisplayItem line) {
|
||||||
|
line.setLineNo(l);
|
||||||
|
line.setIsLastLine(false);
|
||||||
|
lastLine = line;
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastLine != null) lastLine.setIsLastLine(true);
|
||||||
|
|
||||||
HeaderStatusDisplayItem header;
|
HeaderStatusDisplayItem header;
|
||||||
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, notification, scheduledStatus));
|
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, notification, scheduledStatus));
|
||||||
if(!TextUtils.isEmpty(statusForContent.content)){
|
if(!TextUtils.isEmpty(statusForContent.content))
|
||||||
items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID), fragment, statusForContent, disableTranslate));
|
items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID), fragment, statusForContent, disableTranslate));
|
||||||
} else
|
else
|
||||||
header.needBottomPadding=true;
|
header.needBottomPadding=true;
|
||||||
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream().filter(att->att.type.isImage()).collect(Collectors.toList());
|
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream().filter(att->att.type.isImage()).collect(Collectors.toList());
|
||||||
if(!imageAttachments.isEmpty()){
|
if(!imageAttachments.isEmpty()){
|
||||||
int photoIndex=0;
|
PhotoLayoutHelper.TiledLayoutResult layout=PhotoLayoutHelper.processThumbs(imageAttachments);
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=PhotoLayoutHelper.processThumbs(1000, 1910, imageAttachments);
|
items.add(new MediaGridStatusDisplayItem(parentID, fragment, layout, imageAttachments, statusForContent));
|
||||||
for(Attachment attachment:imageAttachments){
|
|
||||||
if(attachment.type==Attachment.Type.IMAGE){
|
|
||||||
items.add(new PhotoStatusDisplayItem(parentID, statusForContent, attachment, fragment, photoIndex, imageAttachments.size(), layout, layout.tiles[photoIndex]));
|
|
||||||
}else if(attachment.type==Attachment.Type.GIFV){
|
|
||||||
items.add(new GifVStatusDisplayItem(parentID, statusForContent, attachment, fragment, photoIndex, imageAttachments.size(), layout, layout.tiles[photoIndex]));
|
|
||||||
}else if(attachment.type==Attachment.Type.VIDEO){
|
|
||||||
items.add(new VideoStatusDisplayItem(parentID, statusForContent, attachment, fragment, photoIndex, imageAttachments.size(), layout, layout.tiles[photoIndex]));
|
|
||||||
}else{
|
|
||||||
throw new IllegalStateException("This isn't supposed to happen, type is "+attachment.type);
|
|
||||||
}
|
|
||||||
photoIndex++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(Attachment att:statusForContent.mediaAttachments){
|
for(Attachment att:statusForContent.mediaAttachments){
|
||||||
if(att.type==Attachment.Type.AUDIO){
|
if(att.type==Attachment.Type.AUDIO){
|
||||||
@@ -189,19 +182,15 @@ public abstract class StatusDisplayItem{
|
|||||||
}
|
}
|
||||||
if(addFooter){
|
if(addFooter){
|
||||||
items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID));
|
items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID));
|
||||||
if(status.hasGapAfter && !(fragment instanceof ThreadFragment)){
|
if(status.hasGapAfter && !(fragment instanceof ThreadFragment))
|
||||||
items.add(new GapStatusDisplayItem(parentID, fragment));
|
items.add(new GapStatusDisplayItem(parentID, fragment));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int i=1;
|
int i=1;
|
||||||
for(StatusDisplayItem item:items){
|
for(StatusDisplayItem item:items){
|
||||||
item.inset=inset;
|
item.inset=inset;
|
||||||
item.index=i++;
|
item.index=i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (titleItem != null) items.add(0, titleItem);
|
|
||||||
|
|
||||||
if (!statusForContent.filterRevealed) {
|
if (!statusForContent.filterRevealed) {
|
||||||
return new ArrayList<>(List.of(
|
return new ArrayList<>(List.of(
|
||||||
new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)
|
new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)
|
||||||
@@ -222,9 +211,6 @@ public abstract class StatusDisplayItem{
|
|||||||
HEADER,
|
HEADER,
|
||||||
REBLOG_OR_REPLY_LINE,
|
REBLOG_OR_REPLY_LINE,
|
||||||
TEXT,
|
TEXT,
|
||||||
PHOTO,
|
|
||||||
VIDEO,
|
|
||||||
GIFV,
|
|
||||||
AUDIO,
|
AUDIO,
|
||||||
POLL_OPTION,
|
POLL_OPTION,
|
||||||
POLL_FOOTER,
|
POLL_FOOTER,
|
||||||
@@ -234,8 +220,9 @@ public abstract class StatusDisplayItem{
|
|||||||
ACCOUNT,
|
ACCOUNT,
|
||||||
HASHTAG,
|
HASHTAG,
|
||||||
GAP,
|
GAP,
|
||||||
WARNING,
|
EXTENDED_FOOTER,
|
||||||
EXTENDED_FOOTER
|
MEDIA_GRID,
|
||||||
|
WARNING
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class Holder<T extends StatusDisplayItem> extends BindableViewHolder<T> implements UsableRecyclerView.DisableableClickable{
|
public static abstract class Holder<T extends StatusDisplayItem> extends BindableViewHolder<T> implements UsableRecyclerView.DisableableClickable{
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
@Override
|
@Override
|
||||||
public void onBind(TextStatusDisplayItem item){
|
public void onBind(TextStatusDisplayItem item){
|
||||||
text.setText(item.translated
|
text.setText(item.translated
|
||||||
? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
|
? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
|
||||||
: item.text);
|
: item.text);
|
||||||
text.setTextIsSelectable(item.textSelectable);
|
text.setTextIsSelectable(item.textSelectable);
|
||||||
if (item.textSelectable) {
|
if (item.textSelectable) {
|
||||||
textScrollView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
textScrollView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||||
@@ -171,8 +171,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
|||||||
translateEnabled &&
|
translateEnabled &&
|
||||||
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
|
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
|
||||||
item.status.language != null &&
|
item.status.language != null &&
|
||||||
(item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage))));
|
(item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage))))
|
||||||
// && (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable);
|
&& (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable);
|
||||||
translateWrap.setVisibility(translateVisible ? View.VISIBLE : View.GONE);
|
translateWrap.setVisibility(translateVisible ? View.VISIBLE : View.GONE);
|
||||||
translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post);
|
translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post);
|
||||||
translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, isBottomText ? "bottom-java" : item.translation.provider) : "");
|
translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, isBottomText ? "bottom-java" : item.translation.provider) : "");
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package org.joinmastodon.android.ui.displayitems;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.Outline;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewOutlineProvider;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
|
||||||
import org.joinmastodon.android.model.Attachment;
|
|
||||||
import org.joinmastodon.android.model.Status;
|
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
|
|
||||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|
||||||
|
|
||||||
public class VideoStatusDisplayItem extends ImageStatusDisplayItem{
|
|
||||||
public VideoStatusDisplayItem(String parentID, Status status, Attachment attachment, BaseStatusListFragment parentFragment, int index, int totalPhotos, PhotoLayoutHelper.TiledLayoutResult tiledLayout, PhotoLayoutHelper.TiledLayoutResult.Tile thisTile){
|
|
||||||
super(parentID, parentFragment, attachment, status, index, totalPhotos, tiledLayout, thisTile);
|
|
||||||
request=new UrlImageLoaderRequest(attachment.previewUrl, 1000, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type getType(){
|
|
||||||
return Type.VIDEO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Holder extends ImageStatusDisplayItem.Holder<VideoStatusDisplayItem>{
|
|
||||||
|
|
||||||
public Holder(Activity activity, ViewGroup parent){
|
|
||||||
super(activity, R.layout.display_item_video, parent);
|
|
||||||
View play=findViewById(R.id.play_button);
|
|
||||||
play.setOutlineProvider(new ViewOutlineProvider(){
|
|
||||||
@Override
|
|
||||||
public void getOutline(View view, Outline outline){
|
|
||||||
outline.setOval(0, 0, view.getWidth(), view.getHeight());
|
|
||||||
outline.setAlpha(.99f); // fixes shadow rendering
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,60 +3,50 @@ package org.joinmastodon.android.ui.displayitems;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
|
|
||||||
// Mind the gap!
|
|
||||||
public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
||||||
public boolean loading;
|
public boolean loading;
|
||||||
public final Status status;
|
public final Status status;
|
||||||
public ArrayList<StatusDisplayItem> filteredItems;
|
public List<StatusDisplayItem> filteredItems;
|
||||||
|
|
||||||
public WarningFilteredStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status, ArrayList<StatusDisplayItem> items){
|
public WarningFilteredStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status, List<StatusDisplayItem> filteredItems){
|
||||||
super(parentID, parentFragment);
|
super(parentID, parentFragment);
|
||||||
this.status=status;
|
this.status=status;
|
||||||
this.filteredItems = items;
|
this.filteredItems = filteredItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType(){
|
public Type getType(){
|
||||||
return Type.WARNING;
|
return Type.WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
|
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
|
||||||
public final View warningWrap;
|
public final View warningWrap;
|
||||||
public final Button showBtn;
|
public final TextView text;
|
||||||
public final TextView text;
|
public List<StatusDisplayItem> filteredItems;
|
||||||
public ArrayList<StatusDisplayItem> filteredItems;
|
|
||||||
|
|
||||||
public Holder(Context context, ViewGroup parent){
|
public Holder(Context context, ViewGroup parent) {
|
||||||
super(context, R.layout.display_item_warning, parent);
|
super(context, R.layout.display_item_filter_warning, parent);
|
||||||
warningWrap=findViewById(R.id.warning_wrap);
|
warningWrap=findViewById(R.id.warning_wrap);
|
||||||
showBtn=findViewById(R.id.reveal_btn);
|
text=findViewById(R.id.text);
|
||||||
showBtn.setOnClickListener(i -> item.parentFragment.onWarningClick(this));
|
}
|
||||||
text=findViewById(R.id.text);
|
|
||||||
// itemView.setOnClickListener(v->item.parentFragment.onRevealFilteredClick(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBind(WarningFilteredStatusDisplayItem item){
|
public void onBind(WarningFilteredStatusDisplayItem item) {
|
||||||
filteredItems = item.filteredItems;
|
filteredItems = item.filteredItems;
|
||||||
text.setText(item.parentFragment.getString(R.string.mo_filtered, item.status.filtered.get(item.status.filtered.size() -1).filter.title));
|
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.status.filtered.get(item.status.filtered.size() -1).filter.title));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(){
|
public void onClick() {
|
||||||
|
item.parentFragment.onWarningClick(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package org.joinmastodon.android.ui.photoviewer;
|
package org.joinmastodon.android.ui.photoviewer;
|
||||||
|
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
|
||||||
|
|
||||||
public interface PhotoViewerHost{
|
public interface PhotoViewerHost{
|
||||||
void openPhotoViewer(String parentID, Status status, int attachmentIndex);
|
void openPhotoViewer(String parentID, Status status, int attachmentIndex, MediaGridStatusDisplayItem.Holder gridHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,25 +8,25 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
import android.view.GestureDetector;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SoundEffectConstants;
|
import android.view.SoundEffectConstants;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewConfiguration;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class ClickableLinksDelegate {
|
public class ClickableLinksDelegate {
|
||||||
|
|
||||||
private Paint hlPaint;
|
private final Paint hlPaint;
|
||||||
private Path hlPath;
|
private Path hlPath;
|
||||||
private LinkSpan selectedSpan;
|
private LinkSpan selectedSpan;
|
||||||
private TextView view;
|
private final TextView view;
|
||||||
|
|
||||||
private final Runnable longClickRunnable = () -> {
|
|
||||||
if (selectedSpan != null) selectedSpan.onLongClick(view);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
private final GestureDetector gestureDetector;
|
||||||
|
|
||||||
public ClickableLinksDelegate(TextView view) {
|
public ClickableLinksDelegate(TextView view) {
|
||||||
this.view=view;
|
this.view=view;
|
||||||
@@ -34,11 +34,45 @@ public class ClickableLinksDelegate {
|
|||||||
hlPaint.setAntiAlias(true);
|
hlPaint.setAntiAlias(true);
|
||||||
hlPaint.setPathEffect(new CornerPathEffect(V.dp(3)));
|
hlPaint.setPathEffect(new CornerPathEffect(V.dp(3)));
|
||||||
// view.setHighlightColor(view.getResources().getColor(android.R.color.holo_blue_light));
|
// view.setHighlightColor(view.getResources().getColor(android.R.color.holo_blue_light));
|
||||||
|
gestureDetector = new GestureDetector(view.getContext(), new LinkGestureListener(), view.getHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouch(MotionEvent event) {
|
public boolean onTouch(MotionEvent event) {
|
||||||
long eventDuration = event.getEventTime() - event.getDownTime();
|
if(event.getAction()==MotionEvent.ACTION_CANCEL){
|
||||||
if(event.getAction()==MotionEvent.ACTION_DOWN){
|
// the gestureDetector does not provide a callback for CANCEL, therefore:
|
||||||
|
// remove background color of view before passing event to gestureDetector
|
||||||
|
resetAndInvalidate();
|
||||||
|
}
|
||||||
|
return gestureDetector.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove highlighting from span and let the system redraw the view
|
||||||
|
*/
|
||||||
|
private void resetAndInvalidate() {
|
||||||
|
hlPath=null;
|
||||||
|
selectedSpan=null;
|
||||||
|
view.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDraw(Canvas canvas){
|
||||||
|
if(hlPath!=null){
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(0, view.getPaddingTop());
|
||||||
|
canvas.drawPath(hlPath, hlPaint);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GestureListener for spans that represent URLs.
|
||||||
|
* onDown: on start of touch event, set highlighting
|
||||||
|
* onSingleTapUp: when there was a (short) tap, call onClick and reset highlighting
|
||||||
|
* onLongPress: copy URL to clipboard, let user know, reset highlighting
|
||||||
|
*/
|
||||||
|
private class LinkGestureListener extends GestureDetector.SimpleOnGestureListener {
|
||||||
|
@Override
|
||||||
|
public boolean onDown(@NonNull MotionEvent event) {
|
||||||
int line=-1;
|
int line=-1;
|
||||||
Rect rect=new Rect();
|
Rect rect=new Rect();
|
||||||
Layout l=view.getLayout();
|
Layout l=view.getLayout();
|
||||||
@@ -53,8 +87,7 @@ public class ClickableLinksDelegate {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CharSequence text=view.getText();
|
CharSequence text=view.getText();
|
||||||
if(text instanceof Spanned){
|
if(text instanceof Spanned s){
|
||||||
Spanned s=(Spanned)text;
|
|
||||||
LinkSpan[] spans=s.getSpans(0, s.length()-1, LinkSpan.class);
|
LinkSpan[] spans=s.getSpans(0, s.length()-1, LinkSpan.class);
|
||||||
if(spans.length>0){
|
if(spans.length>0){
|
||||||
for(LinkSpan span:spans){
|
for(LinkSpan span:spans){
|
||||||
@@ -71,7 +104,6 @@ public class ClickableLinksDelegate {
|
|||||||
}
|
}
|
||||||
hlPath=new Path();
|
hlPath=new Path();
|
||||||
selectedSpan=span;
|
selectedSpan=span;
|
||||||
view.postDelayed(longClickRunnable, ViewConfiguration.getLongPressTimeout());
|
|
||||||
hlPaint.setColor((span.getColor() & 0x00FFFFFF) | 0x33000000);
|
hlPaint.setColor((span.getColor() & 0x00FFFFFF) | 0x33000000);
|
||||||
//l.getSelectionPath(start, end, hlPath);
|
//l.getSelectionPath(start, end, hlPath);
|
||||||
for(int j=lstart;j<=lend;j++){
|
for(int j=lstart;j<=lend;j++){
|
||||||
@@ -97,35 +129,26 @@ public class ClickableLinksDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return super.onDown(event);
|
||||||
}
|
}
|
||||||
if(event.getAction()==MotionEvent.ACTION_UP && selectedSpan!=null){
|
|
||||||
if (eventDuration <= ViewConfiguration.getLongPressTimeout()) {
|
@Override
|
||||||
|
public boolean onSingleTapUp(@NonNull MotionEvent event) {
|
||||||
|
if(selectedSpan!=null){
|
||||||
view.playSoundEffect(SoundEffectConstants.CLICK);
|
view.playSoundEffect(SoundEffectConstants.CLICK);
|
||||||
selectedSpan.onClick(view.getContext());
|
selectedSpan.onClick(view.getContext());
|
||||||
|
resetAndInvalidate();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
view.removeCallbacks(longClickRunnable);
|
|
||||||
hlPath=null;
|
|
||||||
selectedSpan=null;
|
|
||||||
view.invalidate();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(event.getAction()==MotionEvent.ACTION_CANCEL){
|
|
||||||
hlPath=null;
|
|
||||||
selectedSpan=null;
|
|
||||||
view.removeCallbacks(longClickRunnable);
|
|
||||||
view.invalidate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDraw(Canvas canvas){
|
|
||||||
if(hlPath!=null){
|
|
||||||
canvas.save();
|
|
||||||
canvas.translate(0, view.getPaddingTop());
|
|
||||||
canvas.drawPath(hlPath, hlPaint);
|
|
||||||
canvas.restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(@NonNull MotionEvent event) {
|
||||||
|
if (selectedSpan == null) return;
|
||||||
|
UiUtils.copyText(view, selectedSpan.getType() == LinkSpan.Type.URL ? selectedSpan.getLink() : selectedSpan.getText());
|
||||||
|
//reset view
|
||||||
|
resetAndInvalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package org.joinmastodon.android.ui.text;
|
package org.joinmastodon.android.ui.text;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.style.CharacterStyle;
|
import android.text.style.CharacterStyle;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
@@ -38,7 +36,7 @@ public class LinkSpan extends CharacterStyle {
|
|||||||
public void updateDrawState(TextPaint tp) {
|
public void updateDrawState(TextPaint tp) {
|
||||||
tp.setColor(color=tp.linkColor);
|
tp.setColor(color=tp.linkColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(Context context){
|
public void onClick(Context context){
|
||||||
switch(getType()){
|
switch(getType()){
|
||||||
case URL -> UiUtils.openURL(context, accountID, link);
|
case URL -> UiUtils.openURL(context, accountID, link);
|
||||||
@@ -48,21 +46,14 @@ public class LinkSpan extends CharacterStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLongClick(View view) {
|
|
||||||
if (getType() == Type.URL) {
|
|
||||||
Intent shareIntent = new Intent(Intent.ACTION_SEND)
|
|
||||||
.setType("text/plain")
|
|
||||||
.putExtra(Intent.EXTRA_TEXT, link);
|
|
||||||
view.getContext().startActivity(Intent.createChooser(shareIntent, null));
|
|
||||||
} else {
|
|
||||||
UiUtils.copyText(view, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLink(){
|
public String getLink(){
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
public Type getType(){
|
public Type getType(){
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ public class ColorPalette {
|
|||||||
ColorPreference.BLUE, new ColorPalette(R.style.ColorPalette_Blue),
|
ColorPreference.BLUE, new ColorPalette(R.style.ColorPalette_Blue),
|
||||||
ColorPreference.BROWN, new ColorPalette(R.style.ColorPalette_Brown),
|
ColorPreference.BROWN, new ColorPalette(R.style.ColorPalette_Brown),
|
||||||
ColorPreference.RED, new ColorPalette(R.style.ColorPalette_Red),
|
ColorPreference.RED, new ColorPalette(R.style.ColorPalette_Red),
|
||||||
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow),
|
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
|
||||||
ColorPreference.NORD, new ColorPalette(R.style.ColorPalette_Nord)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private @StyleRes int base;
|
private @StyleRes int base;
|
||||||
|
|||||||
@@ -65,4 +65,4 @@ public class DiscoverInfoBannerHelper{
|
|||||||
POST_NOTIFICATIONS,
|
POST_NOTIFICATIONS,
|
||||||
// ACCOUNTS
|
// ACCOUNTS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ import android.view.View;
|
|||||||
|
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||||
import org.joinmastodon.android.fragments.NotificationsListFragment;
|
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
|
||||||
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -87,21 +85,11 @@ public class InsetStatusItemDecoration extends RecyclerView.ItemDecoration{
|
|||||||
boolean topSiblingInset=pos>0 && displayItems.get(pos-1).inset;
|
boolean topSiblingInset=pos>0 && displayItems.get(pos-1).inset;
|
||||||
boolean bottomSiblingInset=pos<displayItems.size()-1 && displayItems.get(pos+1).inset;
|
boolean bottomSiblingInset=pos<displayItems.size()-1 && displayItems.get(pos+1).inset;
|
||||||
int pad;
|
int pad;
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder || holder instanceof LinkCardStatusDisplayItem.Holder)
|
if(holder instanceof MediaGridStatusDisplayItem.Holder || holder instanceof LinkCardStatusDisplayItem.Holder)
|
||||||
pad=V.dp(16);
|
pad=V.dp(16);
|
||||||
else
|
else
|
||||||
pad=V.dp(12);
|
pad=V.dp(12);
|
||||||
boolean insetLeft=true, insetRight=true;
|
boolean insetLeft=true, insetRight=true;
|
||||||
if(holder instanceof ImageStatusDisplayItem.Holder<?> img){
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult layout=img.getItem().tiledLayout;
|
|
||||||
PhotoLayoutHelper.TiledLayoutResult.Tile tile=img.getItem().thisTile;
|
|
||||||
// only inset those items that are on the edges of the layout
|
|
||||||
insetLeft=tile.startCol==0;
|
|
||||||
insetRight=tile.startCol+tile.colSpan==layout.columnSizes.length;
|
|
||||||
// inset all items in the bottom row
|
|
||||||
if(tile.startRow+tile.rowSpan==layout.rowSizes.length)
|
|
||||||
bottomSiblingInset=false;
|
|
||||||
}
|
|
||||||
if(insetLeft)
|
if(insetLeft)
|
||||||
outRect.left=pad;
|
outRect.left=pad;
|
||||||
if(insetRight)
|
if(insetRight)
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package org.joinmastodon.android.ui.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.model.Attachment;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
|
||||||
|
|
||||||
|
public class MediaAttachmentViewController{
|
||||||
|
public final View view;
|
||||||
|
public final MediaGridStatusDisplayItem.GridItemType type;
|
||||||
|
public final ImageView photo;
|
||||||
|
public final View altButton, noAltButton, btnsWrap;
|
||||||
|
public static int[] altWrapPadding = null;
|
||||||
|
private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable();
|
||||||
|
private final Context context;
|
||||||
|
private boolean didClear;
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
|
||||||
|
view=context.getSystemService(LayoutInflater.class).inflate(switch(type){
|
||||||
|
case PHOTO -> R.layout.display_item_photo;
|
||||||
|
case VIDEO -> R.layout.display_item_video;
|
||||||
|
case GIFV -> R.layout.display_item_gifv;
|
||||||
|
}, null);
|
||||||
|
photo=view.findViewById(R.id.photo);
|
||||||
|
altButton=view.findViewById(R.id.alt_button);
|
||||||
|
noAltButton=view.findViewById(R.id.no_alt_button);
|
||||||
|
btnsWrap=view.findViewById(R.id.alt_badges);
|
||||||
|
this.type=type;
|
||||||
|
this.context=context;
|
||||||
|
if (altWrapPadding == null) {
|
||||||
|
altWrapPadding = new int[] { btnsWrap.getPaddingLeft(), btnsWrap.getPaddingTop(), btnsWrap.getPaddingRight(), btnsWrap.getPaddingBottom() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(Attachment attachment, Status status){
|
||||||
|
this.status=status;
|
||||||
|
crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight());
|
||||||
|
crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder);
|
||||||
|
crossfadeDrawable.setCrossfadeAlpha(status.spoilerRevealed ? 0f : 1f);
|
||||||
|
photo.setImageDrawable(null);
|
||||||
|
photo.setImageDrawable(crossfadeDrawable);
|
||||||
|
boolean hasAltText = !TextUtils.isEmpty(attachment.description);
|
||||||
|
photo.setContentDescription(!hasAltText ? context.getString(R.string.media_no_description) : attachment.description);
|
||||||
|
if(btnsWrap!=null){
|
||||||
|
btnsWrap.setVisibility(View.VISIBLE);
|
||||||
|
altButton.setVisibility(hasAltText && GlobalUserPreferences.showAltIndicator ? View.VISIBLE : View.GONE);
|
||||||
|
noAltButton.setVisibility(!hasAltText && GlobalUserPreferences.showNoAltIndicator ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
didClear=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImage(Drawable drawable){
|
||||||
|
crossfadeDrawable.setImageDrawable(drawable);
|
||||||
|
if(didClear && status.spoilerRevealed)
|
||||||
|
crossfadeDrawable.animateAlpha(0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearImage(){
|
||||||
|
crossfadeDrawable.setCrossfadeAlpha(1f);
|
||||||
|
crossfadeDrawable.setImageDrawable(null);
|
||||||
|
didClear=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRevealed(boolean revealed){
|
||||||
|
crossfadeDrawable.animateAlpha(revealed ? 0f : 1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
package org.joinmastodon.android.ui.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
public class FrameLayoutThatOnlyMeasuresFirstChild extends FrameLayout{
|
||||||
|
public FrameLayoutThatOnlyMeasuresFirstChild(Context context){
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameLayoutThatOnlyMeasuresFirstChild(Context context, AttributeSet attrs){
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameLayoutThatOnlyMeasuresFirstChild(Context context, AttributeSet attrs, int defStyle){
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
||||||
|
if(getChildCount()==0)
|
||||||
|
return;
|
||||||
|
View child0=getChildAt(0);
|
||||||
|
measureChild(child0, widthMeasureSpec, heightMeasureSpec);
|
||||||
|
super.onMeasure(child0.getMeasuredWidth() | MeasureSpec.EXACTLY, child0.getMeasuredHeight() | MeasureSpec.EXACTLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package org.joinmastodon.android.ui.views;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import me.grishka.appkit.utils.V;
|
|
||||||
|
|
||||||
public class ImageAttachmentFrameLayout extends FrameLayout{
|
|
||||||
public static final int MAX_WIDTH=400; // dp
|
|
||||||
|
|
||||||
private PhotoLayoutHelper.TiledLayoutResult tileLayout;
|
|
||||||
private PhotoLayoutHelper.TiledLayoutResult.Tile tile;
|
|
||||||
private int horizontalInset;
|
|
||||||
|
|
||||||
public ImageAttachmentFrameLayout(@NonNull Context context){
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageAttachmentFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs){
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageAttachmentFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr){
|
|
||||||
super(context, attrs, defStyleAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
|
||||||
if(isInEditMode()){
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int w=Math.min(((View)getParent()).getMeasuredWidth(), V.dp(MAX_WIDTH))-horizontalInset;
|
|
||||||
int actualHeight=Math.round(tile.height/1000f*w)+V.dp(1)*(tile.rowSpan-1);
|
|
||||||
int actualWidth=Math.round(tile.width/1000f*w);
|
|
||||||
if(tile.startCol+tile.colSpan<tileLayout.columnSizes.length)
|
|
||||||
actualWidth-=V.dp(1);
|
|
||||||
heightMeasureSpec=actualHeight | MeasureSpec.EXACTLY;
|
|
||||||
widthMeasureSpec=actualWidth | MeasureSpec.EXACTLY;
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLayout(PhotoLayoutHelper.TiledLayoutResult layout, PhotoLayoutHelper.TiledLayoutResult.Tile tile, int horizontalInset){
|
|
||||||
tileLayout=layout;
|
|
||||||
this.tile=tile;
|
|
||||||
this.horizontalInset=horizontalInset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package org.joinmastodon.android.ui.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
||||||
|
|
||||||
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
|
public class MediaGridLayout extends ViewGroup{
|
||||||
|
private static final String TAG="MediaGridLayout";
|
||||||
|
|
||||||
|
public static final int MAX_WIDTH=400; // dp
|
||||||
|
private static final int GAP=1; // dp
|
||||||
|
private PhotoLayoutHelper.TiledLayoutResult tiledLayout;
|
||||||
|
private int[] columnStarts=new int[10], columnEnds=new int[10], rowStarts=new int[10], rowEnds=new int[10];
|
||||||
|
|
||||||
|
public MediaGridLayout(Context context){
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaGridLayout(Context context, AttributeSet attrs){
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaGridLayout(Context context, AttributeSet attrs, int defStyle){
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
|
||||||
|
if(tiledLayout==null){
|
||||||
|
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int width=Math.min(V.dp(MAX_WIDTH), MeasureSpec.getSize(widthMeasureSpec));
|
||||||
|
int height=Math.round(width*(tiledLayout.height/(float)PhotoLayoutHelper.MAX_WIDTH));
|
||||||
|
|
||||||
|
int offset=0;
|
||||||
|
for(int i=0;i<tiledLayout.columnSizes.length;i++){
|
||||||
|
columnStarts[i]=offset;
|
||||||
|
offset+=Math.round(tiledLayout.columnSizes[i]/(float)tiledLayout.width*width);
|
||||||
|
columnEnds[i]=offset;
|
||||||
|
offset+=V.dp(GAP);
|
||||||
|
}
|
||||||
|
columnEnds[tiledLayout.columnSizes.length-1]=width;
|
||||||
|
offset=0;
|
||||||
|
for(int i=0;i<tiledLayout.rowSizes.length;i++){
|
||||||
|
rowStarts[i]=offset;
|
||||||
|
offset+=Math.round(tiledLayout.rowSizes[i]/(float)tiledLayout.height*height);
|
||||||
|
rowEnds[i]=offset;
|
||||||
|
offset+=V.dp(GAP);
|
||||||
|
}
|
||||||
|
rowEnds[tiledLayout.rowSizes.length-1]=height;
|
||||||
|
|
||||||
|
for(int i=0;i<getChildCount();i++){
|
||||||
|
View child=getChildAt(i);
|
||||||
|
LayoutParams lp=(LayoutParams) child.getLayoutParams();
|
||||||
|
int colSpan=Math.max(1, lp.tile.colSpan)-1;
|
||||||
|
int rowSpan=Math.max(1, lp.tile.rowSpan)-1;
|
||||||
|
int w=columnEnds[lp.tile.startCol+colSpan]-columnStarts[lp.tile.startCol];
|
||||||
|
int h=rowEnds[lp.tile.startRow+rowSpan]-rowStarts[lp.tile.startRow];
|
||||||
|
child.measure(w | MeasureSpec.EXACTLY, h | MeasureSpec.EXACTLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b){
|
||||||
|
if(tiledLayout==null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int maxWidth=V.dp(MAX_WIDTH);
|
||||||
|
int xOffset=0;
|
||||||
|
if(r-l>maxWidth){
|
||||||
|
xOffset=(r-l)/2-maxWidth/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<getChildCount();i++){
|
||||||
|
View child=getChildAt(i);
|
||||||
|
LayoutParams lp=(LayoutParams) child.getLayoutParams();
|
||||||
|
int colSpan=Math.max(1, lp.tile.colSpan)-1;
|
||||||
|
int rowSpan=Math.max(1, lp.tile.rowSpan)-1;
|
||||||
|
child.layout(columnStarts[lp.tile.startCol]+xOffset, rowStarts[lp.tile.startRow], columnEnds[lp.tile.startCol+colSpan]+xOffset, rowEnds[lp.tile.startRow+rowSpan]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTiledLayout(PhotoLayoutHelper.TiledLayoutResult tiledLayout){
|
||||||
|
this.tiledLayout=tiledLayout;
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LayoutParams extends ViewGroup.LayoutParams{
|
||||||
|
public PhotoLayoutHelper.TiledLayoutResult.Tile tile;
|
||||||
|
|
||||||
|
public LayoutParams(PhotoLayoutHelper.TiledLayoutResult.Tile tile){
|
||||||
|
super(WRAP_CONTENT, WRAP_CONTENT);
|
||||||
|
this.tile=tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,8 +50,8 @@ public abstract class GithubSelfUpdater{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class UpdateInfo{
|
public static class UpdateInfo{
|
||||||
public String changelog;
|
|
||||||
public String version;
|
public String version;
|
||||||
|
public String changelog;
|
||||||
public long size;
|
public long size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.joinmastodon.android.ui.utils;
|
package org.joinmastodon.android.utils;
|
||||||
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.joinmastodon.android.utils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class TypedObjectPool<K, V>{
|
||||||
|
private final Function<K, V> producer;
|
||||||
|
private final HashMap<K, LinkedList<V>> pool=new HashMap<>();
|
||||||
|
|
||||||
|
public TypedObjectPool(Function<K, V> producer){
|
||||||
|
this.producer=producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V obtain(K type){
|
||||||
|
LinkedList<V> tp=pool.get(type);
|
||||||
|
if(tp==null)
|
||||||
|
pool.put(type, tp=new LinkedList<>());
|
||||||
|
|
||||||
|
V value=tp.poll();
|
||||||
|
if(value==null)
|
||||||
|
value=producer.apply(type);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reuse(K type, V obj){
|
||||||
|
Objects.requireNonNull(obj);
|
||||||
|
Objects.requireNonNull(type);
|
||||||
|
|
||||||
|
LinkedList<V> tp=pool.get(type);
|
||||||
|
if(tp==null)
|
||||||
|
pool.put(type, tp=new LinkedList<>());
|
||||||
|
tp.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="?bookmark_selected" android:state_selected="true"/>
|
<item android:color="@color/bookmark_selected" android:state_selected="true"/>
|
||||||
<item android:color="?android:textColorSecondary"/>
|
<item android:color="?android:textColorSecondary"/>
|
||||||
</selector>
|
</selector>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="?colorBackgroundLightest" android:state_enabled="true"/>
|
<item android:color="?colorButtonBackgroundSecondaryDarkOnLight" android:state_enabled="true"/>
|
||||||
<item android:color="?android:colorBackground"/>
|
<item android:color="?colorButtonBackgroundSecondaryDarkOnLightDisabled"/>
|
||||||
</selector>
|
</selector>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="@color/black" android:state_enabled="true"/>
|
<item android:color="?colorButtonTextPrimaryLightOnDark" android:state_enabled="true"/>
|
||||||
<item android:color="?colorTabInactive"/>
|
<item android:color="?colorButtonTextPrimaryLightOnDarkDisabled"/>
|
||||||
</selector>
|
</selector>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="?favorite_selected" android:state_selected="true"/>
|
<item android:color="@color/favorite_selected" android:state_selected="true"/>
|
||||||
<item android:color="?android:textColorSecondary"/>
|
<item android:color="?android:textColorSecondary"/>
|
||||||
</selector>
|
</selector>
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:color="?android:colorAccent" android:state_selected="true"/>
|
|
||||||
<item android:color="?android:textColorSecondary" android:state_enabled="true"/>
|
|
||||||
<item android:color="?colorSecondary"/>
|
|
||||||
</selector>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user