Compare commits

..

No commits in common. "main" and "3.0.6" have entirely different histories.
main ... 3.0.6

2487 changed files with 40156 additions and 137245 deletions

View file

@ -1,40 +0,0 @@
---
name: "Bug"
about: "Something isn't working"
labels:
- Bug
---
<!-- Please, describe the issue here -->
## # Steps for reproducing the issue
<!-- Step, to reproduce it -->
---
<!-- The instance you are using -->
Instance:
<!-- Your social network -->
<!-- Put a x between brackets like: - [x] Mastodon -->
- [ ] Mastodon
- [ ] Pleroma
- [ ] Friendica
- [ ] Pixelfed
<!-- If you know the version of Fedilab that you are using (can be found in about page) -->
Version of Fedilab:
<!-- Your Android version -->
Android version:
<!-- If you read our contributing advice -->
- [ ] I read the [contributing page](https://codeberg.org/tom79/Fedilab/src/branch/main/CONTRIBUTING.md)

View file

@ -1,25 +0,0 @@
---
name: "Feature"
about: "A new feature or an enhancement to an existing feature"
labels:
- Feature
---
## # Describe the improvement
<!-- Your social network -->
<!-- Put a x between brackets like: - [x] Mastodon -->
- [ ] Mastodon
- [ ] Pleroma
- [ ] Friendica
- [ ] Pixelfed
<!-- Describe the improvement here -->
<!-- If you read our contributing advice -->
- [ ] I read the [contributing page](https://codeberg.org/tom79/Fedilab/src/branch/main/CONTRIBUTING.md)

View file

@ -1 +0,0 @@
- Fix some bugs reported.

View file

@ -1,6 +0,0 @@
- Keep improving the scroll behaviour
- Scroll to top (tab reselection) will fetch new messages and then scroll to top
- Remove focus point for fit media preview
- Fix cannot share with one account
- Fix black theme
- Fix some button colors

View file

@ -1,16 +0,0 @@
Added:
- Set compose language (from compose menu -> three vertical dots)
- Add reactions support for Pleroma
- Add privacy indicator at the top right
Changed
- Improve the scrolling behaviour
- Scroll to top (tab reselection) will fetch new messages and then scroll to top
Fixed:
- Empty tag timelines
- Remove focus point for fit media preview
- Fix cannot share with one account
- Fix black theme
- Theme cannot be selected
- Fix some button colors

View file

@ -1,9 +0,0 @@
Added:
- Allow to define the max chars count when not detected (In about the instance)
- Add emoji one picker when composing (must be enabled in settings)
- Add release notes with the ability to translate them
Fixed:
- Friendica custom emojis not displayed
- Long press to store media
- Some bug fixes

View file

@ -1,11 +0,0 @@
Changed:
- Composing messages is no longer forced to max chars
Fixed:
- Cross-account follow
- Cannot subscribe to notifications for an account
- Issues when sharing
- Wrong profile for emoji reactions in notifications
- Issue with cards
- Crashes with tabs
- Tabs cannot be renamed

View file

@ -1,15 +0,0 @@
Added:
- New theme: Dark Elephant from S1m
- Error messages from server side when posting fails
- Allow to set the fetch time for delayed notifications
Changed:
- Fetch more buttons more visible
Fixed:
- Issue when fetching missing messages
- Some issues with themes
- Too much lost space with reaction (Pleroma)
- Delete and redraft crashes
- Crash when playing a video
- Other crash fixes

View file

@ -1,20 +0,0 @@
Added:
- Export Settings
- Propagate manual reordering of lists in timeline to "Lists" submenu
- Allow to change the push distributor in settings
Changed:
- Improve fit preview images
- Improve notifications
- Profile media displayed in a grid
Fixed:
- Some Peertube videos not working
- Respect the default visibility account when replying
- Discriminate gif from images
- App crashes when opening external instance timeline
- Remove button in thread composer crashes the app
- Back button opens a lot of old activities before closing the app
- Problems with sharing
- Reorder Lists with UI issue on change the visibility
- Link is not shown correctly in posts from Friendica

View file

@ -1,9 +0,0 @@
Added:
- Settings to set all timelines at the top (default disabled)
- Settings to display timelines in a list (default disabled)
- Display counters for fav/reblog in timelines (default disabled)
Fixed:
- Visibility issue when replying
- Some theme issues when composing
- Some crashes

View file

@ -1,5 +0,0 @@
- Improve speed for Nitter instances
- Allow to edit Nitter accounts with a long press on tabs
- Fix pagination issue with pinned timelines
- Fix some crashes
- Fix visibility when displaying counters

View file

@ -1,5 +0,0 @@
- Fix an issue with cache and home timeline
- Nitter timelines use the custom instance from settings
- Fix Nitter issues (only RT)
- No longer accepts invalid certificate for onion URLs(Google)
- Fix some crashes

View file

@ -1,4 +0,0 @@
- New cache mechanism
- Cache can be disabled in settings
- Add counters for new messages
- Some fixes.

View file

@ -1,3 +0,0 @@
- Fix post message with media
- Set thumbnails load behavior Always/Wifi only /ask
- Some other small fixes

View file

@ -1,5 +0,0 @@
- Fix post message with media
- Fix encoding issue with media descriptions
- Fix Friendica tag search
- Fixes when composing
- Some other small fixes

View file

@ -1,10 +0,0 @@
Added:
- New cache mechanism (can be disabled in settings)
- Set thumbnails load behavior Always/Wifi only /ask
- Add counters for new messages in timelines
Fixed:
- Contextual menu not working in threads
- Tag search issue with Friendica
- Notifications click open the wrong tab
- Encoding issue with media descriptions
- Some other fixes.

View file

@ -1,7 +0,0 @@
Added:
- Disable counters in settings
Fixed:
- Duplicated messages from cache
- Notifications in double
- Drafts not automatically removed
- Messages not removed from cache after deletion

View file

@ -1,2 +0,0 @@
Fixed:
- Attach media to a reply

View file

@ -1,12 +0,0 @@
Changed:
- Swipe between timelines
- Improve cache
- Button sizes in messages follow defined scale
Fixed:
- Pleroma: Emoji reactions
- Sharing (several fixes)
- Theme issues
- Rendering issue for links
- Notifications not removed from cache
- Some crashes

View file

@ -1,15 +0,0 @@
Changed:
- Swipe between timelines
- Improve cache
- Button sizes can be changed in settings
- French translation
Fixed:
- Pleroma: Emoji reactions
- Sharing (several fixes)
- Theme issues
- Rendering issue for links
- Notifications not removed from cache
- Issue with watermarks
- Pagination with bookmarks/favourites
- Some crashes

View file

@ -1,15 +0,0 @@
Added:
- Change app icon (Settings > Interface)
- Allow to disable "remember position" in timelines
- Allow to disable notification aggregation in settings
Changed:
- Allow to disable/enable media for notifications
Fixed:
- Post loses "spoiler message" when adding a media
- Camera not working on Android 11
- Notification aggregation
- Vibrations when fetching new notifications
- Fix an issue with media timelines
- Some crashes

View file

@ -1,11 +0,0 @@
Added:
- Pin/Unpin messages
- Set the default language for translations
Changed:
- Allow to disable/enable media for notifications
Fixed:
- Wrong images in notification timeline
- Double icon bug
- Fix some crashes

View file

@ -1,2 +0,0 @@
- Edit messages (if your instance supports that feature)
- Some fixes

View file

@ -1,22 +0,0 @@
Added:
- Edit messages (if your instance supports that feature)
- Pin/Unpin messages
- Set the default language for translations
- Change app icon (Settings > Interface)
- Allow to disable "remember position" in timelines
- Allow to disable notification aggregation in settings
- Icon on media previews if a description is available
Changed:
- Allow to disable/enable media for notifications
Fixed:
- Post loses "spoiler message" when adding a media
- Camera not working on Android 11
- Notification aggregation
- Vibrations when fetching new notifications
- Fix an issue with media timelines
- Fix some theme issues
- Fix an issue with built-in browser & openId
- Bad behaviours with Art Timelines
- Some crashes

View file

@ -1,13 +0,0 @@
Added:
- Display client in detailed messages
- Visual support for quotes starting with ">"
- Increase indentations for threads (zero to 20, default 5)
- Visibility for public replies set to unlisted (can be disabled)
Changed:
- Reduce title size when text size is increased
Fixed:
- Filters are not applied
- Blocking an account doesn't remove messages in cache
- Fix some crashes

View file

@ -1,5 +0,0 @@
Fixed:
- Order of notifications
- URL when sharing boosted message
- Blank pages when restarting
- Fix some crashes

View file

@ -1,5 +0,0 @@
Fixed:
- Issue with messages/notifications not correctly displayed
- Friendica: issues with mentions and tags (open browser)
- Improve sharing behaviour

View file

@ -1,9 +0,0 @@
Changed:
- Tag search ordered by popularity
Fixed:
- Unable to get client ID on some devices
- Issue with messages/notifications not correctly displayed
- Notifications not received
- Friendica: issues with mentions and tags (open browser)
- Improve sharing behaviour

View file

@ -1,9 +0,0 @@
Added:
- Two new Light themes
- More moderation features
Fixed:
- Filter not working
- Crash with trends
- Some content lost when sending messages (mentions)
- Some other fixes

View file

@ -1,16 +0,0 @@
Added:
- Follow tags (dedicated entry in menu)
- Reduce the list of languages when composing (Settings > Compose)
- Language indicator when composing
- Replies are automatically set to first message language
- Two new Light themes
- More moderation features
- List name can be edited
Fixed:
- Filter not working
- Crash with trends
- Issue with themes
- Some content lost when sending messages (mentions)
- Fix freezes in timelines
- Some other fixes

View file

@ -1,14 +0,0 @@
Added:
- Support to open links containing /@display_name/ in their path (works on older devices)
- Display reply count when counters are enabled
- Add support for filtering profile messages
Changed:
- Compose view takes the whole width even in threads
- Reset push notification marker when clearing cache
Fixed:
- Draft stored when replying "no" or dialog prompted without changes
- Filters not working with tags
- Add a specific error message for followed tags
- Empty pages when starting the app

View file

@ -1,2 +0,0 @@
Added:
- Full support to new filters for Mastodon 4

View file

@ -1,5 +0,0 @@
Added:
- Visit profiles without being authenticated / Allow to display all their messages
Fixed:
- Saving media fails on some devices

View file

@ -1,14 +0,0 @@
Added:
- Full support to new filters for Mastodon 4
- Visit profiles without being authenticated / Allow to display all their messages
Changed:
- Compose view takes the whole width even in threads
- Accounts can be timed-mute from their profile
Fixed:
- Draft stored when replying "no" or dialog prompted without changes
- Empty pages when starting the app
- Saving and sharing media fails on some devices
- Add support for admin notifications
- Copying content of a message

View file

@ -1,13 +0,0 @@
Added:
- List of blocked domains (allow to unblock)
- Support gemini links
- Suggested followers
Changed:
- Allow search term to be edited
Fixed:
- Drafts deleted with no warning
- App crashes when proxy is set
- Filter not synced after being edited
- Some crashes

View file

@ -1,18 +0,0 @@
Added:
- List of blocked domains (allow to unblock)
- Support gemini links
- Suggested followers
- Mod/Adm: Manage instance blocked domains
- Open messages with another account
- Allow to disable notifications for admins
- Sort lists
Changed:
- Allow search term to be edited
Fixed:
- Drafts deleted with no warning
- Remove lists from "Manage timelines"
- App crashes when proxy is set
- Filter not synced after being edited
- Some crashes / improvements

View file

@ -1,12 +0,0 @@
Added:
- Mute tags with long press in timelines
Changed:
- Muted account messages are now removed from cache
Fixed:
- Open with another account
- Fix jumps in profiles
- Media not displayed in album -> force indexation
- Built-in browser does not give admin scope
- Some crashes

View file

@ -1,9 +0,0 @@
Added:
- Migrate to Material Design 3
- 5 Themes (Light, Dark, Solarized Light/Dark, Black)
- Automatically switch between Light/Dark
- Light and Dark theme can be defined for time-based switch
- Android 12+: Dynamic color
Fixed:
- Jumps in timelines

View file

@ -1,10 +0,0 @@
Changed:
- Remove built-in browser support
- More spaces between action buttons in messages
Fixed:
- Text size issue
- Text overlap
- Wrong background for solarized black
- Mix between light and dark theme
- Save button hidden

View file

@ -1,14 +0,0 @@
Added:
- New design with 5 themes
Changed:
- Remove built-in browser support
- Fit preview image displays images vertically
- Add counters next to images
Fixed:
- Jumps in timelines
- Replies to wrong messages with followed instances
- Bug with delete&redraft with a media
- List cannot be hidden
- Some crashes

View file

@ -1,6 +0,0 @@
Changed:
- Remove card presentation
- Link color for black theme
Fixed:
- Crash when changing the theme

View file

@ -1,4 +0,0 @@
Fixed:
- Custom emoji are not always displayed
- Jumps in timeline when using "fit preview images"
- Dark theme: timeline buttons without toggle

View file

@ -1,3 +0,0 @@
Fixed:
- Jumps with fit preview images when scrolling up
- Fetch more button broken with cache

View file

@ -1,11 +0,0 @@
Added:
- Dracula theme
Changed:
- Colors for Light/Dark/Black themes
Fixed:
- Animated profile pictures not displayed
- Mentions broken in profile bio and fields
- Tag patterns in URL break the link
- Typo in followed tags

View file

@ -1,16 +0,0 @@
Added:
- Dracula theme
- Customize message colors
- Enable/Disable Card presentation
Changed:
- Colors for some themes
- Space between buttons
Fixed:
- Animated profile pictures not displayed
- Mentions broken in profile bio and fields
- Jumps with fit preview images when scrolling up
- Fetch more button broken with cache
- Tag patterns in URL break the link
- Typo in followed tags

View file

@ -1,4 +0,0 @@
Added:
- Display all messages in threads from remote instances (when possible)
* Only public messages for instances using the Mastodon API
* A dedicated button is displayed at the top right when conditions are filled.

View file

@ -1,11 +0,0 @@
Added:
- Allow to unmute/unfollow/unpin a tag from tag timelines
- Automatically add the tag when composing from a tag timeline
- Add a translate button at the bottom of messages (default: disabled)
- Add account role in profiles
Fixed:
- Contact not working when composing
- Status bar for black theme
- Message duplicated in conversations when edited
- Color issue on Android 5

View file

@ -1,18 +0,0 @@
Added:
- Display all messages in threads from remote instances (when possible)
- Allow to unmute/unfollow/unpin a tag from tag timelines
- Display most used accounts in header menu for an easy switch
- Automatically add the tag when composing from a tag timeline
- Add a translate button at the bottom of messages (default: disabled)
- Add account role in profiles
- Translate morse
Changed:
- Disable animations after a refresh
Fixed:
- Contact not working when composing
- Status bar for black theme
- Message duplicated in conversations when edited
- Color issue on Android 5
- Several crashes

View file

@ -1,4 +0,0 @@
Added:
- Mute/Unmute accounts in the Home timeline from their messages or their profiles
- Add all users from a list to "Muted home" in one click
- Display/Manage users that are muted for home

View file

@ -1,7 +0,0 @@
Added:
- Mute/Unmute accounts in the Home timeline from their messages or their profiles
- Add all users from a list to "Muted home" in one click
- Display/Manage users that are muted for home
Fixed:
- Timeline crashes

View file

@ -1,9 +0,0 @@
Added:
- Add more targeted languages in picker for translations
- Add account name in push notifications
Fixed:
- Fix a crash when changing language
- Fix counter colors
- Fix default link color
- Fix a crash when clicking on mentions

View file

@ -1,12 +0,0 @@
Added:
- Full data import/export feature
- Android 13 themed icon support
Fixed:
- Fix a regression with filters
- Fix dark solarized theme
- Fix hide link previews for CW
- Fix status bar color for all themes
- Fix language in compose "..."
- Fix add all home muted accounts from lists
- Fix top notification badges

View file

@ -1,12 +0,0 @@
Added:
- Post random quotes
- Group reblogs in home timeline
Changed:
- Display translate button only when language is different
- Respect blank spaces between words in messages
- Focus button more accessible when editing media
Fixed:
- Behavior with cw toggle
- Truncated gimini links

View file

@ -1,16 +0,0 @@
Added:
- Rename Nitter timelines
- Android 13 support
Changed:
- Visual feedback for block on account list
- Visual changes with compose / top bar
Fixed:
- Nav buttons not visible with media (Light theme)
- Status bar with Android 5
- Fix links not clickable
- Fix deep links
- Fix remote threads not fetched for some instances
- Adding description to shared media
- Fix crashes

View file

@ -1,8 +0,0 @@
Added:
- Pagination with search / trending
Fixed:
- Long press on Nitter tabs
- Open with another accounts
- Chars size not respected for Android 5-6
- Wrong instance fetched for instances.social

View file

@ -1,33 +0,0 @@
Added:
- Post random quotes
- Group reblogs in home timeline
- Rename Nitter timelines
- Android 13 support
- Pagination with search / trending
- Allow to remove left margin in messages (default: disabled)
Changed:
- Display translate button only when language is different
- Respect blank spaces between words in messages
- Focus button more accessible when editing media
- Visual feedback for block on account list
- Visual changes with compose / top bar
- Use custom Nitter timeline name in manage timelines
Fixed:
- Behavior with cw toggle
- Truncated gimini links
- Nav buttons not visible with media (Light theme)
- Status bar with Android 5
- Fix links not clickable
- Fix deep links
- Fix remote threads not fetched for some instances
- Adding description to shared media
- Open with another accounts
- Chars size not respected for Android 5-6
- Wrong instance fetched for instances.social
- Bouncing Timeline on refresh
- Links to mentions, tags, urls, not visible.
- Custom channel sounds not applied
- users with short username are not linked
- Fix crashes

View file

@ -1,9 +0,0 @@
Added:
- DeepL translation support free/pro keys
Changed:
- Hide buttons for media when editing
Fixed:
- GIF loaded as static images
- Suggested accounts cannot be followed

View file

@ -1,10 +0,0 @@
Changed:
- Hidden media smaller with preview images
Fixed:
- Issue with Media for Android 11+
- Crash when not setting a translation key
- Fix DeepL for API pro
- Crash when visiting a profile with a lot of media
- Home muted accounts not working without filters
- Animated custom emoji not displayed

View file

@ -1,14 +0,0 @@
Added:
- Allow to enable extra features in Settings
- Customizable settings for extra features
- Support quotes, reactions with messages
- Support text format (html, markdown, etc.) when composing
Changed:
- Context menu when long pressing a link
- Display bookmark and translate buttons are now per account
Fixed:
- CW not working with media
- Media not displayed for older instances
- Some crashes

View file

@ -1,10 +0,0 @@
Added:
- Add Bubble timeline support in extra-features with filters
- Allow to display public profiles by default to get all messages (Settings > Interface)
Changed:
- Full rework on links in messages (also mentions and tags)
Fixed:
- Spoiler text when editing
- Fix watermarks

View file

@ -1,5 +0,0 @@
Added:
- Glitch: Allow to post messages locally (Can be turned off in Settings)
Fixed:
- Crashes

View file

@ -3,19 +3,9 @@ CONTRIBUTING
### Localizations:
Fedilab works only with [Weblate](https://hosted.weblate.org/projects/fedilab), which offers nice
Fedilab works only with [Weblate]https://hosted.weblate.org/projects/fedilab), which offers nice
tools for helping in translations. New translations will be automatically merged in a branch.
If you're submiting a merge request and your work adds new strings to the app, make sure they only
exist in the default strings.xml file (res/values/strings.xml). If you add or modify strings of
other languages, it will interfere with weblate's translations.
### Issues and Reports:
Before creating an issue please take a moment and search the repository issues to avoid duplicates.
For bug reports, please provide as much details as possible to better debug the problem. The
important part is how to reproduce the bug and steps to reproduce it.
### Pull Requests
Please target the develop branch and not the main branch.
other languages, it will interfere with weblate's translations.

View file

@ -1,46 +1,23 @@
[![Translation status](https://hosted.weblate.org/widgets/fedilab/-/strings/svg-badge.svg)](https://hosted.weblate.org/engage/fedilab/)
&nbsp;&nbsp;&nbsp;[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
<img src="src/fdroid/fastlane/metadata/android/en/images/icon.png" width="100"/>
# Fedilab
A multi-accounts client for Mastodon, Pleroma, Friendica and Pixelfed
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0)
[![Weblate project translated](https://img.shields.io/weblate/progress/fedilab?server=https%3A%2F%2Fhosted.weblate.org&style=for-the-badge)](https://hosted.weblate.org/engage/fedilab/)
[![F-Droid Version](https://img.shields.io/f-droid/v/fr.gouv.etalab.mastodon?label=F-Droid&style=for-the-badge)](https://f-droid.org/app/fr.gouv.etalab.mastodon)
[![Liberapay patrons](https://img.shields.io/liberapay/patrons/tom79?label=Liberapay&style=for-the-badge)](https://liberapay.com/tom79/donate)
[![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/fedilab?label=Open%20Collective&style=for-the-badge)](https://opencollective.com/fedilab)
## Screenshots
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/1.png" width="150"/>
&nbsp;&nbsp;
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/2.png" width="150"/>
&nbsp;&nbsp;
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/4.png" width="150"/>
&nbsp;&nbsp;
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/7.png" width="150"/>
## Download
[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/app/fr.gouv.etalab.mastodon)&nbsp;&nbsp;[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.android)
## Translate
- [Weblate](https://hosted.weblate.org/engage/fedilab/)
# Fedilab is a multi-accounts client for Mastodon, Pleroma, Peertube, GNU Social, Friendica and Pixelfed
## Donate
- [Liberapay](https://liberapay.com/tom79/donate)
- [Open Collective](https://opencollective.com/fedilab)
- [More...](https://fedilab.app/page/donations/)
[<img alt="Donate using Liberapay" src="https://img.shields.io/liberapay/patrons/tom79.svg?logo=liberapay"/>](https://liberapay.com/tom79/donate)
## Download
[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.android)
&nbsp;&nbsp;[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/app/fr.gouv.etalab.mastodon)
## Resources
- [Wiki](https://wiki.fedilab.app)
- [Releases + Changelogs](https://codeberg.org/tom79/Fedilab/releases)
[WIKI](https://fedilab.app/wiki/home/)
## Contact
- Fedi:<br>[toot.fedilab.app/@apps](https://toot.fedilab.app/@apps)
[Release notes](https://framagit.org/tom79/fedilab/tags)
Lead developer: [toot.fedilab.app/@apps](https://toot.fedilab.app/@apps)

View file

@ -1,20 +1,16 @@
import java.util.regex.Matcher
import java.util.regex.Pattern
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'androidx.navigation.safeargs.kotlin'
}
def flavor
android {
compileSdk 34
compileSdk 31
defaultConfig {
minSdk 21
targetSdk 34
versionCode 534
versionName "3.33.1"
targetSdk 31
versionCode 396
versionName "3.0.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
flavorDimensions "default"
@ -23,15 +19,10 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
applicationIdSuffix '.debug'
pseudoLocalesEnabled true
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
productFlavors {
fdroid {
@ -47,11 +38,16 @@ android {
flavor = "playstore"
}
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
buildFeatures {
viewBinding true
}
sourceSets {
playstore {
manifest.srcFile "src/playstore/AndroidManifest.xml"
java.srcDirs = ['src/main/java', 'src/playstore/java']
res.srcDirs = ['src/main/res', 'src/playstore/res']
}
@ -59,39 +55,12 @@ android {
java.srcDirs = ['src/main/java', 'src/fdroid/java']
res.srcDirs = ['src/main/res', 'src/fdroid/res']
}
main {
res.srcDirs = [
'src/main/res/layouts/mastodon',
'src/main/res/layouts/peertube',
'src/main/res/layouts',
'src/main/res/drawables/mastodon',
'src/main/res/drawables/peertube',
'src/main/res/drawables',
'src/main/res/menus/mastodon',
'src/main/res/menus/peertube',
'src/main/res/menus',
'src/main/res/values',
'src/main/res'
]
}
}
configurations {
cleanedAnnotations
implementation.exclude group: 'org.jetbrains', module: 'annotations'
all {
exclude group: 'androidx.lifecycle', module: 'lifecycle-viewmodel-ktx'
}
}
namespace 'app.fedilab.android'
lint {
abortOnError false
checkReleaseBuilds false
}
buildToolsVersion '35.0.0'
}
allprojects {
repositories {
@ -100,140 +69,63 @@ allprojects {
}
}
dependencies {
implementation 'org.unifiedpush.android:connector:3.0.9'
playstoreImplementation('org.unifiedpush.android:embedded-fcm-distributor:3.0.0')
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
implementation "com.google.code.gson:gson:2.10.1"
implementation project(':autoimageslider')
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "com.google.code.gson:gson:2.8.6"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.preference:preference:1.2.1'
implementation 'androidx.preference:preference:1.2.0'
implementation "org.conscrypt:conscrypt-android:2.5.2"
implementation 'com.github.evozi:Cyanea:1.0.7'
implementation 'com.vanniktech:emoji-one:0.6.0'
implementation 'com.github.GrenderG:Toasty:1.5.2'
implementation "com.github.bumptech.glide:glide:4.14.2"
implementation "com.github.bumptech.glide:okhttp3-integration:4.14.2"
implementation("com.github.bumptech.glide:recyclerview-integration:4.14.2") {
implementation 'org.framagit.tom79:SparkButton:1.0.13'
implementation "com.github.bumptech.glide:glide:4.12.0"
implementation 'com.github.mergehez:ArgPlayer:v3.1'
implementation ("com.github.bumptech.glide:recyclerview-integration:4.12.0") {
// Excludes the support library because it's already included by Glide.
transitive = false
}
implementation "org.jsoup:jsoup:1.18.1"
implementation 'com.github.mergehez:ArgPlayer:v3.1'
implementation project(':autoimageslider')
implementation project(path: ':mytransl')
implementation project(path: ':ratethisapp')
implementation project(path: ':sparkbutton')
implementation project(path: ':colorPicker')
implementation project(path: ':mathjaxandroid')
implementation project(path: ':doubletapplayerview')
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation("com.vanniktech:android-image-cropper:4.3.3")
implementation project(path: ':cropper')
annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"
implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:3.0.5'
implementation 'androidx.media3:media3-exoplayer-hls:1.2.1'
implementation "androidx.media3:media3-exoplayer:1.2.1"
implementation "androidx.media3:media3-exoplayer-dash:1.2.1"
implementation "androidx.media3:media3-ui:1.2.1"
implementation "androidx.media3:media3-session:1.2.1"
implementation "androidx.viewpager2:viewpager2:1.1.0"
implementation 'com.github.penfeizhou.android.animation:apng:2.22.0'
implementation 'com.github.penfeizhou.android.animation:gif:2.22.0'
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'com.github.piasy:rxandroidaudio:1.7.0'
implementation 'com.github.piasy:AudioProcessor:1.7.0'
implementation "androidx.work:work-runtime:2.9.0"
implementation "androidx.work:work-runtime:2.7.1"
implementation 'app.futured.hauler:hauler:5.0.0'
implementation "com.github.chrisbanes:PhotoView:2.3.0"
implementation "ch.acra:acra-mail:5.11.3"
implementation "ch.acra:acra-limiter:5.11.3"
implementation "ch.acra:acra-dialog:5.11.3"
implementation "ch.acra:acra-mail:5.9.3"
implementation "ch.acra:acra-limiter:5.9.3"
implementation "ch.acra:acra-dialog:5.9.3"
implementation "com.madgag.spongycastle:bctls-jdk15on:1.58.0.0"
implementation 'com.github.UnifiedPush:android-connector:2.0.0'
// implementation 'com.github.UnifiedPush:android-foss_embedded_fcm_distributor:1.0.0-beta1'
playstoreImplementation 'com.github.UnifiedPush:android-embedded_fcm_distributor:1.1.0'
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.8.7'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.8.7'
implementation 'androidx.navigation:navigation-fragment:2.8.7'
implementation 'androidx.navigation:navigation-ui:2.8.7'
implementation 'androidx.lifecycle:lifecycle-livedata:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.4.1'
implementation 'androidx.navigation:navigation-fragment:2.4.2'
implementation 'androidx.navigation:navigation-ui:2.4.2'
testImplementation 'junit:junit:'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
implementation 'com.r0adkll:slidableactivity:2.1.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
implementation 'androidx.vectordrawable:vectordrawable:1.2.0'
implementation "androidx.fragment:fragment:1.8.6"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.browser:browser:1.8.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'com.github.amoskorir:avatarimagegenerator:1.5.0'
implementation "com.github.mabbas007:TagsEditText:1.0.5"
implementation "net.gotev:uploadservice:4.9.2"
implementation "net.gotev:uploadservice-okhttp:4.9.2"
implementation 'androidx.media:media:1.7.0'
implementation 'com.github.mancj:MaterialSearchBar:0.8.5'
implementation 'com.github.androidmads:QRGenerator:1.0.1'
implementation 'io.noties.markwon:core:4.6.2'
implementation 'io.noties.markwon:ext-tables:4.6.2'
implementation 'io.noties.markwon:syntax-highlight:4.6.2'
implementation 'io.noties.markwon:ext-strikethrough:4.6.2'
implementation 'io.noties.markwon:inline-parser:4.6.2'
annotationProcessor 'io.noties:prism4j-bundler:2.0.0'
//************ CAST **************///
//---> Google libs (google_full)
playstoreImplementation "com.google.android.gms:play-services-cast-tv:21.1.1"
playstoreImplementation "com.google.android.gms:play-services-cast:22.0.0"
playstoreImplementation "androidx.mediarouter:mediarouter:1.7.0"
playstoreImplementation 'com.google.android.gms:play-services-cast-framework:22.0.0'
//----> Other flavors
fdroidImplementation 'su.litvak.chromecast:api-v2:0.11.3'
fdroidImplementation 'com.fasterxml.jackson.core:jackson-core:2.12.0'
fdroidImplementation 'org.slf4j:slf4j-simple:1.7.30'
}
def getCurrentFlavor() {
Gradle gradle = getGradle()
String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
println("tskReqStr:" +tskReqStr)
Pattern pattern
if( tskReqStr.contains( "assemble" ) ) // to run ./gradlew assembleRelease to build APK
pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
else if( tskReqStr.contains( "bundle" ) ) // to run ./gradlew bundleRelease to build .aab
pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
else
pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
Matcher matcher = pattern.matcher( tskReqStr )
println(tskReqStr)
if( matcher.find() )
return matcher.group(1).toLowerCase()
else
{
println "NO MATCH FOUND"
return ""
}
}
println("Flavor: ${getCurrentFlavor()}")
if ( getCurrentFlavor() == "playstore" ){
apply plugin: 'com.google.gms.google-services'
}

View file

@ -1,15 +1,15 @@
package app.fedilab.android;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*

View file

@ -1,68 +0,0 @@
{
"project_info": {
"project_number": "479837431022",
"project_id": "pc-api-4835782490875392372-140",
"storage_bucket": "pc-api-4835782490875392372-140.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:479837431022:android:1102a97a55202beb547fff",
"android_client_info": {
"package_name": "app.fedilab.android"
}
},
"oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCklTEEgLUxy__0Vzcr5_H179kYPXGjmGo"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:479837431022:android:529536f519b8f4ce547fff",
"android_client_info": {
"package_name": "app.fedilab.android.debug"
}
},
"oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCklTEEgLUxy__0Vzcr5_H179kYPXGjmGo"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "479837431022-mettpakdcso72c35djvikfc57l4i7n53.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -1,3 +0,0 @@
<resources>
<string name="app_name" translatable="false">Fedilab dbg</string>
</resources>

View file

@ -1,19 +0,0 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<shortcut
android:shortcutId="compose"
android:enabled="true"
android:icon="@drawable/ic_baseline_add_comment_24"
android:shortcutShortLabel="@string/compose_shortcut_short_label1"
tools:targetApi="n_mr1">
<intent
android:action="app.fedilab.android.shorcut.compose"
android:targetClass="app.fedilab.android.activities.MainActivity"
android:targetPackage="fr.gouv.etalab.mastodon.debug" />
<categories android:name="android.shortcut.conversation" />
<capability-binding android:key="actions.intent.CREATE_MESSAGE" />
</shortcut>
</shortcuts>

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="my_images"
path="Android/data/fr.gouv.etalab.mastodon.debug/files/Pictures" />
<cache-path
name="*"
path="." />
</paths>

View file

@ -1,215 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2023 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.peertube.helper.Helper.CAST_ID;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.MimeTypeMap;
import androidx.appcompat.app.AlertDialog;
import androidx.media3.common.Player;
import androidx.media3.exoplayer.ExoPlayer;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.security.GeneralSecurityException;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityPeertubeBinding;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.peertube.client.data.VideoData;
import app.fedilab.android.peertube.helper.Helper;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.MediaStatus;
import su.litvak.chromecast.api.v2.Status;
public class BasePeertubeActivity extends BaseBarActivity {
protected ActivityPeertubeBinding binding;
protected VideoData.Video peertube;
protected ExoPlayer player;
protected String videoURL;
protected String subtitlesStr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityPeertubeBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
binding.minController.castPlay.setOnClickListener(v -> {
binding.minController.castLoader.setVisibility(View.VISIBLE);
if (PeertubeBaseMainActivity.chromeCast != null) {
new Thread(() -> {
try {
int icon = -1;
if (PeertubeBaseMainActivity.chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
PeertubeBaseMainActivity.chromeCast.pause();
icon = R.drawable.ic_baseline_play_arrow_32;
} else if (PeertubeBaseMainActivity.chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PAUSED) {
PeertubeBaseMainActivity.chromeCast.play();
icon = R.drawable.ic_baseline_pause_32;
}
if (icon != -1) {
Handler mainHandler = new Handler(Looper.getMainLooper());
int finalIcon = icon;
Runnable myRunnable = () -> binding.minController.castPlay.setImageResource(finalIcon);
mainHandler.post(myRunnable);
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> binding.minController.castLoader.setVisibility(View.GONE);
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_cast) {
if (PeertubeBaseMainActivity.chromeCasts != null && PeertubeBaseMainActivity.chromeCasts.size() > 0) {
String[] chromecast_choice = new String[PeertubeBaseMainActivity.chromeCasts.size()];
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(this);
alt_bld.setTitle(R.string.chromecast_choice);
int i = 0;
for (ChromeCast cc : PeertubeBaseMainActivity.chromeCasts) {
chromecast_choice[i] = cc.getTitle();
i++;
}
i = 0;
for (ChromeCast cc : PeertubeBaseMainActivity.chromeCasts) {
if (PeertubeBaseMainActivity.chromecastActivated && cc.isConnected()) {
break;
}
i++;
}
alt_bld.setSingleChoiceItems(chromecast_choice, i, (dialog, position) -> {
PeertubeBaseMainActivity.chromeCast = PeertubeBaseMainActivity.chromeCasts.get(position);
new Thread(() -> {
if (PeertubeBaseMainActivity.chromeCast != null) {
Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
Bundle b = new Bundle();
if (PeertubeBaseMainActivity.chromecastActivated) {
b.putInt("displayed", 0);
intentBC.putExtras(b);
intentBC.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentBC);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
binding.doubleTapPlayerView.setVisibility(View.VISIBLE);
binding.minController.castMiniController.setVisibility(View.GONE);
};
mainHandler.post(myRunnable);
} else {
b.putInt("displayed", 1);
b.putSerializable("castedTube", peertube);
intentBC.putExtras(b);
intentBC.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentBC);
try {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
invalidateOptionsMenu();
binding.minController.castLoader.setVisibility(View.VISIBLE);
player.setPlayWhenReady(false);
binding.doubleTapPlayerView.setVisibility(View.GONE);
binding.minController.castMiniController.setVisibility(View.VISIBLE);
dialog.dismiss();
if (videoURL != null) {
if (player != null && player.getCurrentPosition() > 0) {
videoURL += "?start=" + (player.getCurrentPosition() / 1000);
}
}
};
mainHandler.post(myRunnable);
if (!PeertubeBaseMainActivity.chromeCast.isConnected()) {
PeertubeBaseMainActivity.chromeCast.connect();
}
myRunnable = this::invalidateOptionsMenu;
mainHandler.post(myRunnable);
Status status = PeertubeBaseMainActivity.chromeCast.getStatus();
if (PeertubeBaseMainActivity.chromeCast.isAppAvailable(CAST_ID) && !status.isAppRunning(CAST_ID)) {
PeertubeBaseMainActivity.chromeCast.launchApp(CAST_ID);
}
if (videoURL != null) {
String mime = MimeTypeMap.getFileExtensionFromUrl(videoURL);
PeertubeBaseMainActivity.chromeCast.setRequestTimeout(60000);
PeertubeBaseMainActivity.chromeCast.load(peertube.getTitle(), null, videoURL, mime);
PeertubeBaseMainActivity.chromeCast.play();
binding.minController.castPlay.setImageResource(R.drawable.ic_baseline_pause_32);
}
myRunnable = () -> binding.minController.castLoader.setVisibility(View.GONE);
mainHandler.post(myRunnable);
} catch (IOException | GeneralSecurityException e) {
e.printStackTrace();
}
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
invalidateOptionsMenu();
dialog.dismiss();
};
mainHandler.post(myRunnable);
}
}).start();
});
alt_bld.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
}
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
getMenuInflater().inflate(R.menu.video_menu, menu);
MenuItem castItem = menu.findItem(R.id.action_cast);
if (PeertubeBaseMainActivity.chromeCasts != null && PeertubeBaseMainActivity.chromeCasts.size() > 0) {
castItem.setVisible(true);
if (PeertubeBaseMainActivity.chromeCast != null && PeertubeBaseMainActivity.chromeCast.isConnected()) {
castItem.setIcon(R.drawable.ic_baseline_cast_connected_24);
} else {
castItem.setIcon(R.drawable.ic_baseline_cast_24);
}
}
return true;
}
}

View file

@ -1,270 +0,0 @@
package app.fedilab.android.activities;
/* Copyright 2023 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityMainPeertubeBinding;
import app.fedilab.android.mastodon.activities.BaseActivity;
import app.fedilab.android.peertube.client.data.VideoData;
import app.fedilab.android.peertube.helper.Helper;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.ChromeCasts;
import su.litvak.chromecast.api.v2.ChromeCastsListener;
import su.litvak.chromecast.api.v2.MediaStatus;
public abstract class PeertubeBaseMainActivity extends BaseActivity implements ChromeCastsListener {
public static List<ChromeCast> chromeCasts;
public static ChromeCast chromeCast;
public static boolean chromecastActivated = false;
protected ActivityMainPeertubeBinding parentBinding;
private BroadcastReceiver manage_chromecast;
private VideoData.Video castedTube;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
parentBinding = ActivityMainPeertubeBinding.inflate(getLayoutInflater());
View view = parentBinding.getRoot();
setContentView(view);
ChromeCastsListener chromeCastsListener = this;
ChromeCasts.registerListener(chromeCastsListener);
parentBinding.castClose.setOnClickListener(v -> {
Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
Bundle b = new Bundle();
b.putInt("displayed", 0);
intentBC.putExtras(b);
intentBC.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentBC);
});
parentBinding.castTogglePlay.setOnClickListener(v -> {
if (chromeCast != null) {
new Thread(() -> {
try {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> parentBinding.castTogglePlay.setVisibility(View.GONE);
mainHandler.post(myRunnable);
int icon = -1;
if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
chromeCast.pause();
icon = R.drawable.ic_baseline_play_arrow_32;
} else if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PAUSED) {
chromeCast.play();
icon = R.drawable.ic_baseline_pause_32;
}
if (icon != -1) {
int finalIcon = icon;
myRunnable = () -> parentBinding.castTogglePlay.setImageResource(finalIcon);
mainHandler.post(myRunnable);
}
myRunnable = () -> parentBinding.castTogglePlay.setVisibility(View.VISIBLE);
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
});
manage_chromecast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
assert b != null;
int state = b.getInt("state_asked", -1);
int displayed = b.getInt("displayed", -1);
castedTube = (VideoData.Video) b.getSerializable("castedTube");
if (state == 1) {
discoverCast();
} else if (state == 0) {
new Thread(() -> {
try {
if (chromeCast != null) {
chromeCast.stopApp();
chromeCast.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
if (displayed == 1) {
chromecastActivated = true;
if (castedTube != null) {
parentBinding.castInfo.setVisibility(View.VISIBLE);
Helper.loadGiF(PeertubeBaseMainActivity.this, castedTube.getThumbnailPath(), parentBinding.castView);
parentBinding.castTitle.setText(castedTube.getTitle());
parentBinding.castDescription.setText(castedTube.getDescription());
}
} else if (displayed == 0) {
chromecastActivated = false;
parentBinding.castInfo.setVisibility(View.GONE);
new Thread(() -> {
try {
if (chromeCast != null) {
chromeCast.stopApp();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
};
ContextCompat.registerReceiver(PeertubeBaseMainActivity.this, manage_chromecast, new IntentFilter(Helper.RECEIVE_CAST_SETTINGS), ContextCompat.RECEIVER_NOT_EXPORTED);
}
@Override
public void newChromeCastDiscovered(ChromeCast chromeCast) {
if (chromeCasts == null) {
chromeCasts = new ArrayList<>();
chromeCasts.add(chromeCast);
} else {
boolean canBeAdded = true;
for (ChromeCast cast : chromeCasts) {
if (cast.getName().compareTo(chromeCast.getName()) == 0) {
canBeAdded = false;
break;
}
}
if (canBeAdded) {
chromeCasts.add(chromeCast);
}
}
try {
if (chromeCast.isAppRunning(Helper.CAST_ID) && chromeCast.getMediaStatus() != null && chromeCast.getMediaStatus().playerState != null) {
if (parentBinding.castInfo.getVisibility() == View.GONE) {
parentBinding.castInfo.setVisibility(View.VISIBLE);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void chromeCastRemoved(ChromeCast chromeCast) {
}
@Override
public void onDestroy() {
super.onDestroy();
ChromeCasts.unregisterListener(this);
if (manage_chromecast != null) {
try {
unregisterReceiver(manage_chromecast);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
new Thread(() -> {
if (chromeCasts != null && chromeCasts.size() > 0) {
for (ChromeCast cast : chromeCasts) {
try {
cast.stopApp();
cast.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
if (chromeCasts != null) {
chromeCasts = null;
}
if (chromeCast != null) {
chromeCast = null;
}
}
//Method for discovering cast devices
public void discoverCast() {
new Thread(() -> {
if (chromeCasts != null) {
for (ChromeCast cast : chromeCasts) {
try {
cast.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
chromeCasts = null;
}
chromeCasts = new ArrayList<>();
try {
List<NetworkInterface> interfaces;
interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface ni : interfaces) {
if ((!ni.isLoopback()) && ni.isUp() && (ni.getName().equals("wlan0"))) {
Enumeration<InetAddress> inetAddressEnumeration = ni.getInetAddresses();
while (inetAddressEnumeration.hasMoreElements()) {
InetAddress inetAddress = inetAddressEnumeration.nextElement();
ChromeCasts.restartDiscovery(inetAddress);
int tryFind = 0;
while (ChromeCasts.get().isEmpty() && tryFind < 5) {
try {
//noinspection BusyWait
Thread.sleep(1000);
tryFind++;
} catch (InterruptedException ignored) {
}
}
}
}
}
ChromeCasts.stopDiscovery();
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = this::invalidateOptionsMenu;
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/castMiniController"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:visibility="gone">
<ImageView
android:id="@+id/cast_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/play"
android:src="@drawable/ic_baseline_play_arrow_32"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cast_loader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/cast_loader_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/please_wait"
android:textColor="?colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/cast_loader_small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/cast_loader_small"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_gravity="center"
android:layout_marginStart="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/cast_loader_text"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_cast"
android:icon="@drawable/ic_baseline_cast_24"
android:title="@string/cast"
android:visible="false"
app:showAsAction="always" />
</menu>

View file

@ -1,19 +0,0 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<shortcut
android:shortcutId="compose"
android:enabled="true"
android:icon="@drawable/ic_baseline_add_comment_24"
android:shortcutShortLabel="@string/compose_shortcut_short_label1"
tools:targetApi="n_mr1">
<intent
android:action="app.fedilab.android.shorcut.compose"
android:targetClass="app.fedilab.android.activities.MainActivity"
android:targetPackage="fr.gouv.etalab.mastodon" />
<categories android:name="android.shortcut.conversation" />
<capability-binding android:key="actions.intent.CREATE_MESSAGE" />
</shortcut>
</shortcuts>

View file

@ -1,47 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools"
package="app.fedilab.android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<application
android:name="app.fedilab.android.MainApplication"
android:name=".MainApplication"
tools:replace="android:allowBackup"
android:allowBackup="false"
android:dataExtractionRules="@xml/extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:configChanges="orientation|screenSize"
android:icon="@mipmap/ic_launcher_bubbles"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_bubbles_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
tools:replace="android:allowBackup">
android:label="@string/app_name"
android:configChanges="orientation|screenSize"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppThemeDark"
>
<activity
android:name=".activities.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize"
android:configChanges="orientation|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
@ -61,33 +50,15 @@
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- The app is a good candidate for URL in https://domain.name/@xxxxxx-->
<!-- It should cover every URLs for statuses but some others not related to mastodon matching this scheme -->
<data
android:host="*"
android:pathPrefix="/@"
android:scheme="https" />
<data
android:host="*"
android:pathPrefix="/notes"
android:scheme="https" />
</intent-filter>
</activity>
<activity
android:exported="true"
android:name=".activities.LoginActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@ -96,74 +67,63 @@
android:scheme="fedilab" />
</intent-filter>
</activity>
<activity
android:name=".mastodon.activities.StatusHistoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/status_history"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ContextActivity"
android:name=".activities.WebviewConnectActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.DirectMessageActivity"
android:name=".activities.ContextActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.DraftActivity"
android:name=".activities.DraftActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.imageeditor.EditImageActivity"
android:name=".imageeditor.EditImageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.ComposeActivity"
android:name=".activities.ComposeActivity"
android:configChanges="orientation|screenSize"
android:label="@string/compose" />
<activity
android:name=".mastodon.activities.StatusInfoActivity"
android:name=".activities.StatusInfoActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.FollowRequestActivity"
android:name=".activities.FollowRequestActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.ProfileActivity"
android:name=".activities.WebviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.ProfileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".mastodon.activities.admin.AdminAccountActivity"
android:name=".activities.AdminAccountActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".mastodon.activities.AccountReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/report"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ScheduledActivity"
android:name=".activities.ScheduledActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/scheduled" />
<activity
android:name="com.canhub.cropper.CropImageActivity"
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />
<service
android:name=".services.PostMessageService"
android:label="@string/post_message" />
<activity
android:name=".mastodon.activities.SearchResultTabActivity"
android:name=".activities.SearchResultTabActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/search"
android:theme="@style/AppThemeBar" />
android:theme="@style/AppThemeBar"
android:label="@string/search" />
<activity
android:name=".mastodon.activities.TrendsActivity"
android:name=".activities.TrendsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/trending"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ReorderTimelinesActivity"
android:name=".activities.ReorderTimelinesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/reorder_timelines"
android:theme="@style/AppThemeBar" />
@ -172,107 +132,86 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.TimelineActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.CheckHomeCacheActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/home_cache"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminDomainBlockActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/blocked_domains"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SuggestionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Suggestions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.DirectoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Directory"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.PartnerShipActivity"
android:name=".activities.PartnerShipActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ActionActivity"
android:name=".activities.ActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/interactions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminActionActivity"
android:name=".activities.AdminActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/administration"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.MastodonListActivity"
android:name=".activities.MastodonListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_lists"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.FollowedTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/followed_tags"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SettingsActivity"
android:name=".activities.SettingsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/settings"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.HashTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.AnnouncementActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.MediaActivity"
android:hardwareAccelerated="true"
android:name=".activities.InstanceActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/Transparent" />
android:label="@string/action_about_instance"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.InstanceProfileActivity"
android:excludeFromRecents="true"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.ProxyActivity"
android:excludeFromRecents="true"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.HashTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.AnnouncementActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".activities.MediaActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/TransparentDark" />
<activity
android:name=".mastodon.activities.ReportActivity"
android:theme="@style/AppThemeBar"
android:name=".activities.InstanceHealthActivity"
android:excludeFromRecents="true"
android:theme="@style/DialogDark" />
<activity
android:name=".activities.ReportActivity"
android:theme="@style/AppThemeBarDark"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.CustomSharingActivity"
android:name=".activities.CustomSharingActivity"
android:label="@string/settings_title_custom_sharing"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
android:windowSoftInputMode="stateVisible"
android:theme="@style/AppThemeBarDark" />
<activity
android:name=".mastodon.activities.FilterActivity"
android:name=".activities.FilterActivity"
android:label="@string/filters"
android:theme="@style/AppThemeBar"
android:theme="@style/AppThemeBarDark"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.EditProfileActivity"
android:name=".activities.EditProfileActivity"
android:label="@string/edit_profile"
android:theme="@style/AppThemeBar"
android:theme="@style/AppThemeBarDark"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.CacheActivity"
android:name=".activities.CacheActivity"
android:label="@string/action_cache"
android:theme="@style/AppThemeBar" />
<activity android:name=".activities.WebActivityPub"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="web+ap" />
</intent-filter>
</activity>
android:theme="@style/AppThemeBarDark" />
<provider
android:name="androidx.core.content.FileProvider"
@ -285,476 +224,24 @@
</provider>
<receiver
android:name=".mastodon.broadcastreceiver.ToastMessage"
android:name=".broadcastreceiver.ToastMessage"
android:exported="false">
<intent-filter>
<action android:name="RECEIVE_TOAST_MESSAGE" />
</intent-filter>
</receiver>
<service android:name=".mastodon.services.PushServiceImpl"
android:exported="false">
<intent-filter>
<action android:name="org.unifiedpush.android.connector.PUSH_EVENT"/>
</intent-filter>
</service>
<activity
android:name=".peertube.activities.PeertubeMainActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.PeertubeActivity"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
tools:targetApi="n" />
<activity
android:name=".peertube.activities.PeertubeEditUploadActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowChannelActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.MyAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SearchActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllLocalPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.VideosTimelineActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SepiaSearchActivity"
android:configChanges="orientation|screenSize"
android:label="@string/sepia_search"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ManageInstancesActivity"
android:configChanges="orientation|screenSize"
android:label="@string/instances_picker"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.WebviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.LoginActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="backtotubelab"
android:scheme="tubelab" />
</intent-filter>
</activity>
<activity
android:name=".peertube.activities.SettingsActivity"
android:configChanges="orientation|screenSize"
android:label="@string/settings"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PeertubeUploadActivity"
android:configChanges="orientation|screenSize"
android:label="@string/upload_video"
android:windowSoftInputMode="stateAlwaysHidden" />
<service
android:name=".peertube.services.RetrieveInfoService"
android:foregroundServiceType="dataSync"
android:exported="false" />
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
<!-- ============ -->
<!-- CUSTOM ICONS -->
<!-- ============ -->
<activity-alias
android:name=".activities.MainActivity.Bubbles"
<receiver
android:name=".services.CustomReceiver"
android:enabled="true"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles"
android:roundIcon="@mipmap/ic_launcher_bubbles_round"
android:targetActivity=".activities.MainActivity">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="org.unifiedpush.android.connector.MESSAGE" />
<action android:name="org.unifiedpush.android.connector.UNREGISTERED" />
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT" />
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED" />
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BubblesUA"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles_ua"
android:roundIcon="@mipmap/ic_launcher_bubbles_ua_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BubblesPeaGreen"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles_pea_green"
android:roundIcon="@mipmap/ic_launcher_bubbles_pea_green_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BubblesPride"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles_pride"
android:roundIcon="@mipmap/ic_launcher_bubbles_pride_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BubblesPink"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles_pink"
android:roundIcon="@mipmap/ic_launcher_bubbles_pink_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BubblesPirate"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_bubbles_pirate"
android:roundIcon="@mipmap/ic_launcher_bubbles_pirate_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Fediverse"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_fediverse"
android:roundIcon="@mipmap/ic_launcher_fediverse_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Hero"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_hero"
android:roundIcon="@mipmap/ic_launcher_hero_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Atom"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_atom"
android:roundIcon="@mipmap/ic_launcher_atom_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.BrainCrash"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_crash"
android:roundIcon="@mipmap/ic_launcher_crash_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Mastalab"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_mastalab"
android:roundIcon="@mipmap/ic_launcher_mastalab_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Leaf"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_leaf"
android:roundIcon="@mipmap/ic_launcher_leaf_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Offset"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_offset"
android:roundIcon="@mipmap/ic_launcher_offset_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Jungle"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_jungle"
android:roundIcon="@mipmap/ic_launcher_jungle_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Confetti"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_confetti"
android:roundIcon="@mipmap/ic_launcher_confetti_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Spaghetti"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_spaghetti"
android:roundIcon="@mipmap/ic_launcher_spaghetti_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Warm"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_warm"
android:roundIcon="@mipmap/ic_launcher_warm_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Purple1"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_purple_1"
android:roundIcon="@mipmap/ic_launcher_purple_1_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Purple2"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_purple_2"
android:roundIcon="@mipmap/ic_launcher_purple_2_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.YellowHeadedRedBubble"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_yellow_headed_red_bubble"
android:roundIcon="@mipmap/ic_launcher_yellow_headed_red_bubble_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Mosaic"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_mosaic"
android:roundIcon="@mipmap/ic_launcher_mosaic_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
</receiver>
</application>
</manifest>
</manifest>

View file

@ -1,20 +0,0 @@
{
"1": "Music",
"2": "Films",
"3": "Vehicles",
"4": "Art",
"5": "Sports",
"6": "Travels",
"7": "Gaming",
"8": "People",
"9": "Comedy",
"10": "Entertainment",
"11": "News & Politics",
"12": "How To",
"13": "Education",
"14": "Activism",
"15": "Science & Technology",
"16": "Animals",
"17": "Kids",
"18": "Food"
}

View file

@ -1,199 +0,0 @@
{
"aa": "Afar",
"ab": "Abkhazian",
"af": "Afrikaans",
"ak": "Akan",
"am": "Amharic",
"ar": "Arabic",
"an": "Aragonese",
"ase": "American Sign Language",
"as": "Assamese",
"av": "Avaric",
"avk": "Kotava",
"ay": "Aymara",
"az": "Azerbaijani",
"ba": "Bashkir",
"bm": "Bambara",
"be": "Belarusian",
"bn": "Bengali",
"bfi": "British Sign Language",
"bi": "Bislama",
"bo": "Tibetan",
"bs": "Bosnian",
"br": "Breton",
"bg": "Bulgarian",
"bzs": "Brazilian Sign Language",
"ca": "Catalan",
"cs": "Czech",
"ch": "Chamorro",
"ce": "Chechen",
"cv": "Chuvash",
"kw": "Cornish",
"co": "Corsican",
"cr": "Cree",
"cse": "Czech Sign Language",
"csl": "Chinese Sign Language",
"cy": "Welsh",
"da": "Danish",
"de": "German",
"dv": "Dhivehi",
"dsl": "Danish Sign Language",
"dz": "Dzongkha",
"el": "Greek",
"en": "English",
"eo": "Esperanto",
"et": "Estonian",
"eu": "Basque",
"ee": "Ewe",
"fo": "Faroese",
"fa": "Persian",
"fj": "Fijian",
"fi": "Finnish",
"fr": "French",
"fy": "Western Frisian",
"fsl": "French Sign Language",
"ff": "Fulah",
"gd": "Scottish Gaelic",
"ga": "Irish",
"gl": "Galician",
"gv": "Manx",
"gn": "Guarani",
"gsg": "German Sign Language",
"gu": "Gujarati",
"ht": "Haitian",
"ha": "Hausa",
"sh": "Serbo-Croatian",
"he": "Hebrew",
"hz": "Herero",
"hi": "Hindi",
"ho": "Hiri Motu",
"hr": "Croatian",
"hu": "Hungarian",
"hy": "Armenian",
"ig": "Igbo",
"ii": "Sichuan Yi",
"iu": "Inuktitut",
"id": "Indonesian",
"ik": "Inupiaq",
"is": "Icelandic",
"it": "Italian",
"jv": "Javanese",
"jbo": "Lojban",
"ja": "Japanese",
"jsl": "Japanese Sign Language",
"kab": "Kabyle",
"kl": "Kalaallisut",
"kn": "Kannada",
"ks": "Kashmiri",
"ka": "Georgian",
"kr": "Kanuri",
"kk": "Kazakh",
"km": "Khmer",
"ki": "Kikuyu",
"rw": "Kinyarwanda",
"ky": "Kirghiz",
"kv": "Komi",
"kg": "Kongo",
"ko": "Korean",
"kj": "Kuanyama",
"ku": "Kurdish",
"lo": "Lao",
"la": "Latin",
"lv": "Latvian",
"li": "Limburgan",
"ln": "Lingala",
"lt": "Lithuanian",
"lb": "Luxembourgish",
"lu": "Luba-Katanga",
"lg": "Ganda",
"mh": "Marshallese",
"ml": "Malayalam",
"mr": "Marathi",
"mk": "Macedonian",
"mg": "Malagasy",
"mt": "Maltese",
"mn": "Mongolian",
"mi": "Maori",
"ms": "Malay (macrolanguage)",
"my": "Burmese",
"na": "Nauru",
"nv": "Navajo",
"nr": "South Ndebele",
"nd": "North Ndebele",
"ng": "Ndonga",
"ne": "Nepali (macrolanguage)",
"nl": "Dutch",
"nn": "Norwegian Nynorsk",
"nb": "Norwegian Bokmål",
"no": "Norwegian",
"ny": "Nyanja",
"oc": "Occitan",
"oj": "Ojibwa",
"or": "Oriya (macrolanguage)",
"om": "Oromo",
"os": "Ossetian",
"pa": "Panjabi",
"pks": "Pakistan Sign Language",
"pl": "Polish",
"pt": "Portuguese",
"ps": "Pushto",
"qu": "Quechua",
"rm": "Romansh",
"ro": "Romanian",
"rsl": "Russian Sign Language",
"rn": "Rundi",
"ru": "Russian",
"sg": "Sango",
"sdl": "Saudi Arabian Sign Language",
"sfs": "South African Sign Language",
"si": "Sinhala",
"sk": "Slovak",
"sl": "Slovenian",
"se": "Northern Sami",
"sm": "Samoan",
"sn": "Shona",
"sd": "Sindhi",
"so": "Somali",
"st": "Southern Sotho",
"es": "Spanish",
"sq": "Albanian",
"sc": "Sardinian",
"sr": "Serbian",
"ss": "Swati",
"su": "Sundanese",
"sw": "Swahili (macrolanguage)",
"sv": "Swedish",
"swl": "Swedish Sign Language",
"ty": "Tahitian",
"ta": "Tamil",
"tt": "Tatar",
"te": "Telugu",
"tg": "Tajik",
"tl": "Tagalog",
"th": "Thai",
"ti": "Tigrinya",
"tlh": "Klingon",
"to": "Tonga (Tonga Islands)",
"tn": "Tswana",
"ts": "Tsonga",
"tk": "Turkmen",
"tr": "Turkish",
"tw": "Twi",
"ug": "Uighur",
"uk": "Ukrainian",
"ur": "Urdu",
"uz": "Uzbek",
"ve": "Venda",
"vi": "Vietnamese",
"wa": "Walloon",
"wo": "Wolof",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"za": "Zhuang",
"zh": "Chinese",
"zu": "Zulu",
"zxx": "No linguistic content",
"zh-Hans": "Simplified Chinese",
"zh-Hant": "Traditional Chinese"
}

View file

@ -1,834 +0,0 @@
[
{
"code": "aa",
"language": "Afaraf"
},
{
"code": "ab",
"language": "аҧсуа бызшәа"
},
{
"code": "ae",
"language": "avesta"
},
{
"code": "af",
"language": "Afrikaans"
},
{
"code": "ak",
"language": "Akan"
},
{
"code": "am",
"language": "አማርኛ"
},
{
"code": "an",
"language": "aragonés"
},
{
"code": "ar",
"language": "اللغة العربية"
},
{
"code": "as",
"language": "অসমীয়া"
},
{
"code": "av",
"language": "авар мацӀ"
},
{
"code": "ay",
"language": "aymar aru"
},
{
"code": "az",
"language": "azərbaycan dili"
},
{
"code": "ba",
"language": "башҡорт теле"
},
{
"code": "be",
"language": "беларуская мова"
},
{
"code": "bg",
"language": "български език"
},
{
"code": "bh",
"language": "भोजपुरी"
},
{
"code": "bi",
"language": "Bislama"
},
{
"code": "bm",
"language": "bamanankan"
},
{
"code": "bn",
"language": "বাংলা"
},
{
"code": "bo",
"language": "བོད་ཡིག"
},
{
"code": "br",
"language": "brezhoneg"
},
{
"code": "bs",
"language": "bosanski jezik"
},
{
"code": "ca",
"language": "Català"
},
{
"code": "ce",
"language": "нохчийн мотт"
},
{
"code": "ch",
"language": "Chamoru"
},
{
"code": "co",
"language": "corsu"
},
{
"code": "cr",
"language": "ᓀᐦᐃᔭᐍᐏᐣ"
},
{
"code": "cs",
"language": "čeština"
},
{
"code": "cu",
"language": "ѩзыкъ словѣньскъ"
},
{
"code": "cv",
"language": "чӑваш чӗлхи"
},
{
"code": "cy",
"language": "Cymraeg"
},
{
"code": "da",
"language": "dansk"
},
{
"code": "de",
"language": "Deutsch"
},
{
"code": "dv",
"language": "Dhivehi"
},
{
"code": "dz",
"language": "རྫོང་ཁ"
},
{
"code": "ee",
"language": "Eʋegbe"
},
{
"code": "el",
"language": "Ελληνικά"
},
{
"code": "en",
"language": "English"
},
{
"code": "eo",
"language": "Esperanto"
},
{
"code": "es",
"language": "Español"
},
{
"code": "et",
"language": "eesti"
},
{
"code": "eu",
"language": "euskara"
},
{
"code": "fa",
"language": "فارسی"
},
{
"code": "ff",
"language": "Fulfulde"
},
{
"code": "fi",
"language": "suomi"
},
{
"code": "fj",
"language": "Vakaviti"
},
{
"code": "fo",
"language": "føroyskt"
},
{
"code": "fr",
"language": "Français"
},
{
"code": "fy",
"language": "Frysk"
},
{
"code": "ga",
"language": "Gaeilge"
},
{
"code": "gd",
"language": "Gàidhlig"
},
{
"code": "gl",
"language": "galego"
},
{
"code": "gu",
"language": "ગુજરાતી"
},
{
"code": "gv",
"language": "Gaelg"
},
{
"code": "ha",
"language": "هَوُسَ"
},
{
"code": "he",
"language": "עברית"
},
{
"code": "hi",
"language": "हिन्दी"
},
{
"code": "ho",
"language": "Hiri Motu"
},
{
"code": "hr",
"language": "Hrvatski"
},
{
"code": "ht",
"language": "Kreyòl ayisyen"
},
{
"code": "hu",
"language": "magyar"
},
{
"code": "hy",
"language": "Հայերեն"
},
{
"code": "hz",
"language": "Otjiherero"
},
{
"code": "ia",
"language": "Interlingua"
},
{
"code": "id",
"language": "Bahasa Indonesia"
},
{
"code": "ie",
"language": "Interlingue"
},
{
"code": "ig",
"language": "Asụsụ Igbo"
},
{
"code": "ii",
"language": "ꆈꌠ꒿ Nuosuhxop"
},
{
"code": "ik",
"language": "Iñupiaq"
},
{
"code": "io",
"language": "Ido"
},
{
"code": "is",
"language": "Íslenska"
},
{
"code": "it",
"language": "Italiano"
},
{
"code": "iu",
"language": "ᐃᓄᒃᑎᑐᑦ"
},
{
"code": "ja",
"language": "日本語"
},
{
"code": "jv",
"language": "basa Jawa"
},
{
"code": "ka",
"language": "ქართული"
},
{
"code": "kg",
"language": "Kikongo"
},
{
"code": "ki",
"language": "Gĩkũyũ"
},
{
"code": "kj",
"language": "Kuanyama"
},
{
"code": "kk",
"language": "қазақ тілі"
},
{
"code": "kl",
"language": "kalaallisut"
},
{
"code": "km",
"language": "ខេមរភាសា"
},
{
"code": "kn",
"language": "ಕನ್ನಡ"
},
{
"code": "ko",
"language": "한국어"
},
{
"code": "kr",
"language": "Kanuri"
},
{
"code": "ks",
"language": "कश्मीरी"
},
{
"code": "ku",
"language": "Kurmancî"
},
{
"code": "kv",
"language": "коми кыв"
},
{
"code": "kw",
"language": "Kernewek"
},
{
"code": "ky",
"language": "Кыргызча"
},
{
"code": "la",
"language": "latine"
},
{
"code": "lb",
"language": "Lëtzebuergesch"
},
{
"code": "lg",
"language": "Luganda"
},
{
"code": "li",
"language": "Limburgs"
},
{
"code": "ln",
"language": "Lingála"
},
{
"code": "lo",
"language": "ລາວ"
},
{
"code": "lt",
"language": "lietuvių kalba"
},
{
"code": "lu",
"language": "Tshiluba"
},
{
"code": "lv",
"language": "latviešu valoda"
},
{
"code": "mg",
"language": "fiteny malagasy"
},
{
"code": "mh",
"language": "Kajin M̧ajeļ"
},
{
"code": "mi",
"language": "te reo Māori"
},
{
"code": "mk",
"language": "македонски јазик"
},
{
"code": "ml",
"language": "മലയാളം"
},
{
"code": "mn",
"language": "Монгол хэл"
},
{
"code": "mr",
"language": "मराठी"
},
{
"code": "ms",
"language": "Bahasa Melayu"
},
{
"code": "mt",
"language": "Malti"
},
{
"code": "my",
"language": "ဗမာစာ"
},
{
"code": "na",
"language": "Ekakairũ Naoero"
},
{
"code": "nb",
"language": "Norsk bokmål"
},
{
"code": "nd",
"language": "isiNdebele"
},
{
"code": "ne",
"language": "नेपाली"
},
{
"code": "ng",
"language": "Owambo"
},
{
"code": "nl",
"language": "Nederlands"
},
{
"code": "nn",
"language": "Norsk Nynorsk"
},
{
"code": "no",
"language": "Norsk"
},
{
"code": "nr",
"language": "isiNdebele"
},
{
"code": "nv",
"language": "Diné bizaad"
},
{
"code": "ny",
"language": "chiCheŵa"
},
{
"code": "oc",
"language": "occitan"
},
{
"code": "oj",
"language": "ᐊᓂᔑᓈᐯᒧᐎᓐ"
},
{
"code": "om",
"language": "Afaan Oromoo"
},
{
"code": "or",
"language": "ଓଡ଼ିଆ"
},
{
"code": "os",
"language": "ирон æвзаг"
},
{
"code": "pa",
"language": "ਪੰਜਾਬੀ"
},
{
"code": "pi",
"language": "पाऴि"
},
{
"code": "pl",
"language": "Polski"
},
{
"code": "ps",
"language": "پښتو"
},
{
"code": "pt",
"language": "Português"
},
{
"code": "qu",
"language": "Runa Simi"
},
{
"code": "rm",
"language": "rumantsch grischun"
},
{
"code": "rn",
"language": "Ikirundi"
},
{
"code": "ro",
"language": "Română"
},
{
"code": "ru",
"language": "Русский"
},
{
"code": "rw",
"language": "Ikinyarwanda"
},
{
"code": "sa",
"language": "संस्कृतम्"
},
{
"code": "sc",
"language": "sardu"
},
{
"code": "sd",
"language": "सिन्धी"
},
{
"code": "se",
"language": "Davvisámegiella"
},
{
"code": "sg",
"language": "yângâ tî sängö"
},
{
"code": "si",
"language": "සිංහල"
},
{
"code": "sk",
"language": "slovenčina"
},
{
"code": "sl",
"language": "slovenščina"
},
{
"code": "sn",
"language": "chiShona"
},
{
"code": "so",
"language": "Soomaaliga"
},
{
"code": "sq",
"language": "Shqip"
},
{
"code": "sr",
"language": "српски језик"
},
{
"code": "ss",
"language": "SiSwati"
},
{
"code": "st",
"language": "Sesotho"
},
{
"code": "su",
"language": "Basa Sunda"
},
{
"code": "sv",
"language": "Svenska"
},
{
"code": "sw",
"language": "Kiswahili"
},
{
"code": "ta",
"language": "தமிழ்"
},
{
"code": "te",
"language": "తెలుగు"
},
{
"code": "tg",
"language": "тоҷикӣ"
},
{
"code": "th",
"language": "ไทย"
},
{
"code": "ti",
"language": "ትግርኛ"
},
{
"code": "tk",
"language": "Türkmen"
},
{
"code": "tl",
"language": "Wikang Tagalog"
},
{
"code": "tn",
"language": "Setswana"
},
{
"code": "to",
"language": "faka Tonga"
},
{
"code": "tr",
"language": "Türkçe"
},
{
"code": "ts",
"language": "Xitsonga"
},
{
"code": "tt",
"language": "татар теле"
},
{
"code": "tw",
"language": "Twi"
},
{
"code": "ty",
"language": "Reo Tahiti"
},
{
"code": "ug",
"language": "ئۇيغۇرچە‎"
},
{
"code": "uk",
"language": "Українська"
},
{
"code": "ur",
"language": "اردو"
},
{
"code": "uz",
"language": "Ўзбек"
},
{
"code": "ve",
"language": "Tshivenḓa"
},
{
"code": "vi",
"language": "Tiếng Việt"
},
{
"code": "vo",
"language": "Volapük"
},
{
"code": "wa",
"language": "walon"
},
{
"code": "wo",
"language": "Wollof"
},
{
"code": "xh",
"language": "isiXhosa"
},
{
"code": "yi",
"language": "ייִדיש"
},
{
"code": "yo",
"language": "Yorùbá"
},
{
"code": "za",
"language": "Saɯ cueŋƅ"
},
{
"code": "zh",
"language": "中文"
},
{
"code": "zu",
"language": "isiZulu"
},
{
"code": "ast",
"language": "Asturianu"
},
{
"code": "ckb",
"language": "سۆرانی"
},
{
"code": "cnr",
"language": "crnogorski"
},
{
"code": "jbo",
"language": "la .lojban."
},
{
"code": "kab",
"language": "Taqbaylit"
},
{
"code": "kmr",
"language": "Kurmancî"
},
{
"code": "ldn",
"language": "Láadan"
},
{
"code": "lfn",
"language": "lingua franca nova"
},
{
"code": "sco",
"language": "Scots"
},
{
"code": "sma",
"language": "Åarjelsaemien Gïele"
},
{
"code": "smj",
"language": "Julevsámegiella"
},
{
"code": "szl",
"language": "ślůnsko godka"
},
{
"code": "tai",
"language": "ภาษาไท or ภาษาไต"
},
{
"code": "tok",
"language": "toki pona"
},
{
"code": "zba",
"language": "باليبلن"
},
{
"code": "zgh",
"language": "ⵜⴰⵎⴰⵣⵉⵖⵜ"
},
{
"code": "en-GB",
"language": "English (British)"
},
{
"code": "es-AR",
"language": "Español (Argentina)"
},
{
"code": "es-MX",
"language": "Español (México)"
},
{
"code": "fr-QC",
"language": "Français (Canadien)"
},
{
"code": "pt-BR",
"language": "Português (Brasil)"
},
{
"code": "pt-PT",
"language": "Português (Portugal)"
},
{
"code": "sr-Latn",
"language": "Srpski (latinica)"
},
{
"code": "zh-CN",
"language": "简体中文"
},
{
"code": "zh-HK",
"language": "繁體中文(香港)"
},
{
"code": "zh-TW",
"language": "繁體中文(臺灣)"
}
]

File diff suppressed because it is too large Load diff

View file

@ -1,298 +0,0 @@
[
{
"version": "3.33.1",
"code": "534",
"note": "Added:\n- Highlight bottom hashtags\n- Support Trending Links\n- Featured tags displayed in profiles\n- Add/Remove featured tags from the profile editor\n\nChanged:\n- Add confirmation dialog when long pressing the boost button\n- Open messages by tapping on Scheduled Boost\n- Improve language picker when filtered with some languages\n\nFixed:\n- Limits number of fetch for filters\n- Pleroma instances cannot select media\n- Wrong messages deleted for scheduled (messages and boosts)\n- Fix a crash with long threads\n- Fix a potential memory issue for not cropped media\n- Fix embedded quotes not displayed\n- Some crashes"
},
{
"version": "3.32.3",
"code": "532",
"note": "Fixed:\n- Polls not displayed\n- Pagination with trends\n- Push notifications not working on some devices"
},
{
"version": "3.32.2",
"code": "531",
"note": "Added:\n- An outline around media\n\nChanged:\n- Make username, display name in nav drawer clickable\n- Gif media not animated by default\n- Disable by default the mention to the booster when replying. Can be enabled in Settings > Compose (per account)\n\nFixed:\n- Wrong preview picture on share from another app\n- Crash when translating with MinT\n- Refresh and pagination broken for the Trending timeline\n- Fix lags / Crashes"
},
{
"version": "3.32.1",
"code": "530",
"note": "Fixed:\n- Fix a crash on some devices\n- Hide quote button\n- Fix a layout issue with pictures in landscape\n- Fix a crash when opening the original message from a picture"
},
{
"version": "3.32.0",
"code": "529",
"note": "Added:\n- Add option to disable auto hiding compose button\n\nChanged:\n- Add more content descriptions for buttons\n- Update some buttons\n- Update navigation drawer header\n- Squeeze action buttons when needed to prevent overlapping\n\nFixed:\n- Fix crash when media are too heavy\n- Some custom emojis in bio do not render\n- Posting messages does not work on some Friendica instances\n- Fix a crash with auto-split messages\n- Fix a crash when opening conversations\n- Fix a background color issue when displaying media"
},
{
"version": "3.31.3",
"code": "528",
"note": "Added:\n- Add new icon launchers (Settings > Interface)\n\nChanged:\n- Make logout/proxy button more visible in main menu\n- Remove permission FOREGROUND_SERVICE\n- Improve a little more media layout with translations\n\nFixed:\n- Fix status bar icons not visible in light theme with custom accent color\n- Reaction buttons not clickable for some instances"
},
{
"version": "3.31.2",
"code": "527",
"note": "Added:\n- Add support to URL scheme \"web+ap\" for opening profiles with the app\n\nChanged:\n- Layout for media descriptions\n\nFixed:\n- Fix a crash when translating media descriptions\n- Handle included twice when replying to a self user's boost\n- Fix color issues when using a custom theme"
},
{
"version": "3.31.1",
"code": "526",
"note": "Added:\n- Add MinT machine translation system support\n- Add support \"instance only\" for GoToSocial\n\nFixed:\n- GIF not displayed in timelines\n- Fix a crash when unpinning timelines\n- Top bar coloring at scroll for conversations\n- Black screen when going back from the Peertube section"
},
{
"version": "3.31.0",
"code": "524",
"note": "Added:\n- Pinned Trending Timeline (can be hidden in Manage Timelines)\n- Add a fallback to the default translator\n- New Pixelfed entry in Settings to disable fullscreen for media\n- Add tooltips for tabs in profiles\n\nChanged:\n- Increase touch area of reply buttons\n- Show a dialog after settings export\n\nFixed:\n- Fix media description not updated when there are several\n- Only a part of DeepL translations are shown\n- Fix Lingva truncated translations\n- Fix a crash when fetching remote profiles\n- Fix a crash with animated emoji\n- Fix a crash when displaying Home cache charts"
},
{
"version": "3.30.1",
"code": "523",
"note": "Added:\n- Follow Twitter tags\n\nChange:\n- Remove automatic backup (Google only)\n\nFixed:\n- Push notifications not working for some devices\n- Filters not applied to media description\n- Fix a crash with animated images in timelines\n- Fix a crash for long threads\n- Fix a crash due to some messages (happened in different timelines)"
},
{
"version": "3.30.0",
"code": "522",
"note": "Added:\n- Allow to follow the discover timelines of Pixelfed instances\n- Keep media proportions in timeline for Pixelfed\n- Add a like button in timelines for Pixelfed\n- Allow to login with a token\n\nChange:\n- Use Pixelfed layout when following Pixelfed instances\n- Allow to scroll buttons for larger screens in conversations\n- Move QR code into header\n\nFixed:\n- Not clickable URLs when Markdown is enabled\n- Nitter to follow Twitter accounts\n- Pixelfed timeline not displayed by default\n- Fix admin reports not accessible\n- Top bar coloring at scroll\n- Drafts not saved when adding/editing media descriptions\n- User search suggestions have duplicates\n- Some minor crashes"
},
{
"version": "3.29.2",
"code": "518",
"note": "Fixed:\n- Fix crash when changing the type of notifications\n- Fix issue with names not displayed fully\n- Fix a crash with notifications and Sharkey\n- Fix a crash when app is back to the foreground\n- Fix xmpp links not opening xmpp clients\n- Fix wrong muted time"
},
{
"version": "3.29.1",
"code": "517",
"note": "Added:\n- Allow to edit scheduled messages from server side\n\nChanged:\n- Order list name alphabetically in profiles\n- Remove registration for Google\n\nFixed:\n- Push notifications\n- Peertube instances picker\n- Edit scheduled threads (local)\n- Instant search of Hashtag repeats results\n- Quotes broken with Markdowns\n- Fix reports crashes after submitting\n- Fix emoji picker when there is no result\n- Fix other crashes"
},
{
"version": "3.28.2",
"code": "515",
"note": "Added:\n- Display a QR code on profiles\n\nFixed:\n- Fix tap on messages in conversations\n- Pronouns taking too much place"
},
{
"version": "3.28.1",
"code": "514",
"note": "Added:\n- Allow to disable pronouns support (default: enabled)\n- Add more support for pronouns (localization in different languages)\n\nFixed:\n- Fix a crash when reporting messages\n- Fix a crash when following tags\n- Fix some display issues\n- Several fixes from the last release (3.28.0)"
},
{
"version": "3.28.0",
"code": "513",
"note": "Added:\n- Pronouns support (Timeline/Compose/Autocomplete)\n\nChanged:\n- Use Media3 library\n\nFixed:\n- Timed mute duration too long\n- Sharing videos only download them\n- Crashes from previous release"
},
{
"version": "3.27.1",
"code": "511",
"note": "Added:\n- Tap on account banners to display them as media\n\nFixed:\n- Position lost when switching between accounts\n- Wrong profiles when enabling remote conversations\n- Peertube local timeline\n- Peertube instances search\n- Crashes of the previous release"
},
{
"version": "3.27.0",
"code": "510",
"note": "Added:\n- Fixed top bar (default: disabled)\n- Usage frequency of tags when composing\n\nChanged:\n- Markdown support disabled by default\n\nFixed:\n- Fix crashes during interactions or when opening a new screen\n- Fix color of dialogs in Settings\n- Some minor crashes"
},
{
"version": "3.26.0",
"code": "505",
"note": "Added:\n- Android 14 support\n- Automatically split long messages in threads (default: ASK)\n- Links and media are clickable when composing\n- Allow to underline clickable elements (Settings > Timelines - default: disabled)\n- Allow to disable relative date in messages\n- Add a scroll bar for timelines (default: disabled)\n- Add a search bar for custom emojis\n- Links clickable in media descriptions\n\nChanged:\n- Counters close to action buttons\n- Hide emoji picker if the instance has no emoji\n- Followed tags are ordered\n- Account picker when opening with another account\n\nFixed:\n- Avoid error 429 with NTFY\n- Fix custom colors (Android 14)\n- Fix a crash when composing\n- Display issue with followed tags\n- Crashes with profiles\n- Fix an issue with poll and Pleroma\n- Emoji not displayed in the picker\n- Several crashes are fixed"
},
{
"version": "3.25.3",
"code": "504",
"note": "Added:\n- Add a scroll bar for timelines (default: disabled)\n- Add a search bar for custom emojis\n\nFixed:\n- Fix prompt to split asked several times when refusing\n- Crashes with profiles\n- Fix an issue with poll and Pleroma\n- Emoji not displayed in the picker"
},
{
"version": "3.25.2",
"code": "503",
"note": "Added:\n- Allow to underline clickable elements (Settings > Timelines - default: disabled)\n- Allow to disable relative date in messages\n\nChanged:\n- Counters close to action buttons\n- Hide emoji picker if the instance has no emoji\n- Followed tags are ordered\n- Account picker when opening with another account\n\nFixed:\n- Fix a crash when composing\n- Fix an issue with the back button\n- Display issue with followed tags"
},
{
"version": "3.25.1",
"code": "502",
"note": "Fix a crash from release 3.25.0"
},
{
"version": "3.25.0",
"code": "501",
"note": "Added:\n- Android 14 support\n- Automatically split long messages in threads (default: ASK)\n- Links and media are clickable when composing\n\nFixed:\n- Avoid error 429 with NTFY\n- Several crashes are fixed"
},
{
"version": "3.24.1",
"code": "500",
"note": "Added:\n- Three new app icons (Pride, Pink and Pirate)\n- Keep position with remote conversations\n\nFixed:\n- Markdown: stop parsing tags and support strike text\n- Cursor more visible when composing\n- Fix custom instance max char length not working\n- Tabs in profiles\n- Fix not clickable tags for some languages\n- Bug with account having huge amount of followers\n- Crash with several gif in same message\n- Poll max chars\n- Some crashes"
},
{
"version": "3.24.0",
"code": "499",
"note": "Added:\n- Markdown support (can be disabled in Settings > Timelines)\n- Hide / Show Self boosts, self replies and your own messages (Long press the Home tab)\n\nChanged:\n- Full screen size when writing media descriptions.\n- Move media descriptions to the top\n\nFixed:\n- Holes in timelines due to a cache bug\n- Spoiler issue when composing threads\n- CamelCase tags when forwarding them in replies\n- Buttons hidden by keyboard when composing\n- Overlay with menu and buttons when playing videos\n- Clicks on card do not open Mastodon posts inside the app\n- Scrollable bio when editing profiles\n- Crash when adding a user into a list\n- Longer fields when editing bio\n- Crash with Pixelfed\n"
},
{
"version": "3.23.5",
"code": "498",
"note": "Added:\n- Hide / Show Self boosts and self replies (Long press the Home tab)\n\nChanged:\n- Full screen size when writing media descriptions."
},
{
"version": "3.23.4",
"code": "497",
"note": "Fixed:\n\n- Holes in timelines due to a cache bug\n- Fix tags issue with RTL and the markdown format\n- Scrollable bio when editing profiles\n- Crash when adding a user into a list"
},
{
"version": "3.23.3",
"code": "496",
"note": "- Longer fields when editing bio\n- Clicks on card do not open Mastodon posts inside the app\n- Crash with Pixelfed\n- Line breaks with Markdown\n- Side effects with Markdown and some links"
},
{
"version": "3.23.2",
"code": "495",
"note": "Added:\n- Markdown support (can be disabled in Settings > Timelines)"
},
{
"version": "3.23.1",
"code": "494",
"note": "Added:\n- Scrollable media description\n\nFixed:\n- Crashes with profiles"
},
{
"version": "3.23.0",
"code": "493",
"note": "Added:\n- Add preview for app icons\n- Two new app icons\n\nFixed:\n- Fix Nitter feeds\n- Crash with Pixelfed accounts\n- Lingva encoding issue\n- Avoid sleep mode for media activity\n- Videos are played simultaneously\n- Voice messages for Android 10+\n- Punycode not supported for domains"
},
{
"version": "3.22.2",
"code": "492",
"note": "Added:\n- Follow Lemmy instances (from Manage Timelines)\n- View remote conversations (default: disabled - Settings > Interface)\n\nFixed:\n- Add 50 chars max for poll options\n- Too many requests\n- Blank Home page\n- Crashes when visiting profiles\n- Some audio files cannot be uploaded\n- Multiple notifications\n- Fix some other crashes"
},
{
"version": "3.22.1",
"code": "491",
"note": "Added:\n- Follow Lemmy instance (from Manage Timelines)\nFixed:\n- Add 50 chars max for poll options"
},
{
"version": "3.22.0",
"code": "490",
"note": "Fixed:\n- Too many requests\n- Blank Home page\n- Crashes when visiting profiles\n- Some audio files cannot be uploaded"
},
{
"version": "3.21.2",
"code": "489",
"note": "Added:\n- Android 12+ : Customize accent colors for light/dark theme and per account (Settings > Theming > Custom accent color)\n"
},
{
"version": "3.21.1",
"code": "488",
"note": "Added:\n- Filter messages in profiles (hide/show boosts or replies) via a long press on the tab\n\nChanged:\n- Some layout improvements for Peertube\n- Better management of resolution with Peertube\n- Improve instance picker for Peertube\n\nFixed:\n- URL in upper cases\n- Issues with Peertube player\n- False positive error when listening to audio\n- GIF does not honor nsfw\n- Polls having html\n- Fix crashes when scrolling timeline with animated gif"
},
{
"version": "3.21.0",
"code": "487",
"note": "Added:\n- Dedicated Peertube entry in main menu (My app)\n- Select instances (Instances picker with Filters)\n- Comment/Boost/Fav Peertube videos with Mastodon accounts\n\nFixed:\n- Fix a crash when searching and with the user directory"
},
{
"version": "3.20.3",
"code": "486",
"note": "Added:\n- Display all following/followers lists from remote profiles\n- Display all accounts that boosted/fav from a remote message\n\nFixed:\n- Fix a crash with auto-fetch messages"
},
{
"version": "3.20.2",
"code": "485",
"note": "Added:\n- Visual indicator when fetching missing messages\n- Open media description when it is missing from the warning dialog\n\nChanged:\n- Maths formula aligned to the left\n- Faster access to delete all notifications\n\nFixed:\n- Fix an issue with Nitter and some URLs\n- Fix refresh issue with notifications\n- Fix an issue when entering a Peertube instance\n- Fix jumps with Akkoma/Pleroma when media preview size is not set\n- Some crashes"
},
{
"version": "3.20.1",
"code": "484",
"note": "Added:\n- Add a button to fetch remote media when it fails\n- Add a settings to automatically fetch remote media when it fails (default: disabled)\n- Display on profiles & list of accounts if users have requested to follow you\n- Warn before boosting a message having no media descriptions (default: enabled)\n\nChanged:\n- Warn when there are missing descriptions enabled by default\n\nFixed:\n- Some settings not properly restored (multiple choices)\n- Cancel a follow request\n- Media with a lot of height in landscape\n- Some crashes"
},
{
"version": "3.20.0",
"code": "483",
"note": "Added:\n- \"Follows you\" indicator in accounts list\n- Settings compose: display a dialog to warn if there are missing media description (default: disabled)\n- Settings > Cache: disable battery optimization\n- Settings > Cache - Add charts to check cache logs\n- Settings > Timelines: AutoPlay gif media (default: enabled)\n- Google: Automatic backup of data and settings\n\nChanged:\n- Improve detections of gap in timelines\n- Improve media description\n- Chat view by default\n- Chat view add an indicator for messages when not direct\n\nFixed:\n- Fix an issue with cache and fetch more\n- Cache view with large fonts\n- Bad behaviors with truncated messages"
},
{
"version": "3.19.1",
"code": "482",
"note": "Added:\n- Settings compose: display a dialog to warn if there are missing media description (default disabled)\n- Settings > Notification: disable battery optimization\n- Settings > Timelines: AutoPlay gif media (default: enabled)\n\nFixed:\n- Fix an issue with cache and fetch more\n- Cache view with large fonts\n- Bad behaviors with truncated messages"
},
{
"version": "3.19.0",
"code": "481",
"note": "Added:\n- Settings compose: don't send media if there are no description (default: disabled)\n- Settings Timelines: Enable/Disable truncate links\n- Allow to set max link length (20 - 150 chars)\n\nChanged:\n- Align media with text (left margin enabled)\n\nFixed:\n- Media previews remain the same when sharing\n- Edit media description not working\n- Accessibility (larger fonts): profiles/DM\n- Cross replies: Wrong visibility with the selected account\n- Several crashes"
},
{
"version": "3.18.2",
"code": "480",
"note": "Changed:\n- First media layout will depend of its ratio\n\nFixed:\n- Impossible to add media with the chat view\n- Chat view limited in chars\n- Freezes / bad behaviors due to the new media presentation"
},
{
"version": "3.18.1",
"code": "479",
"note": "Added:\n- Add Lingva translator (Settings > Timelines)\n- Add support for Nyastodon-style emoji reactions (skyevg)\n- Add chat view for DM (default: disable / Settings > Timelines)"
},
{
"version": "3.18.0",
"code": "478",
"note": "Added:\n- Support camel case tags (automatically recorded when composing)\n- Manage tags when composing (top right menu)\n- Custom tabs (default: enabled)\n\nChanged:\n- Media heights now use the screen size\n- Remove horizontal scroll for media\n- Reduce size of emoji when text size is increased\n- Update available languages in picker\n\nFixed:\n- Forwarded tags are added back after being deleted\n- TalkBack issues\n- Some crashes"
},
{
"version": "3.17.0",
"code": "477",
"note": "Added:\n- Peertube 2FA support\n- Cache home in background (default disabled -> New settings category and per account) / change frequency\n- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)\n- Automatically switch between tabs when searching\n- More deep links detection\n- Allow to group mentions at the top (default: disabled)\n\n\nFixed:\n- Dynamic color for Android 12+\n- Missing media description for previews\n- Fix a crash when replying\n- Fix button size not changed\n- Forward tags in replies\n- Media cannot be downloaded or shared with Android 10\n- Some crashes"
},
{
"version": "3.16.4",
"code": "476",
"note": "Added:\n- Cache home in background (default disabled -> New settings category and per account) / change frequency\n- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)\n- Automatically switch between tabs when searching\n\nFixed:\n- Some crashes"
},
{
"version": "3.16.3",
"code": "475",
"note": "Added:\n- Peertube 2FA support\n\nFixed:\n- Dynamic color for Android 12+"
},
{
"version": "3.16.2",
"code": "474",
"note": "Added:\n- Peertube support\n- Compose shortcut (long press launcher)\n- Long press compose button to write with another account\n- Edit description and focus for media (for the next Mastodon release)\n\nChanged:\n- Cross actions with two accounts display a dialog\n- Order & compact og values when sharing > title - url - content\n- Tap on top message (user info) open threads\n\nFixed:\n- Text cleared when adding a media\n- Fix Maths not working with quotes\n- Fix crashes"
},
{
"version": "3.16.1",
"code": "473",
"note": "Changed:\n- Edit description and focus for media (for the next Mastodon release)\n\nChanged:\n- Peertube: remove role support to avoid crashes with older instances\n\nFixed:\n- Fix some crashes"
},
{
"version": "3.16.0",
"code": "472",
"note": "Changed:\n- Peertube support\n- Compose shortcut\n- Long press compose button to write with another account\n\nChanged:\n- Cross actions with two accounts display a dialog\n- Order & compact og values when sharing > title - url - content\n\nFixed:\n- Text cleared when adding a media\n- Fix crashes"
},
{
"version": "3.15.2",
"code": "471",
"note": "Changed:\n- Add instance name when sharing\n\nFixed:\n- Fix a crash when removing media\n- Other minor fixes"
},
{
"version": "3.15.1",
"code": "470",
"note": "Changed:\n- Material dialogs\n\nFixed:\n- Light theme issues"
},
{
"version": "3.15.0",
"code": "469",
"note": "Added:\n- Maths support (view and compose)\n- Filter DMs in HOME (long press on the tab)\n- Filter languages for users in home timeline (from their profile)\n- Add several targeted languages for translator\n\nChanged:\n- Hide single media with preview is now a setting (default: disabled)\n- Group items in menu of messages\n\nFixed:\n- Cross-actions didn't display account instances"
},
{
"version": "3.14.6",
"code": "468",
"note": "Added:\n- Maths support (view and compose)\n\nChanged:\n- Hide single media with preview is now a setting (default: disabled)"
},
{
"version": "3.14.5",
"code": "467",
"note": "Changed:\n- Allow to swipe media for profiles\n\nFixed:\n- Fix crashes with pinch zoom\n- Copy/Paste in threads\n- Fix crash when checking redirection on http links\n- Display menu in media viewer resets pinch-zoom"
},
{
"version": "3.14.4",
"code": "466",
"note": "Changed:\n- Media viewer (pinch zoom)\n\nFixed:\n- Cross account actions (long press)\n- Boost color\n- Buttons not visible with custom themes.\n- Fix some bad behaviors with media viewer"
},
{
"version": "3.14.3",
"code": "465",
"note": "Added:\n- Display date of the message instead of the boost (default: disabled)\n- Allow to disable release notes popup in Settings\n\nFixed:\n- Fix timelines slow down and stuttering after some scrolls\n- Fix color issues with follow buttons\n- Fix import from settings (import from login was OK)"
}
]

View file

@ -0,0 +1,13 @@
base_theme,2
author,Fedilab
name,Breeze Dark - Yellow
theme_boost_header_color,-14012878
theme_statuses_color,-14473687
theme_link_color,-12734743
theme_icons_color,-4340793
pref_color_background,-15658735
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-148405
theme_text_color,-1052431
theme_primary,-13552069
1 base_theme 2
2 author Fedilab
3 name Breeze Dark - Yellow
4 theme_boost_header_color -14012878
5 theme_statuses_color -14473687
6 theme_link_color -12734743
7 theme_icons_color -4340793
8 pref_color_background -15658735
9 pref_color_navigation_bar true
10 pref_color_status_bar true
11 theme_accent -148405
12 theme_text_color -1052431
13 theme_primary -13552069

View file

@ -0,0 +1,15 @@
base_theme,2
author,Roboron
name,Cyberpunk Neon
theme_boost_header_color,-16776697,
theme_text_header_1_line,-1441575,
theme_text_header_2_line,-5242717,
theme_statuses_color,-16181197,
theme_link_color,-1441575,
theme_icons_color,-16138810,
pref_color_background,-16774370,
pref_color_navigation_bar,true,
pref_color_status_bar,true,
theme_accent,-1441575,
theme_text_color,-16138810,
theme_primary,-16774370,
1 base_theme,2
2 author,Roboron
3 name,Cyberpunk Neon
4 theme_boost_header_color,-16776697,
5 theme_text_header_1_line,-1441575,
6 theme_text_header_2_line,-5242717,
7 theme_statuses_color,-16181197,
8 theme_link_color,-1441575,
9 theme_icons_color,-16138810,
10 pref_color_background,-16774370,
11 pref_color_navigation_bar,true,
12 pref_color_status_bar,true,
13 theme_accent,-1441575,
14 theme_text_color,-16138810,
15 theme_primary,-16774370,

View file

@ -0,0 +1,15 @@
base_theme,2
author,Jøta Seth
name,Grey Orange
theme_boost_header_color,-14869219
theme_text_header_1_line,-1
theme_text_header_2_line,-1
theme_statuses_color,-14145496
theme_link_color,-26624
theme_icons_color,-26624
pref_color_background,-13092808
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-26624
theme_text_color,-1
theme_primary,-14408668
1 base_theme 2
2 author Jøta Seth
3 name Grey Orange
4 theme_boost_header_color -14869219
5 theme_text_header_1_line -1
6 theme_text_header_2_line -1
7 theme_statuses_color -14145496
8 theme_link_color -26624
9 theme_icons_color -26624
10 pref_color_background -13092808
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -26624
14 theme_text_color -1
15 theme_primary -14408668

View file

@ -0,0 +1,15 @@
base_theme,2
author,@AntoineD@h.kher.nl
name,Gruvbox OLED
theme_boost_header_color,-16777216
theme_text_header_1_line,-265785
theme_text_header_2_line,-6777062
theme_statuses_color,-16777216
theme_link_color,-2647775
theme_icons_color,-7175308
pref_color_background,-16777216
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-9921174
theme_text_color,-265785
theme_primary,-16777216
1 base_theme 2
2 author @AntoineD@h.kher.nl
3 name Gruvbox OLED
4 theme_boost_header_color -16777216
5 theme_text_header_1_line -265785
6 theme_text_header_2_line -6777062
7 theme_statuses_color -16777216
8 theme_link_color -2647775
9 theme_icons_color -7175308
10 pref_color_background -16777216
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -9921174
14 theme_text_color -265785
15 theme_primary -16777216

View file

@ -0,0 +1,15 @@
base_theme,2
author,AngryTux
name,Less Angry Orange
theme_boost_header_color,-15855063
theme_text_header_1_line,-2128640
theme_text_header_2_line,-5329234
theme_statuses_color,-1
theme_link_color,-12146699
theme_icons_color,-2128640
pref_color_background,-15987700
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-3968000
theme_text_color,-197380
theme_primary,-14408668
1 base_theme 2
2 author AngryTux
3 name Less Angry Orange
4 theme_boost_header_color -15855063
5 theme_text_header_1_line -2128640
6 theme_text_header_2_line -5329234
7 theme_statuses_color -1
8 theme_link_color -12146699
9 theme_icons_color -2128640
10 pref_color_background -15987700
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -3968000
14 theme_text_color -197380
15 theme_primary -14408668

View file

@ -0,0 +1,15 @@
base_theme,2
author,Mondstern
name,Mondstern Fedilab
theme_boost_header_color,-1,
theme_text_header_1_line,-13855804,
theme_text_header_2_line,-16227945,
theme_statuses_color,-14935012,
theme_link_color,-15542685,
theme_icons_color,-10723999,
pref_color_background,-15921907,
pref_color_navigation_bar,false,
pref_color_status_bar,false,
theme_accent,-15542685,
theme_text_color,-1,
theme_primary,-14474461,
1 base_theme,2
2 author,Mondstern
3 name,Mondstern Fedilab
4 theme_boost_header_color,-1,
5 theme_text_header_1_line,-13855804,
6 theme_text_header_2_line,-16227945,
7 theme_statuses_color,-14935012,
8 theme_link_color,-15542685,
9 theme_icons_color,-10723999,
10 pref_color_background,-15921907,
11 pref_color_navigation_bar,false,
12 pref_color_status_bar,false,
13 theme_accent,-15542685,
14 theme_text_color,-1,
15 theme_primary,-14474461,

View file

@ -0,0 +1,13 @@
base_theme,2
author,Fedilab
name,Nocturnal
theme_boost_header_color,-12895429
theme_statuses_color,-13553359
theme_link_color,-16747570
theme_icons_color,-10158118
pref_color_background,-14606047
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-13136013
theme_text_color,-2236963
theme_primary,-14013910
1 base_theme 2
2 author Fedilab
3 name Nocturnal
4 theme_boost_header_color -12895429
5 theme_statuses_color -13553359
6 theme_link_color -16747570
7 theme_icons_color -10158118
8 pref_color_background -14606047
9 pref_color_navigation_bar true
10 pref_color_status_bar true
11 theme_accent -13136013
12 theme_text_color -2236963
13 theme_primary -14013910

View file

@ -0,0 +1,15 @@
base_theme,2
author,Jøta Seth
name,Photon Dark
theme_boost_header_color,-14145496
theme_text_header_1_line,-1
theme_text_header_2_line,-1
theme_statuses_color,-14935012
theme_link_color,-14059009
theme_icons_color,-9474193
pref_color_background,-15921907
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-14059009
theme_text_color,-1
theme_primary,-14474461
1 base_theme 2
2 author Jøta Seth
3 name Photon Dark
4 theme_boost_header_color -14145496
5 theme_text_header_1_line -1
6 theme_text_header_2_line -1
7 theme_statuses_color -14935012
8 theme_link_color -14059009
9 theme_icons_color -9474193
10 pref_color_background -15921907
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -14059009
14 theme_text_color -1
15 theme_primary -14474461

View file

@ -0,0 +1,15 @@
base_theme,2
author,Fedilab
name,Solarized Dark - Purple
theme_boost_header_color,-16506327
theme_text_header_1_line,-1120043
theme_text_header_2_line,-1120043
theme_statuses_color,-16304574
theme_link_color,-14251054
theme_icons_color,-7102047
pref_color_background,-16766154
pref_color_navigation_bar,true
pref_color_status_bar,true
theme_accent,-9670204
theme_text_color,-133405
theme_primary,-16304574
1 base_theme 2
2 author Fedilab
3 name Solarized Dark - Purple
4 theme_boost_header_color -16506327
5 theme_text_header_1_line -1120043
6 theme_text_header_2_line -1120043
7 theme_statuses_color -16304574
8 theme_link_color -14251054
9 theme_icons_color -7102047
10 pref_color_background -16766154
11 pref_color_navigation_bar true
12 pref_color_status_bar true
13 theme_accent -9670204
14 theme_text_color -133405
15 theme_primary -16304574

View file

@ -0,0 +1,47 @@
[
{
"theme_name": "Dark",
"base_theme": "DARK",
"primary": "#FF272727",
"primary_dark": "#FF272727",
"primary_light": "#FFd9e1e8",
"accent": "#FF2b90d9",
"accent_dark": "#FF1b80c9",
"accent_light": "#FF772b90d9",
"background": "#FF121212",
"background_dark": "#FF282c37",
"background_light": "#FF282c37",
"should_tint_statusbar": true,
"should_tint_navbar": true
},
{
"theme_name": "Light",
"base_theme": "LIGHT",
"primary": "#FFFFFF",
"primary_dark": "#FFFFFFFF",
"primary_light": "#FFd9e1e8",
"accent": "#FF2b90d9",
"accent_dark": "#FF1b80c9",
"accent_light": "#FF772b90d9",
"background": "#FFFFFFFF",
"background_dark": "#FFFFFFFF",
"background_light": "#FFFFFFFF",
"should_tint_statusbar": true,
"should_tint_navbar": true
},
{
"theme_name": "Black",
"base_theme": "DARK",
"primary": "#FF000000",
"primary_dark": "#FF000000",
"primary_light": "#FF000000",
"accent": "#FF606984",
"accent_dark": "#FF606984",
"accent_light": "#FF606984",
"background": "#FF000000",
"background_dark": "#FF000000",
"background_light": "#FF000000",
"should_tint_statusbar": true,
"should_tint_navbar": true
}
]

File diff suppressed because it is too large Load diff

View file

@ -15,20 +15,16 @@ package app.fedilab.android;
* see <http://www.gnu.org/licenses>. */
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.StrictMode;
import android.webkit.WebView;
import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
import androidx.preference.PreferenceManager;
import net.gotev.uploadservice.UploadServiceConfig;
import net.gotev.uploadservice.observer.request.GlobalRequestObserver;
import com.jaredrummler.cyanea.Cyanea;
import com.jaredrummler.cyanea.prefs.CyaneaTheme;
import org.acra.ACRA;
import org.acra.ReportField;
@ -37,52 +33,49 @@ import org.acra.config.DialogConfigurationBuilder;
import org.acra.config.MailSenderConfigurationBuilder;
import org.acra.data.StringFormat;
import java.util.Objects;
import java.util.List;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.peertube.services.GlobalUploadObserver;
import es.dmoral.toasty.Toasty;
import io.noties.prism4j.annotations.PrismBundle;
@PrismBundle(includeAll = true, grammarLocatorClassName = ".MySuperGrammerLocator")
public class MainApplication extends MultiDexApplication {
public static String UPLOAD_CHANNEL_ID = "upload_info_peertube";
private WebView webView;
private static MainApplication app;
public static MainApplication getApp() {
return app;
}
@Override
public void onCreate() {
super.onCreate();
try {
webView = new WebView(this);
} catch (Exception ignored) {
app = this;
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(MainApplication.this);
Cyanea.init(this, super.getResources());
List<CyaneaTheme> list = CyaneaTheme.Companion.from(getAssets(), "themes/cyanea_themes.json");
boolean custom_theme = sharedpreferences.getBoolean("use_custom_theme", false);
boolean no_theme_set = sharedpreferences.getBoolean("no_theme_set", true);
if (no_theme_set && !custom_theme) {
list.get(0).apply(Cyanea.getInstance());
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean("no_theme_set", false);
editor.apply();
}
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Toasty.Config.getInstance().apply();
if (webView != null) {
try {
webView.destroy();
} catch (Exception ignored) {
}
}
createNotificationChannel();
UploadServiceConfig.initialize(MainApplication.this, UPLOAD_CHANNEL_ID, true);
new GlobalRequestObserver(this, new GlobalUploadObserver());
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(MainApplication.this);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(MainApplication.this);
boolean send_crash_reports = sharedpreferences.getBoolean(getString(R.string.SET_SEND_CRASH_REPORTS), false);
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
ThemeHelper.switchTo(currentTheme);
if (send_crash_reports) {
ACRA.init(this, new CoreConfigurationBuilder()
//core configuration:
@ -99,6 +92,7 @@ public class MainApplication extends MultiDexApplication {
.withResIcon(R.mipmap.ic_launcher)
.withText(getString(R.string.crash_title))
.withCommentPrompt(getString(R.string.crash_message))
.withResTheme(R.style.DialogDark)
.withPositiveButtonText(getString(R.string.send_email))
.withNegativeButtonText(getString(R.string.cancel))
.build()
@ -114,15 +108,4 @@ public class MainApplication extends MultiDexApplication {
);
}
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(UPLOAD_CHANNEL_ID,
getString(R.string.notification_channel_name),
NotificationManager.IMPORTANCE_LOW);
channel.setSound(null, null);
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).createNotificationChannel(channel);
}
}
}

View file

@ -15,17 +15,16 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import java.util.ArrayList;
@ -34,20 +33,17 @@ import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.databinding.ActivityAboutBinding;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.activities.ProfileActivity;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.CrossActionHelper;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import es.dmoral.toasty.Toasty;
import app.fedilab.android.helper.CrossActionHelper;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
public class AboutActivity extends BaseBarActivity {
public class AboutActivity extends BaseActivity {
private ActivityAboutBinding binding;
@ -56,17 +52,18 @@ public class AboutActivity extends BaseBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityAboutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
String version = "";
try {
PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
version = pInfo.versionName;
String version = pInfo.versionName;
binding.aboutVersion.setText(getResources().getString(R.string.about_vesrion, version));
} catch (PackageManager.NameNotFoundException ignored) {
}
@ -82,26 +79,13 @@ public class AboutActivity extends BaseBarActivity {
}
binding.aboutSupportPaypal.setOnClickListener(v -> Helper.openBrowser(AboutActivity.this, "https://www.paypal.me/Mastalab"));
String finalVersion = version;
binding.aboutVersionCopy.setOnClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
String content = "Fedilab v" + finalVersion + " for " + (BuildConfig.DONATIONS ? "FDroid" : "Google");
ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content);
if (clipboard != null) {
clipboard.setPrimaryClip(clip);
Toasty.info(AboutActivity.this, getString(R.string.clipboard_version), Toast.LENGTH_LONG).show();
}
});
binding.accountFollow.setBackgroundTintList(ThemeHelper.getButtonActionColorStateList(AboutActivity.this));
if (BuildConfig.DONATIONS) {
binding.aboutSupportPaypal.setVisibility(View.VISIBLE);
} else {
binding.aboutSupportPaypal.setVisibility(View.GONE);
}
binding.accountFollow.setIconResource(R.drawable.ic_baseline_person_add_24);
binding.accountFollow.setImageResource(R.drawable.ic_baseline_person_add_24);
binding.aboutWebsite.setOnClickListener(v -> Helper.openBrowser(AboutActivity.this, "https://fedilab.app"));
CrossActionHelper.fetchRemoteAccount(AboutActivity.this, "@apps@toot.fedilab.app", new CrossActionHelper.Callback() {
@Override
@ -119,14 +103,12 @@ public class AboutActivity extends BaseBarActivity {
binding.accountUn.setText(account.acct);
binding.accountPp.setOnClickListener(v -> {
Intent intent = new Intent(AboutActivity.this, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(AboutActivity.this).insertBundle(args, Helper.getCurrentAccount(AboutActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
startActivity(intent);
});
Bundle b = new Bundle();
b.putSerializable(Helper.ARG_ACCOUNT, account);
intent.putExtras(b);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(AboutActivity.this, binding.accountPp, getString(R.string.activity_porfile_pp));
startActivity(intent, options.toBundle());
});
AccountsVM accountsVM = new ViewModelProvider(AboutActivity.this).get(AccountsVM.class);
List<String> ids = new ArrayList<>();
@ -136,7 +118,7 @@ public class AboutActivity extends BaseBarActivity {
if (relationShips != null && relationShips.size() > 0) {
if (!relationShips.get(0).following) {
binding.accountFollow.setVisibility(View.VISIBLE);
binding.accountFollow.setOnClickListener(v -> accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false, null)
binding.accountFollow.setOnClickListener(v -> accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false)
.observe(AboutActivity.this, relationShip -> binding.accountFollow.setVisibility(View.GONE)));
}
}

View file

@ -0,0 +1,135 @@
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.databinding.ActivityActionsBinding;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonAccount;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline;
public class ActionActivity extends BaseActivity {
private ActivityActionsBinding binding;
private boolean canGoBack;
private FragmentMastodonTimeline fragmentMastodonTimeline;
private FragmentMastodonAccount fragmentMastodonAccount;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityActionsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
canGoBack = false;
binding.favourites.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.FAVOURITE_TIMELINE));
binding.bookmarks.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BOOKMARK_TIMELINE));
binding.muted.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.MUTED_TIMELINE));
binding.blocked.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BLOCKED_TIMELINE));
}
private void displayTimeline(Timeline.TimeLineEnum type) {
canGoBack = true;
if (type == Timeline.TimeLineEnum.MUTED_TIMELINE || type == Timeline.TimeLineEnum.BLOCKED_TIMELINE) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonAccount = new FragmentMastodonAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentMastodonAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonAccount);
fragmentTransaction.commit();
});
} else {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
});
}
switch (type) {
case MUTED_TIMELINE:
setTitle(R.string.muted_menu);
break;
case FAVOURITE_TIMELINE:
setTitle(R.string.favourite);
break;
case BLOCKED_TIMELINE:
setTitle(R.string.blocked_menu);
break;
case BOOKMARK_TIMELINE:
setTitle(R.string.bookmarks);
break;
}
}
@Override
public void onBackPressed() {
if (canGoBack) {
canGoBack = false;
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.buttonContainer, () -> {
if (fragmentMastodonTimeline != null) {
fragmentMastodonTimeline.onDestroyView();
}
if (fragmentMastodonAccount != null) {
fragmentMastodonAccount.onDestroyView();
}
});
setTitle(R.string.interactions);
} else {
super.onBackPressed();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.mastodon.activities.admin;
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -19,14 +19,16 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
@ -44,8 +46,8 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -53,153 +55,78 @@ import java.util.concurrent.TimeUnit;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.AdminAccount;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.databinding.ActivityAdminAccountBinding;
import app.fedilab.android.mastodon.activities.BaseActivity;
import app.fedilab.android.mastodon.activities.InstanceProfileActivity;
import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminAccount;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminIp;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.SpannableHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.NodeInfoVM;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AdminVM;
import app.fedilab.android.viewmodel.mastodon.NodeInfoVM;
import es.dmoral.toasty.Toasty;
public class AdminAccountActivity extends BaseActivity {
private AdminAccount adminAccount;
private Account account;
private ScheduledExecutorService scheduledExecutorService;
private ActivityAdminAccountBinding binding;
private String account_id;
private AdminVM adminVM;
private AdminAccount adminAccount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityAdminAccountBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
Bundle args = getIntent().getExtras();
adminAccount = null;
Bundle b = getIntent().getExtras();
if (b != null) {
adminAccount = (AdminAccount) b.getSerializable(Helper.ARG_ACCOUNT);
if (adminAccount != null) {
account = adminAccount.account;
}
}
postponeEnterTransition();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AdminAccountActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AdminAccountActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
}
private void initializeAfterBundle(Bundle bundle) {
if (bundle != null) {
adminAccount = (AdminAccount) bundle.getSerializable(Helper.ARG_ACCOUNT);
account_id = bundle.getString(Helper.ARG_ACCOUNT_ID, null);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
adminVM = new ViewModelProvider(AdminAccountActivity.this).get(AdminVM.class);
if (account_id != null) {
adminVM.getAccount(MainActivity.currentInstance, MainActivity.currentToken, account_id).observe(this, this::initializeView);
return;
}
if (adminAccount != null && adminAccount.account != null) {
initializeView(adminAccount);
binding.toolbar.setPopupTheme(Helper.popupStyle());
if (account != null) {
new Thread(() -> {
account = SpannableHelper.convertAccount(AdminAccountActivity.this, account);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> initializeView(account);
mainHandler.post(myRunnable);
}).start();
} else {
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
finish();
}
binding.disableAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.enable(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.disabled = false;
binding.disableAction.setText(R.string.disable);
binding.disabled.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "disable ", null, null, null, null);
adminAccount.disabled = true;
binding.disableAction.setText(R.string.undisable);
binding.disabled.setText(R.string.yes);
}
});
binding.approveAction.setOnClickListener(v -> {
if (adminAccount.approved) {
adminVM.reject(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount = adminAccountResult;
initializeView(adminAccount);
});
} else {
adminVM.approve(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id);
adminAccount.approved = true;
initializeView(adminAccount);
}
});
binding.silenceAction.setOnClickListener(v -> {
if (adminAccount.silenced) {
adminVM.unsilence(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount = adminAccountResult;
initializeView(adminAccount);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "silence", null, null, null, null);
adminAccount.silenced = true;
initializeView(adminAccount);
}
});
binding.suspendAction.setOnClickListener(v -> {
if (adminAccount.suspended) {
adminVM.unsuspend(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount = adminAccountResult;
initializeView(adminAccount);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, adminAccount.id, "suspend", null, null, null, null);
adminAccount.suspended = true;
initializeView(adminAccount);
}
});
}
private void initializeView(AdminAccount adminAccount) {
private void initializeView(Account account) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(AdminAccountActivity.this);
if (adminAccount == null) {
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
if (account == null) {
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
finish();
return;
}
binding.title.setText(String.format(Locale.getDefault(), "@%s", adminAccount.account.acct));
binding.title.setText(String.format(Locale.getDefault(), "@%s", account.acct));
// MastodonHelper.loadPPMastodon(binding.profilePicture, account);
binding.appBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
@ -213,18 +140,14 @@ public class AdminAccountActivity extends BaseActivity {
}
});
binding.username.setText(String.format(Locale.getDefault(), "@%s", adminAccount.username));
binding.domain.setText(adminAccount.domain);
binding.email.setText(adminAccount.email);
StringBuilder lastActive = new StringBuilder();
if (adminAccount.ips != null) {
int count = 0;
for (AdminIp ip : adminAccount.ips) {
for (AdminAccount.IP ip : adminAccount.ips) {
lastActive.append(Helper.shortDateToString(ip.used_at)).append(" - ").append(ip.ip).append("\r\n");
count++;
if (count > 4) {
break;
}
}
}
if (lastActive.toString().trim().length() == 0) {
@ -244,9 +167,78 @@ public class AdminAccountActivity extends BaseActivity {
binding.silenceAction.setText(adminAccount.silenced ? R.string.unsilence : R.string.silence);
binding.suspendAction.setText(adminAccount.suspended ? R.string.unsuspend : R.string.suspend);
AdminVM adminVM = new ViewModelProvider(AdminAccountActivity.this).get(AdminVM.class);
binding.disableAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.enable(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.disabled = false;
binding.disableAction.setText(R.string.disable);
binding.disabled.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, "disable ", null, null, null, null);
adminAccount.disabled = true;
binding.disableAction.setText(R.string.undisable);
binding.disabled.setText(R.string.yes);
}
});
binding.approveAction.setOnClickListener(v -> {
if (adminAccount.approved) {
adminVM.reject(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.approved = false;
binding.approveAction.setText(R.string.approve);
binding.approved.setText(R.string.no);
});
} else {
adminVM.approve(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id);
adminAccount.approved = true;
binding.approveAction.setText(R.string.reject);
binding.approved.setText(R.string.yes);
}
});
binding.silenceAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.unsilence(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.silenced = false;
binding.silenceAction.setText(R.string.silence);
binding.disabled.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, "silence", null, null, null, null);
adminAccount.silenced = true;
binding.disableAction.setText(R.string.unsilence);
binding.disabled.setText(R.string.yes);
}
});
binding.suspendAction.setOnClickListener(v -> {
if (adminAccount.disabled) {
adminVM.unsuspend(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id)
.observe(AdminAccountActivity.this, adminAccountResult -> {
adminAccount.suspended = false;
binding.suspendAction.setText(R.string.suspend);
binding.suspended.setText(R.string.no);
});
} else {
adminVM.performAction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, "suspend", null, null, null, null);
adminAccount.suspended = true;
binding.disableAction.setText(R.string.unsuspend);
binding.suspended.setText(R.string.yes);
}
});
//Retrieve relationship with the connected account
List<String> accountListToCheck = new ArrayList<>();
accountListToCheck.add(account.id);
//Animate emojis
if (adminAccount.account.emojis != null && adminAccount.account.emojis.size() > 0) {
if (account.emojis != null && account.emojis.size() > 0) {
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false);
if (!disableAnimatedEmoji) {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
@ -257,35 +249,35 @@ public class AdminAccountActivity extends BaseActivity {
//Tablayout for timelines/following/followers
boolean disableGif = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_GIF), false);
String targetedUrl = disableGif ? adminAccount.account.avatar_static : adminAccount.account.avatar;
String targetedUrl = disableGif ? account.avatar_static : account.avatar;
Glide.with(AdminAccountActivity.this)
.asDrawable()
.dontTransform()
.load(targetedUrl).into(
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
}
);
}
}
);
//Load header
MastodonHelper.loadProfileMediaMastodon(AdminAccountActivity.this, binding.bannerPp, adminAccount.account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, account, MastodonHelper.MediaAccountType.HEADER);
//Redraws icon for locked accounts
final float scale = getResources().getDisplayMetrics().density;
if (adminAccount.account.locked) {
if (account.locked) {
Drawable img = ContextCompat.getDrawable(AdminAccountActivity.this, R.drawable.ic_baseline_lock_24);
assert img != null;
img.setBounds(0, 0, (int) (16 * scale + 0.5f), (int) (16 * scale + 0.5f));
@ -295,41 +287,38 @@ public class AdminAccountActivity extends BaseActivity {
}
//Peertube account watched by a Mastodon account
//Bot account
if (adminAccount.account.bot) {
if (account.bot) {
binding.accountBot.setVisibility(View.VISIBLE);
}
if (adminAccount.account.acct != null) {
setTitle(adminAccount.account.acct);
if (account.acct != null) {
setTitle(account.acct);
}
final SpannableString content = new SpannableString(getString(R.string.disclaimer_full));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
content.setSpan(new ForegroundColorSpan(ThemeHelper.getAttColor(this, R.attr.colorPrimary)), 0, content.length(),
content.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AdminAccountActivity.this, R.color.cyanea_accent_reference)), 0, content.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//This account was moved to another one
if (adminAccount.account.moved != null) {
if (account.moved != null) {
binding.accountMoved.setVisibility(View.VISIBLE);
Drawable imgTravel = ContextCompat.getDrawable(AdminAccountActivity.this, R.drawable.ic_baseline_card_travel_24);
assert imgTravel != null;
imgTravel.setBounds(0, 0, (int) (20 * scale + 0.5f), (int) (20 * scale + 0.5f));
binding.accountMoved.setCompoundDrawables(imgTravel, null, null, null);
//Retrieves content and make account names clickable
SpannableString spannableString = SpannableHelper.moveToText(AdminAccountActivity.this, adminAccount.account);
SpannableString spannableString = SpannableHelper.moveToText(AdminAccountActivity.this, account);
binding.accountMoved.setText(spannableString, TextView.BufferType.SPANNABLE);
binding.accountMoved.setMovementMethod(LinkMovementMethod.getInstance());
}
binding.accountDn.setText(
adminAccount.account.getSpanDisplayNameEmoji(AdminAccountActivity.this,
new WeakReference<>(binding.accountDn)),
TextView.BufferType.SPANNABLE);
binding.accountUn.setText(String.format("@%s", adminAccount.account.acct));
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
binding.accountUn.setText(String.format("@%s", account.acct));
binding.accountUn.setOnLongClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
String account_id = adminAccount.account.acct;
String account_id = account.acct;
if (account_id.split("@").length == 1)
account_id += "@" + BaseMainActivity.currentInstance;
ClipData clip = ClipData.newPlainText("mastodon_account_id", "@" + account_id);
@ -339,36 +328,32 @@ public class AdminAccountActivity extends BaseActivity {
return false;
});
MastodonHelper.loadPPMastodon(binding.accountPp, adminAccount.account);
MastodonHelper.loadPPMastodon(binding.accountPp, account);
binding.accountPp.setOnClickListener(v -> {
Intent intent = new Intent(AdminAccountActivity.this, MediaActivity.class);
Bundle args = new Bundle();
Bundle b = new Bundle();
Attachment attachment = new Attachment();
attachment.description = adminAccount.account.acct;
attachment.preview_url = adminAccount.account.avatar;
attachment.url = adminAccount.account.avatar;
attachment.remote_url = adminAccount.account.avatar;
attachment.description = account.acct;
attachment.preview_url = account.avatar;
attachment.url = account.avatar;
attachment.remote_url = account.avatar;
attachment.type = "image";
ArrayList<Attachment> attachments = new ArrayList<>();
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(AdminAccountActivity.this).insertBundle(args, Helper.getCurrentAccount(AdminAccountActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(AdminAccountActivity.this, binding.accountPp, attachment.url);
// start the new activity
startActivity(intent, options.toBundle());
});
b.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
b.putInt(Helper.ARG_MEDIA_POSITION, 1);
intent.putExtras(b);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(AdminAccountActivity.this, binding.accountPp, attachment.url);
// start the new activity
startActivity(intent, options.toBundle());
});
binding.accountDate.setText(Helper.shortDateToString(adminAccount.created_at));
binding.accountDate.setText(Helper.shortDateToString(account.created_at));
binding.accountDate.setVisibility(View.VISIBLE);
String[] accountInstanceArray = adminAccount.account.acct.split("@");
String[] accountInstanceArray = account.acct.split("@");
String accountInstance = BaseMainActivity.currentInstance;
if (accountInstanceArray.length > 1) {
accountInstance = accountInstanceArray[1];
@ -382,11 +367,12 @@ public class AdminAccountActivity extends BaseActivity {
binding.instanceInfo.setVisibility(View.VISIBLE);
binding.instanceInfo.setOnClickListener(v -> {
InstanceProfileActivity instanceProfileActivity = new InstanceProfileActivity();
Intent intent = new Intent(AdminAccountActivity.this, InstanceProfileActivity.class);
Bundle b = new Bundle();
b.putString(Helper.ARG_INSTANCE, finalAccountInstance);
instanceProfileActivity.setArguments(b);
instanceProfileActivity.show(getSupportFragmentManager(), null);
intent.putExtras(b);
startActivity(intent);
});
}
});

View file

@ -1,4 +1,4 @@
package app.fedilab.android.mastodon.activities.admin;
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -14,20 +14,13 @@ package app.fedilab.android.mastodon.activities.admin;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.activities.AdminActionActivity.AdminEnum.REPORT;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.ACCOUNT;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.DOMAIN;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.REPORT;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@ -35,156 +28,89 @@ import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.gson.annotations.SerializedName;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityAdminActionsBinding;
import app.fedilab.android.databinding.PopupAdminFilterAccountsBinding;
import app.fedilab.android.databinding.PopupAdminFilterReportsBinding;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminDomainBlock;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.fragment.admin.FragmentAdminAccount;
import app.fedilab.android.mastodon.ui.fragment.admin.FragmentAdminDomain;
import app.fedilab.android.mastodon.ui.fragment.admin.FragmentAdminReport;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.admin.FragmentAdminAccount;
import app.fedilab.android.ui.fragment.admin.FragmentAdminReport;
public class AdminActionActivity extends BaseBarActivity {
public class AdminActionActivity extends BaseActivity {
public static Boolean local = true, remote = true, active = true, pending = true, disabled = true, silenced = true, suspended = true, staff = null, orderByMostRecent = true;
public static Boolean resolved = null, reportLocal = true, reportRemote = true;
public static Boolean resolved = false, reportLocal = true, reportRemote = true;
private ActivityAdminActionsBinding binding;
private boolean canGoBack;
private FragmentAdminReport fragmentAdminReport;
private FragmentAdminAccount fragmentAdminAccount;
private FragmentAdminDomain fragmentAdminDomain;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle args = intent.getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AdminActionActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AdminActionActivity.this), bundle -> {
AdminDomainBlock adminDomainBlock = (AdminDomainBlock) bundle.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK);
AdminDomainBlock adminDomainBlockDelete = (AdminDomainBlock) bundle.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK_DELETE);
if (adminDomainBlock != null && adminDomainBlock.domain != null && fragmentAdminDomain != null) {
fragmentAdminDomain.update(adminDomainBlock);
}
if (adminDomainBlockDelete != null && fragmentAdminDomain != null) {
fragmentAdminDomain.delete(adminDomainBlockDelete);
}
});
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyThemeBar(this);
binding = ActivityAdminActionsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
ContextCompat.registerReceiver(AdminActionActivity.this, mReceiver, new IntentFilter(Helper.BROADCAST_DATA), ContextCompat.RECEIVER_NOT_EXPORTED);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
canGoBack = false;
binding.reports.setOnClickListener(v -> displayTimeline(REPORT));
binding.accounts.setOnClickListener(v -> displayTimeline(ACCOUNT));
binding.domains.setOnClickListener(v -> displayTimeline(DOMAIN));
getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (canGoBack) {
canGoBack = false;
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.buttonContainer, () -> {
if (fragmentAdminReport != null) {
fragmentAdminReport.onDestroyView();
fragmentAdminReport = null;
}
if (fragmentAdminAccount != null) {
fragmentAdminAccount.onDestroyView();
fragmentAdminAccount = null;
}
if (fragmentAdminDomain != null) {
fragmentAdminDomain.onDestroyView();
fragmentAdminDomain = null;
}
setTitle(R.string.administration);
invalidateOptionsMenu();
});
} else {
finish();
}
}
});
binding.accounts.setOnClickListener(v -> displayTimeline(AdminEnum.ACCOUNT));
}
private void displayTimeline(AdminEnum type) {
canGoBack = true;
if (type == REPORT) {
fragmentAdminReport = new FragmentAdminReport();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminReport.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminReport);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
});
} else if (type == ACCOUNT) {
fragmentAdminAccount = new FragmentAdminAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminAccount);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminReport = new FragmentAdminReport();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminReport.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminReport);
fragmentTransaction.commit();
});
} else if (type == DOMAIN) {
fragmentAdminDomain = new FragmentAdminDomain();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminDomain.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminDomain);
fragmentTransaction.commit();
} else {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminAccount = new FragmentAdminAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminAccount);
fragmentTransaction.commit();
});
}
switch (type) {
case REPORT -> setTitle(R.string.reports);
case ACCOUNT -> setTitle(R.string.accounts);
case DOMAIN -> setTitle(R.string.domains);
case REPORT:
setTitle(R.string.reports);
break;
case ACCOUNT:
setTitle(R.string.accounts);
break;
}
invalidateOptionsMenu();
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
if (canGoBack && fragmentAdminAccount != null) {
if (canGoBack) {
getMenuInflater().inflate(R.menu.menu_admin_account, menu);
}
return super.onCreateOptionsMenu(menu);
@ -193,11 +119,11 @@ public class AdminActionActivity extends BaseBarActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getOnBackPressedDispatcher().onBackPressed();
onBackPressed();
return true;
} else if (item.getItemId() == R.id.action_filter) {
if (getTitle().toString().equalsIgnoreCase(getString(R.string.accounts))) {
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(AdminActionActivity.this);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(AdminActionActivity.this, Helper.dialogStyle());
PopupAdminFilterAccountsBinding binding = PopupAdminFilterAccountsBinding.inflate(getLayoutInflater());
alertDialogBuilder.setView(binding.getRoot());
if (local != null && remote == null) {
@ -229,8 +155,6 @@ public class AdminActionActivity extends BaseBarActivity {
binding.moderationAll.setChecked(true);
}
binding.moderation.setOnCheckedChangeListener((group, checkedId) -> {
disabled = null;
silenced = null;
if (checkedId == R.id.moderation_all) {
active = true;
suspended = true;
@ -291,7 +215,7 @@ public class AdminActionActivity extends BaseBarActivity {
AlertDialog alert = alertDialogBuilder.create();
alert.show();
} else {
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(AdminActionActivity.this);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(AdminActionActivity.this, Helper.dialogStyle());
PopupAdminFilterReportsBinding binding = PopupAdminFilterReportsBinding.inflate(getLayoutInflater());
alertDialogBuilder.setView(binding.getRoot());
if (resolved == null) {
@ -303,7 +227,7 @@ public class AdminActionActivity extends BaseBarActivity {
if (checkedId == R.id.status_resolved) {
resolved = true;
} else if (checkedId == R.id.status_unresolved) {
resolved = null;
resolved = false;
}
});
if (reportLocal != null && reportRemote == null) {
@ -347,25 +271,31 @@ public class AdminActionActivity extends BaseBarActivity {
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReceiver != null) {
try {
unregisterReceiver(mReceiver);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
public void onBackPressed() {
if (canGoBack) {
canGoBack = false;
ThemeHelper.slideViewsToRight(binding.fragmentContainer, binding.buttonContainer, () -> {
if (fragmentAdminReport != null) {
fragmentAdminReport.onDestroyView();
}
if (fragmentAdminAccount != null) {
fragmentAdminAccount.onDestroyView();
}
setTitle(R.string.administration);
invalidateOptionsMenu();
});
} else {
super.onBackPressed();
}
}
}
public enum AdminEnum {
@SerializedName("REPORT")
REPORT("REPORT"),
@SerializedName("ACCOUNT")
ACCOUNT("ACCOUNT"),
@SerializedName("DOMAIN")
DOMAIN("DOMAIN");
ACCOUNT("ACCOUNT");
private final String value;
AdminEnum(String value) {

View file

@ -1,4 +1,4 @@
package app.fedilab.android.mastodon.activities.admin;
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -19,14 +19,16 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
@ -44,8 +46,8 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -53,25 +55,20 @@ import java.util.concurrent.TimeUnit;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.AdminAccount;
import app.fedilab.android.client.entities.api.Attachment;
import app.fedilab.android.databinding.ActivityAdminAccountBinding;
import app.fedilab.android.mastodon.activities.BaseBarActivity;
import app.fedilab.android.mastodon.activities.InstanceProfileActivity;
import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminAccount;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminIp;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.SpannableHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.AdminVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.NodeInfoVM;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
import app.fedilab.android.helper.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.viewmodel.mastodon.AdminVM;
import app.fedilab.android.viewmodel.mastodon.NodeInfoVM;
import es.dmoral.toasty.Toasty;
public class AdminReportActivity extends BaseBarActivity {
public class AdminReportActivity extends BaseActivity {
private AdminAccount adminAccount;
private Account account;
@ -82,46 +79,42 @@ public class AdminReportActivity extends BaseBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
binding = ActivityAdminAccountBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ActionBar actionBar = getSupportActionBar();
Bundle args = getIntent().getExtras();
postponeEnterTransition();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
}
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AdminReportActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AdminReportActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
}
private void initializeAfterBundle(Bundle bundle) {
if (bundle != null) {
adminAccount = (AdminAccount) bundle.getSerializable(Helper.ARG_ACCOUNT);
Bundle b = getIntent().getExtras();
if (b != null) {
adminAccount = (AdminAccount) b.getSerializable(Helper.ARG_ACCOUNT);
if (adminAccount != null) {
account = adminAccount.account;
}
}
postponeEnterTransition();
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
binding.toolbar.setPopupTheme(Helper.popupStyle());
if (account != null) {
initializeView(account);
new Thread(() -> {
account = SpannableHelper.convertAccount(AdminReportActivity.this, account);
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> initializeView(account);
mainHandler.post(myRunnable);
}).start();
} else {
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
finish();
}
}
@ -129,7 +122,7 @@ public class AdminReportActivity extends BaseBarActivity {
private void initializeView(Account account) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(AdminReportActivity.this);
if (account == null) {
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
finish();
return;
}
@ -153,14 +146,14 @@ public class AdminReportActivity extends BaseBarActivity {
binding.email.setText(adminAccount.email);
StringBuilder lastActive = new StringBuilder();
if (adminAccount.ips != null) {
for (AdminIp ip : adminAccount.ips) {
for (AdminAccount.IP ip : adminAccount.ips) {
lastActive.append(Helper.shortDateToString(ip.used_at)).append(" - ").append(ip.ip).append("\r\n");
}
}
if (lastActive.toString().trim().isEmpty()) {
if (lastActive.toString().trim().length() == 0) {
binding.lastActiveContainer.setVisibility(View.GONE);
}
if (adminAccount.email == null || adminAccount.email.trim().isEmpty()) {
if (adminAccount.email == null || adminAccount.email.trim().length() == 0) {
binding.emailContainer.setVisibility(View.GONE);
}
binding.lastActive.setText(lastActive.toString());
@ -259,8 +252,11 @@ public class AdminReportActivity extends BaseBarActivity {
});
//Retrieve relationship with the connected account
List<String> accountListToCheck = new ArrayList<>();
accountListToCheck.add(account.id);
//Animate emojis
if (account.emojis != null && !account.emojis.isEmpty()) {
if (account.emojis != null && account.emojis.size() > 0) {
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false);
if (!disableAnimatedEmoji) {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
@ -276,27 +272,27 @@ public class AdminReportActivity extends BaseBarActivity {
.asDrawable()
.dontTransform()
.load(targetedUrl).into(
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull final Drawable resource, Transition<? super Drawable> transition) {
binding.profilePicture.setImageDrawable(resource);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
binding.profilePicture.setImageResource(R.drawable.ic_person);
startPostponedEnterTransition();
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
}
);
}
}
);
//Load header
MastodonHelper.loadProfileMediaMastodon(AdminReportActivity.this, binding.bannerPp, account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadProfileMediaMastodon(binding.bannerPp, account, MastodonHelper.MediaAccountType.HEADER);
//Redraws icon for locked accounts
final float scale = getResources().getDisplayMetrics().density;
if (account.locked) {
@ -319,7 +315,7 @@ public class AdminReportActivity extends BaseBarActivity {
final SpannableString content = new SpannableString(getString(R.string.disclaimer_full));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
content.setSpan(new ForegroundColorSpan(ThemeHelper.getAttColor(this, R.attr.colorPrimary)), 0, content.length(),
content.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AdminReportActivity.this, R.color.cyanea_accent_reference)), 0, content.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//This account was moved to another one
@ -335,10 +331,8 @@ public class AdminReportActivity extends BaseBarActivity {
binding.accountMoved.setMovementMethod(LinkMovementMethod.getInstance());
}
binding.accountDn.setText(
account.getSpanDisplayNameEmoji(AdminReportActivity.this,
new WeakReference<>(binding.accountDn)),
TextView.BufferType.SPANNABLE);
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
binding.accountUn.setText(String.format("@%s", account.acct));
binding.accountUn.setOnLongClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
@ -355,7 +349,7 @@ public class AdminReportActivity extends BaseBarActivity {
MastodonHelper.loadPPMastodon(binding.accountPp, account);
binding.accountPp.setOnClickListener(v -> {
Intent intent = new Intent(AdminReportActivity.this, MediaActivity.class);
Bundle args = new Bundle();
Bundle b = new Bundle();
Attachment attachment = new Attachment();
attachment.description = account.acct;
attachment.preview_url = account.avatar;
@ -364,16 +358,13 @@ public class AdminReportActivity extends BaseBarActivity {
attachment.type = "image";
ArrayList<Attachment> attachments = new ArrayList<>();
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(AdminReportActivity.this).insertBundle(args, Helper.getCurrentAccount(AdminReportActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(AdminReportActivity.this, binding.accountPp, attachment.url);
startActivity(intent, options.toBundle());
});
b.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
b.putInt(Helper.ARG_MEDIA_POSITION, 1);
intent.putExtras(b);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(AdminReportActivity.this, binding.accountPp, attachment.url);
// start the new activity
startActivity(intent, options.toBundle());
});
@ -394,11 +385,12 @@ public class AdminReportActivity extends BaseBarActivity {
binding.instanceInfo.setVisibility(View.VISIBLE);
binding.instanceInfo.setOnClickListener(v -> {
InstanceProfileActivity instanceProfileActivity = new InstanceProfileActivity();
Intent intent = new Intent(AdminReportActivity.this, InstanceProfileActivity.class);
Bundle b = new Bundle();
b.putString(Helper.ARG_INSTANCE, finalAccountInstance);
instanceProfileActivity.setArguments(b);
instanceProfileActivity.show(getSupportFragmentManager(), null);
intent.putExtras(b);
startActivity(intent);
});
}
});

View file

@ -1,4 +1,4 @@
package app.fedilab.android.mastodon.activities;
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -18,20 +18,20 @@ package app.fedilab.android.mastodon.activities;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.emojis;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.preference.PreferenceManager;
import androidx.core.content.ContextCompat;
import app.fedilab.android.R;
import app.fedilab.android.client.entities.api.EmojiInstance;
import app.fedilab.android.databinding.ActivityAnnouncementBinding;
import app.fedilab.android.mastodon.client.entities.api.EmojiInstance;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonAnnouncement;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonAnnouncement;
public class AnnouncementActivity extends BaseActivity {
@ -40,7 +40,7 @@ public class AnnouncementActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.applyTheme(this);
ActivityAnnouncementBinding binding = ActivityAnnouncementBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@ -50,15 +50,14 @@ public class AnnouncementActivity extends BaseActivity {
//Remove title
if (actionBar != null) {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
}
binding.title.setText(R.string.action_announcements);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_tags, new FragmentMastodonAnnouncement(), null, null, null);
if (emojis == null || !emojis.containsKey(currentInstance)) {
new Thread(() -> {

View file

@ -1,5 +1,5 @@
package app.fedilab.android.activities;
/* Copyright 2023 Thomas Schneider
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
@ -15,28 +15,32 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import app.fedilab.android.databinding.ActivityMainPeertubeBinding;
import app.fedilab.android.mastodon.activities.BaseActivity;
import androidx.annotation.Nullable;
import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.ThemeHelper;
public class PeertubeBaseMainActivity extends BaseActivity {
@SuppressLint("Registered")
public class BaseActivity extends CyaneaAppCompatActivity {
protected ActivityMainPeertubeBinding parentBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
parentBinding = ActivityMainPeertubeBinding.inflate(getLayoutInflater());
View view = parentBinding.getRoot();
setContentView(view);
static {
Helper.installProvider();
EmojiManager.install(new EmojiOneProvider());
}
//Method for discovering cast devices
public void discoverCast() {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeHelper.adjustFontScale(this, getResources().getConfiguration());
Helper.setLocale(this);
}
}

View file

@ -1,4 +1,4 @@
package app.fedilab.android.mastodon.client.entities.app;
package app.fedilab.android.activities;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
@ -14,21 +14,23 @@ package app.fedilab.android.mastodon.client.entities.app;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import com.google.gson.annotations.SerializedName;
import android.annotation.SuppressLint;
import java.io.Serializable;
import java.util.List;
import com.jaredrummler.cyanea.app.CyaneaFragmentActivity;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
import app.fedilab.android.helper.Helper;
public class Quotes implements Serializable {
@SuppressLint("Registered")
public class BaseFragmentActivity extends CyaneaFragmentActivity {
@SerializedName("quotes")
public List<Quote> quotes;
public static class Quote implements Serializable {
@SerializedName("author")
public String author;
@SerializedName("content")
public String content;
static {
Helper.installProvider();
EmojiManager.install(new EmojiOneProvider());
}
}

Some files were not shown because too many files have changed in this diff Show more