Compare commits

...

69 Commits

Author SHA1 Message Date
LucasGGamerM
d95b395cfc docs: add changelog 2023-03-07 15:20:40 -03:00
LucasGGamerM
b41b2c8f3c build: bump version 2023-03-07 15:17:34 -03:00
LucasGGamerM
289dc4bf86 Merge remote-tracking branch 'weblate/master'
# Conflicts:
#	mastodon/src/main/res/values-de-rDE/strings_mo.xml
#	mastodon/src/main/res/values-pt-rBR/strings_mo.xml
#	mastodon/src/main/res/values-zh-rCN/strings_mo.xml
2023-03-07 14:52:54 -03:00
CDN18
c34e1e5f32 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (32 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/zh_Hans/
2023-03-07 17:52:01 +00:00
CDN18
729680df8c Translated using Weblate (Chinese (Simplified))
Currently translated at 97.3% (37 of 38 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/zh_Hans/
2023-03-07 17:52:01 +00:00
LucasGGamerM
b85b578ddd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (38 of 38 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-03-07 17:52:01 +00:00
dontobi
8a7d2df7b8 Translated using Weblate (German)
Currently translated at 100.0% (38 of 38 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/de/
2023-03-07 17:52:01 +00:00
LucasGGamerM
3ff3eb819a Translated using Weblate (Portuguese (Brazil))
Currently translated at 9.3% (3 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/pt_BR/
2023-03-07 17:52:01 +00:00
gallegonovato
1ea24b5ff6 Translated using Weblate (Spanish)
Currently translated at 68.7% (22 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/es/
2023-03-07 17:52:01 +00:00
poesty
79d0ab311b Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/zh_Hans/
2023-03-07 17:52:01 +00:00
LucasGGamerM
79f7df089e Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-03-07 17:52:01 +00:00
gallegonovato
32464f8552 Translated using Weblate (Spanish)
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-03-07 17:52:01 +00:00
dontobi
7ce96a2311 Translated using Weblate (German)
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/de/
2023-03-07 17:52:01 +00:00
dontobi
a009ea212f Translated using Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/de/
2023-03-07 17:52:01 +00:00
LucasGGamerM
8848b75325 Merge remote-tracking branch 'weblate/master' 2023-03-07 14:51:16 -03:00
LucasGGamerM
2eb04a3835 Merge remote-tracking branch 'megalodon_weblate/main' 2023-03-07 14:51:06 -03:00
LucasGGamerM
b61ce8399e docs: add translation widget to READMe 2023-03-07 14:49:07 -03:00
LucasGGamerM
52392c9ed9 feat: add toggle for defaulting to unlisted replies 2023-03-07 14:29:48 -03:00
LucasGGamerM
4b35ac6ad8 refactor(settings-page): move Disable Swipe setting between tabs to behavior section 2023-03-07 14:03:02 -03:00
LucasGGamerM
a56b603c5c refactor(settings-page): change the order of the sections 2023-03-07 14:00:38 -03:00
LucasGGamerM
48bd277769 refactor(mute-user-timer): add bottom padding for design consistency 2023-03-06 21:07:48 -03:00
LucasGGamerM
04101eb31b refactor(settings-page): adding new sections and reorganizing settings 2023-03-06 20:52:58 -03:00
LucasGGamerM
34c6a76a53 Translated using Weblate (Portuguese (Brazil))
Currently translated at 9.3% (3 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/pt_BR/
2023-03-06 23:39:04 +00:00
gallegonovato
3f20c6104a Translated using Weblate (Spanish)
Currently translated at 68.7% (22 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/es/
2023-03-06 23:39:04 +00:00
poesty
b5f82261b0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/zh_Hans/
2023-03-06 23:39:04 +00:00
LucasGGamerM
b9a5db7ea4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-03-06 23:39:04 +00:00
gallegonovato
64cb6e52a8 Translated using Weblate (Spanish)
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-03-06 23:39:04 +00:00
dontobi
6e96e8929f Translated using Weblate (German)
Currently translated at 100.0% (26 of 26 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/de/
2023-03-06 23:39:04 +00:00
dontobi
bdd48f0001 Translated using Weblate (German)
Currently translated at 100.0% (32 of 32 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/de/
2023-03-06 23:39:04 +00:00
LucasGGamerM
4bf19adc8e chore: add new strings 2023-03-06 20:38:51 -03:00
LucasGGamerM
bb9ff3c33f feat(unlisted-replies-by-default-toggle): add relevant string 2023-03-06 20:24:05 -03:00
LucasGGamerM
ae11e78d78 refactor: increase border radius of inline buttons 2023-03-06 20:20:52 -03:00
LucasGGamerM
222c3a2526 refactor(add-mute-timer): change of the mute timer popup layout 2023-03-06 20:19:21 -03:00
LucasGGamerM
08aa64a666 fix(strings): fix typo in "day" 2023-03-06 20:00:51 -03:00
LucasGGamerM
f10c157598 Merge branch 'master' of https://github.com/LucasGGamerM/moshidon 2023-03-06 19:54:08 -03:00
LucasGGamerM
5059d8fc4f Merge pull request #111 from FineFindus/feat/mute-timer
feat: add mute timer
2023-03-06 19:53:45 -03:00
FineFindus
4152179dea fix(request/mute): add correct body on unmute 2023-03-06 22:00:49 +01:00
FineFindus
3619be71ab feat: add mute timer 2023-03-06 21:55:32 +01:00
AiOO
810e9eeb11 Translated using Weblate (Korean)
Currently translated at 100.0% (16 of 16 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2023-03-05 15:08:20 +00:00
AiOO
25cff94665 Translated using Weblate (Korean)
Currently translated at 100.0% (262 of 262 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-03-05 15:08:20 +00:00
LucasGGamerM
0e08209f4c style: remove unused imports on CustomLocalTimelineFragment.java 2023-03-04 10:33:07 -03:00
LucasGGamerM
db0b4fb615 refactor(README): swappping "this app" to Moshidon in FAQ 2023-03-04 10:21:02 -03:00
LucasGGamerM
672cfe58d6 fix(notification-actions): replies done within the notification actions now respect the status language and visibility, and also automatically add a mention to the replied account at the end of the reply status. 2023-03-04 10:13:03 -03:00
LucasGGamerM
338e164143 refactor: moving "notification_action_replied" string to strings_mo.xml 2023-03-04 10:07:28 -03:00
LucasGGamerM
e964b76302 refactor: re-using strings in the notification actions instead of new ones 2023-03-04 10:03:53 -03:00
LucasGGamerM
8dedc77ff8 Merge pull request #108
feat(notification): add reply action
2023-03-04 09:44:14 -03:00
LucasGGamerM
3b762c14a1 docs: Add faq section to README 2023-03-04 08:25:43 -03:00
FineFindus
59941fc867 style(notifications-actions/reply): clean-up 2023-03-03 23:49:45 +01:00
FineFindus
50601853f5 feat(notifications/actions): add reply action
Closes https://github.com/LucasGGamerM/moshidon/issues/104
2023-03-03 23:45:07 +01:00
LucasGGamerM
3137f3c1e4 docs: Adding link to Google Play Store 2023-03-03 17:21:49 -03:00
LucasGGamerM
bfaa732544 refactor: Increasing the corner radius of statuses and accounts in the notification section 2023-03-03 16:30:19 -03:00
LucasGGamerM
1b7a257a48 Merge pull request #106 from FineFindus/feat/notification-badge
Feat(tabs): add unread badge to notification tab
2023-03-01 18:12:40 -03:00
LucasGGamerM
4d40fad10d fix: Notifcations not refreshing without manually doing so. Fixes #105 2023-03-01 18:11:07 -03:00
FineFindus
49015f3e3e style: remove unnecessary imports 2023-03-01 22:06:31 +01:00
LucasGGamerM
77b5819c65 Merge pull request #102 from FineFindus/feat/notification-actions
Feat: Add actions to notifications
2023-03-01 18:01:43 -03:00
FineFindus
ac5615497b refactor(notifications-tab/badge): use improved implementation
Removes the now unecessary network call, by hooking into the notification reciever instead.
2023-03-01 22:00:49 +01:00
FineFindus
4ecd525f13 feat(tabs/notifications): add unread badge 2023-03-01 21:44:11 +01:00
FineFindus
b38a460a02 style(notifications/action): fix whitespaces 2023-02-27 21:20:02 +01:00
FineFindus
bddf024ba0 fix(notifications/action): remove unused string 2023-02-27 21:18:51 +01:00
FineFindus
be7a7acadd fix(notifications/action): remove notification after tapping action 2023-02-27 21:15:28 +01:00
FineFindus
d05c90ca7f fix(notifications/action): use radom request code
Fixes the issue with pendingIntents overwriting each other. Probability of equal same request code should be near 0 with 2^32 ints available
2023-02-27 20:24:09 +01:00
FineFindus
4187da9168 feat(notifications/action): remove notfication after action 2023-02-26 21:56:18 +01:00
FineFindus
a051e636e6 feat(notifications/action): add unboost action 2023-02-26 20:50:03 +01:00
FineFindus
360cd7b5df feat(notifications/action): only show actions if necessary 2023-02-26 19:15:31 +01:00
FineFindus
55d2ca4a93 feat(notifications/action): use string titles 2023-02-26 15:23:38 +01:00
FineFindus
c7f61291ed feat(notifications/action): add boost action 2023-02-26 15:21:52 +01:00
FineFindus
f404895b5c feat(notification): add actions 2023-02-25 23:19:41 +01:00
FineFindus
94ed0c3f49 Merge branch 'master' 2023-02-25 21:00:09 +01:00
FineFindus
00ffe9c41e Merge branch 'master' 2023-02-25 21:00:04 +01:00
53 changed files with 571 additions and 68 deletions

View File

@@ -5,13 +5,24 @@
> A fork of [megalodon](https://github.com/sk22/megalodon) which is a fork of [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly wont ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
[![Download latest release](https://img.shields.io/badge/dynamic/json?color=282C37&label=download%20apk&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FLucasGGamerM%2Fmoshidon%2Freleases%2Flatest&style=for-the-badge)](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
[![Download latest release](https://img.shields.io/badge/dynamic/json?color=282C37&label=Download%20APK&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FLucasGGamerM%2Fmoshidon%2Freleases%2Flatest&style=for-the-badge)](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
[![Translation status](https://translate.codeberg.org/widgets/moshidon/-/svg-badge.svg)](https://translate.codeberg.org/engage/moshidon/)
 
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.moshinda"><img height="50" alt="Get it on Google Play" src="img/google-play-badge.png"></a>
&nbsp;
<a href="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
alt="Get it on IzzyOnDroid"
height="80">](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda)
---
## F.A.Q
### Q: What are the main differences between Moshidon and Megalodon?
### A: There are many, but the most outstanding differences are: the ability to have other server's local timeline inside the app. It can be acessed in the "Add community" option in the top right corner of the Edit timelines screen. Most other features are pretty minor, such as profile notes directly available in the person's profile. Other features are quite minor usability and visibility improvements. All of which can be found in the settings page.
---
## Key features

View File

@@ -9,8 +9,8 @@ android {
applicationId "org.joinmastodon.android.moshinda"
minSdk 23
targetSdk 33
versionCode 98
versionName "1.2.0+fork.98.moshinda"
versionCode 99
versionName "1.2.0+fork.99.moshinda"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "nl-rNL", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
}

View File

@@ -47,6 +47,8 @@ public class GlobalUserPreferences{
public static boolean collapseLongPosts;
public static boolean spectatorMode;
public static boolean autoHideFab;
public static boolean unreadNotifications;
public static boolean defaultToUnlistedReplies;
public static String publishButtonText;
public static ThemePreference theme;
public static ColorPreference color;
@@ -101,6 +103,8 @@ public class GlobalUserPreferences{
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
spectatorMode=prefs.getBoolean("spectatorMode", false);
autoHideFab=prefs.getBoolean("autoHideFab", true);
unreadNotifications=prefs.getBoolean("unreadNotifications", false);
defaultToUnlistedReplies=prefs.getBoolean("defaultToUnlistedReplies", false);
publishButtonText=prefs.getString("publishButtonText", "");
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
@@ -150,8 +154,10 @@ public class GlobalUserPreferences{
.putBoolean("collapseLongPosts", collapseLongPosts)
.putBoolean("spectatorMode", spectatorMode)
.putBoolean("autoHideFab", autoHideFab)
.putBoolean("unreadNotifications", unreadNotifications)
.putString("publishButtonText", publishButtonText)
.putBoolean("bottomEncoding", bottomEncoding)
.putBoolean("defaultToUnlistedReplies", defaultToUnlistedReplies)
.putInt("theme", theme.ordinal())
.putString("color", color.name())
.putString("recentLanguages", gson.toJson(recentLanguages))

View File

@@ -7,10 +7,14 @@ import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.requests.accounts.SetPrivateNote;
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
@@ -19,12 +23,17 @@ import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.NotificationAction;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import org.parceler.Parcels;
import androidx.annotation.Nullable;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
public class MainActivity extends FragmentStackActivity{
@Override

View File

@@ -5,6 +5,7 @@ import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -16,15 +17,24 @@ import android.util.Log;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.requests.notifications.GetNotificationByID;
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.NotificationAction;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.PushNotification;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
@@ -37,6 +47,8 @@ public class PushNotificationReceiver extends BroadcastReceiver{
private static final String TAG="PushNotificationReceive";
public static final int NOTIFICATION_ID=178;
private static final String ACTION_KEY_TEXT_REPLY = "ACTION_KEY_TEXT_REPLY";
private static final int SUMMARY_ID = 791;
private static int notificationId = 0;
@@ -76,6 +88,8 @@ public class PushNotificationReceiver extends BroadcastReceiver{
@Override
public void onSuccess(org.joinmastodon.android.model.Notification result){
MastodonAPIController.runInBackground(()->PushNotificationReceiver.this.notify(context, pn, accountID, result));
GlobalUserPreferences.unreadNotifications = true;
GlobalUserPreferences.save();
}
@Override
@@ -92,6 +106,35 @@ public class PushNotificationReceiver extends BroadcastReceiver{
Log.w(TAG, "onReceive: invalid push notification format");
}
}
if(intent.getBooleanExtra("fromNotificationAction", false)){
String accountID=intent.getStringExtra("accountID");
int notificationId=intent.getIntExtra("notificationId", -1);
if (notificationId >= 0){
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(accountID, notificationId);
}
if(intent.hasExtra("notification")){
org.joinmastodon.android.model.Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
String statusID=notification.status.id;
if (statusID != null) {
AccountSessionManager accountSessionManager = AccountSessionManager.getInstance();
Preferences preferences = accountSessionManager.getAccount(accountID).preferences;
switch (NotificationAction.values()[intent.getIntExtra("notificationAction", 0)]) {
case FAVORITE -> new SetStatusFavorited(statusID, true).exec(accountID);
case BOOKMARK -> new SetStatusBookmarked(statusID, true).exec(accountID);
case BOOST -> new SetStatusReblogged(notification.status.id, true, preferences.postingDefaultVisibility).exec(accountID);
case UNBOOST -> new SetStatusReblogged(notification.status.id, false, preferences.postingDefaultVisibility).exec(accountID);
case REPLY -> handleReplyAction(context, accountID, intent, notification, notificationId, preferences);
default -> Log.w(TAG, "onReceive: Failed to get NotificationAction");
}
}
}else{
Log.e(TAG, "onReceive: Failed to load notification");
}
}
}
private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){
@@ -165,6 +208,90 @@ public class PushNotificationReceiver extends BroadcastReceiver{
if(AccountSessionManager.getInstance().getLoggedInAccounts().size()>1){
builder.setSubText(accountName);
}
nm.notify(accountID, GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId++, builder.build());
int id = GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId++;
if (notification != null){
switch (pn.notificationType){
case MENTION, STATUS -> {
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
builder.addAction(buildReplyAction(context, id, accountID, notification));
}
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_favorite), NotificationAction.FAVORITE));
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.add_bookmark), NotificationAction.BOOKMARK));
if(notification.status.visibility != StatusPrivacy.DIRECT) {
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.button_reblog), NotificationAction.BOOST));
}
}
case UPDATE -> {
if(notification.status.reblogged)
builder.addAction(buildNotificationAction(context, id, accountID, notification, context.getString(R.string.sk_undo_reblog), NotificationAction.UNBOOST));
}
}
}
nm.notify(accountID, id, builder.build());
}
private Notification.Action buildNotificationAction(Context context, int notificationId, String accountID, org.joinmastodon.android.model.Notification notification, String title, NotificationAction action){
Intent notificationIntent=new Intent(context, PushNotificationReceiver.class);
notificationIntent.putExtra("notificationId", notificationId);
notificationIntent.putExtra("fromNotificationAction", true);
notificationIntent.putExtra("accountID", accountID);
notificationIntent.putExtra("notificationAction", action.ordinal());
notificationIntent.putExtra("notification", Parcels.wrap(notification));
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, new Random().nextInt(), notificationIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
return new Notification.Action.Builder(null, title, actionPendingIntent).build();
}
private Notification.Action buildReplyAction(Context context, int notificationId, String accountID, org.joinmastodon.android.model.Notification notification){
String replyLabel = context.getResources().getString(R.string.button_reply);
RemoteInput remoteInput = new RemoteInput.Builder(ACTION_KEY_TEXT_REPLY)
.setLabel(replyLabel)
.build();
Intent notificationIntent=new Intent(context, PushNotificationReceiver.class);
notificationIntent.putExtra("notificationId", notificationId);
notificationIntent.putExtra("fromNotificationAction", true);
notificationIntent.putExtra("accountID", accountID);
notificationIntent.putExtra("notificationAction", NotificationAction.REPLY.ordinal());
notificationIntent.putExtra("notification", Parcels.wrap(notification));
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT : PendingIntent.FLAG_UPDATE_CURRENT;
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(context, new Random().nextInt(), notificationIntent,flags);
return new Notification.Action.Builder(null, replyLabel, replyPendingIntent).addRemoteInput(remoteInput).build();
}
private void handleReplyAction(Context context, String accountID, Intent intent, org.joinmastodon.android.model.Notification notification, int notificationId, Preferences preferences) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput == null) {
Log.e(TAG, "handleReplyAction: Could not get reply input");
return;
}
CharSequence input = remoteInput.getCharSequence(ACTION_KEY_TEXT_REPLY);
CreateStatus.Request req=new CreateStatus.Request();
req.status = input.toString() + "\n\n" + "@" + notification.status.account.acct;
req.language = notification.status.language;
req.visibility = notification.status.visibility;
req.inReplyToId = notification.status.id;
if(!notification.status.spoilerText.isEmpty() && GlobalUserPreferences.prefixRepliesWithRe && !notification.status.spoilerText.startsWith("re: ")){
req.spoilerText = "re: " + notification.status.spoilerText;
}
new CreateStatus(req, UUID.randomUUID().toString()).exec(accountID);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ?
new Notification.Builder(context, accountID+"_"+notification.type) :
new Notification.Builder(context)
.setPriority(Notification.PRIORITY_DEFAULT)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
Notification repliedNotification = builder.setSmallIcon(R.drawable.ic_ntf_logo)
.setContentText(context.getString(R.string.mo_notification_action_replied, notification.status.account.getDisplayUsername()))
.build();
notificationManager.notify(accountID, notificationId, repliedNotification);
}
}

View File

@@ -4,8 +4,15 @@ import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Relationship;
public class SetAccountMuted extends MastodonAPIRequest<Relationship>{
public SetAccountMuted(String id, boolean muted){
public SetAccountMuted(String id, boolean muted, long duration){
super(HttpMethod.POST, "/accounts/"+id+"/"+(muted ? "mute" : "unmute"), Relationship.class);
setRequestBody(new Object());
setRequestBody(muted ? new Request(duration): new Object());
}
private static class Request{
public long duration;
public Request(long duration){
this.duration=duration;
}
}
}

View File

@@ -29,6 +29,7 @@ import android.graphics.drawable.LayerDrawable;
import android.icu.text.BreakIterator;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.opengl.Visibility;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
@@ -1945,7 +1946,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
private void loadDefaultStatusVisibility(Bundle savedInstanceState) {
if(replyTo != null) statusVisibility = replyTo.visibility;
if(replyTo != null) {
statusVisibility = (replyTo.visibility == StatusPrivacy.PUBLIC && GlobalUserPreferences.defaultToUnlistedReplies ? StatusPrivacy.UNLISTED : replyTo.visibility);
}
// A saved privacy setting from a previous compose session wins over the reply visibility
if(savedInstanceState !=null){

View File

@@ -1,27 +1,14 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuInflater;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountByHandle;
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.SearchResults;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.List;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
public class CustomLocalTimelineFragment extends StatusListFragment {

View File

@@ -16,6 +16,10 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -28,8 +32,6 @@ import org.parceler.Parcels;
import java.util.ArrayList;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.fragments.LoaderFragment;
@@ -52,6 +54,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private TabBar tabBar;
private View tabBarWrap;
private ImageView tabBarAvatar;
private ImageView notificationTabIcon;
@IdRes
private int currentTab=R.id.tab_home;
@@ -117,6 +120,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
ViewImageLoader.load(tabBarAvatar, null, new UrlImageLoaderRequest(self.avatar, V.dp(28), V.dp(28)));
notificationTabIcon=content.findViewById(R.id.tab_notifications);
setNotificationBadge();
if(savedInstanceState==null){
getChildFragmentManager().beginTransaction()
.add(R.id.fragment_wrap, homeTabFragment)
@@ -255,6 +261,13 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
scrollable.scrollToTop();
return;
}
if(tab == R.id.tab_notifications){
GlobalUserPreferences.unreadNotifications = false;
GlobalUserPreferences.save();
setNotificationBadge();
}
getChildFragmentManager().beginTransaction().hide(fragmentForTab(currentTab)).show(newFragment).commit();
maybeTriggerLoading(newFragment);
currentTab=tab;
@@ -327,4 +340,8 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
// getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
// getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
}
private void setNotificationBadge() {
notificationTabIcon.setImageDrawable(getContext().getDrawable(GlobalUserPreferences.unreadNotifications ? R.drawable.ic_notifications_tab_badged : R.drawable.ic_fluent_alert_28_selector));
}
}

View File

@@ -166,8 +166,11 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
@Override
protected void onShown(){
super.onShown();
// if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
// loadData();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading){
refreshing=true;
loadData();
}
}
@Override

View File

@@ -199,46 +199,38 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.alwaysExpandContentWarnings=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_tabs_disable_swipe, R.drawable.ic_fluent_swipe_right_24_regular, GlobalUserPreferences.disableSwipe, i->{
GlobalUserPreferences.disableSwipe=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_enable_delete_notifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, GlobalUserPreferences.enableDeleteNotifications, i->{
GlobalUserPreferences.enableDeleteNotifications=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
// items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged));
items.add(new SwitchItem(R.string.mo_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{
GlobalUserPreferences.disableDividers=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.mo_hide_compose_button_while_scrolling_setting, R.drawable.ic_fluent_edit_24_regular, GlobalUserPreferences.enableFabAutoHide, i->{
GlobalUserPreferences.enableFabAutoHide =i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_tabs_disable_swipe, R.drawable.ic_fluent_swipe_right_24_regular, GlobalUserPreferences.disableSwipe, i->{
GlobalUserPreferences.disableSwipe=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new HeaderItem(R.string.mo_composer_behavior));
items.add(new SwitchItem(R.string.mo_change_default_reply_visibility_to_unlisted, R.drawable.ic_fluent_lock_closed_24_regular, GlobalUserPreferences.defaultToUnlistedReplies, i->{
GlobalUserPreferences.defaultToUnlistedReplies=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.mo_relocate_publish_button, R.drawable.ic_fluent_arrow_autofit_down_24_regular, GlobalUserPreferences.relocatePublishButton, i->{
GlobalUserPreferences.relocatePublishButton=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
GlobalUserPreferences.keepOnlyLatestNotification=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_prefix_reply_cw_with_re, R.drawable.ic_fluent_arrow_reply_24_regular, GlobalUserPreferences.prefixRepliesWithRe, i->{
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.mo_disable_reminder_to_add_alt_text, R.drawable.ic_fluent_image_alt_text_24_regular, GlobalUserPreferences.disableAltTextReminder, i->{
GlobalUserPreferences.showNoAltIndicator=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_settings_prefix_reply_cw_with_re, R.drawable.ic_fluent_arrow_reply_24_regular, GlobalUserPreferences.prefixRepliesWithRe, i->{
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
GlobalUserPreferences.save();
}));
items.add(new HeaderItem(R.string.sk_timelines));
items.add(new SwitchItem(R.string.sk_settings_show_replies, R.drawable.ic_fluent_chat_multiple_24_regular, GlobalUserPreferences.showReplies, i->{
@@ -303,6 +295,24 @@ public class SettingsFragment extends MastodonToolbarFragment{
items.add(new SwitchItem(R.string.sk_notify_update, R.drawable.ic_fluent_history_24_regular, pushSubscription.alerts.update, i->onNotificationsChanged(PushNotification.Type.UPDATE, i.checked), switchEnabled));
items.add(new SwitchItem(R.string.sk_notify_poll_results, R.drawable.ic_fluent_poll_24_regular, pushSubscription.alerts.poll, i->onNotificationsChanged(PushNotification.Type.POLL, i.checked), switchEnabled));
items.add(new HeaderItem(R.string.mo_miscellaneous_settings));
items.add(new SwitchItem(R.string.mo_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{
GlobalUserPreferences.disableDividers=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_enable_delete_notifications, R.drawable.ic_fluent_mail_inbox_dismiss_24_regular, GlobalUserPreferences.enableDeleteNotifications, i->{
GlobalUserPreferences.enableDeleteNotifications=i.checked;
GlobalUserPreferences.save();
needAppRestart=true;
}));
items.add(new SwitchItem(R.string.sk_settings_single_notification, R.drawable.ic_fluent_convert_range_24_regular, GlobalUserPreferences.keepOnlyLatestNotification, i->{
GlobalUserPreferences.keepOnlyLatestNotification=i.checked;
GlobalUserPreferences.save();
}));
items.add(new HeaderItem(R.string.settings_account));
items.add(new TextItem(R.string.sk_settings_profile, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/profile"), R.drawable.ic_fluent_open_24_regular));
items.add(new TextItem(R.string.sk_settings_posting, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/preferences/other"), R.drawable.ic_fluent_open_24_regular));

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.model;
public enum NotificationAction {
FAVORITE,
BOOST,
UNBOOST,
BOOKMARK,
REPLY,
}

View File

@@ -111,11 +111,11 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
rejectWrap=findViewById(R.id.reject_btn_wrap);
View card=findViewById(R.id.card);
card.setOutlineProvider(OutlineProviders.roundedRect(6));
card.setOutlineProvider(OutlineProviders.roundedRect(12));
card.setClipToOutline(true);
avatar.setOutlineProvider(OutlineProviders.roundedRect(12));
avatar.setClipToOutline(true);
cover.setOutlineProvider(OutlineProviders.roundedRect(3));
cover.setOutlineProvider(OutlineProviders.roundedRect(12));
cover.setClipToOutline(true);
actionButton.setOnClickListener(this::onActionButtonClick);
acceptButton.setOnClickListener(this::onFollowRequestButtonClick);

View File

@@ -67,13 +67,13 @@ public class InsetStatusItemDecoration extends RecyclerView.ItemDecoration{
paint.setColor(bgColor);
rect.left=V.dp(12);
rect.right=list.getWidth()-V.dp(12);
rect.inset(V.dp(4), V.dp(4));
c.drawRoundRect(rect, V.dp(4), V.dp(4), paint);
rect.intersect(V.dp(4), V.dp(4), V.dp(4), V.dp(-4));
c.drawRoundRect(rect, V.dp(12), V.dp(12), paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(V.dp(1));
paint.setColor(borderColor);
rect.inset(paint.getStrokeWidth()/2f, paint.getStrokeWidth()/2f);
c.drawRoundRect(rect, V.dp(4), V.dp(4), paint);
c.drawRoundRect(rect, V.dp(12), V.dp(12), paint);
}
@Override

View File

@@ -36,7 +36,9 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
@@ -99,6 +101,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@@ -109,6 +112,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -464,12 +468,45 @@ public class UiUtils{
}
public static void confirmToggleMuteUser(Activity activity, String accountID, Account account, boolean currentlyMuted, Consumer<Relationship> resultCallback){
showConfirmationAlert(activity, activity.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title),
activity.getString(currentlyMuted ? R.string.confirm_unmute : R.string.confirm_mute, account.displayName),
activity.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute),
currentlyMuted ? R.drawable.ic_fluent_speaker_0_28_regular : R.drawable.ic_fluent_speaker_off_28_regular,
()->{
new SetAccountMuted(account.id, !currentlyMuted)
View menu = LayoutInflater.from(activity).inflate(R.layout.item_mute_duration, null);
Button button = menu.findViewById(R.id.button);
AtomicReference<Duration> muteDuration = new AtomicReference<>(Duration.ZERO);
PopupMenu popupMenu=new PopupMenu(activity, button, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.mute_duration);
popupMenu.setOnMenuItemClickListener(item -> {
int id = item.getItemId();
if (id == R.id.duration_indefinite)
muteDuration.set(Duration.ZERO);
else if (id == R.id.duration_minutes_5) {
muteDuration.set(Duration.ofMinutes(5));
}else if (id == R.id.duration_minutes_30) {
muteDuration.set(Duration.ofMinutes(30));
}else if (id == R.id.duration_hours_1) {
muteDuration.set(Duration.ofHours(1));
}else if (id == R.id.duration_hours_6) {
muteDuration.set(Duration.ofHours(6));
}else if (id == R.id.duration_days_1) {
muteDuration.set(Duration.ofDays(1));
}else if (id == R.id.duration_days_3) {
muteDuration.set(Duration.ofDays(3));
}else if (id == R.id.duration_days_7) {
muteDuration.set(Duration.ofDays(7));
}
button.setText(item.getTitle());
return true;
});
button.setOnTouchListener(popupMenu.getDragToOpenListener());
button.setOnClickListener(v->popupMenu.show());
button.setText(popupMenu.getMenu().getItem(0).getTitle());
new M3AlertDialogBuilder(activity)
.setTitle(activity.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title))
.setMessage(activity.getString(currentlyMuted ? R.string.confirm_unmute : R.string.confirm_mute, account.displayName))
.setView(currentlyMuted ? null : menu)
.setPositiveButton(activity.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), (dlg, i)-> {
new SetAccountMuted(account.id, !currentlyMuted, muteDuration.get().getSeconds())
.setCallback(new Callback<>(){
@Override
public void onSuccess(Relationship result){
@@ -486,7 +523,10 @@ public class UiUtils{
})
.wrapProgress(activity, R.string.loading, false)
.exec(accountID);
});
})
.setNegativeButton(R.string.cancel, null)
.setIcon(currentlyMuted ? R.drawable.ic_fluent_speaker_0_28_regular : R.drawable.ic_fluent_speaker_off_28_regular)
.show();
}
public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer<Status> resultCallback){
confirmDeletePost(activity, accountID, status, resultCallback, false);

View File

@@ -3,7 +3,7 @@
<item>
<shape>
<solid android:color="?colorPollVoted"/>
<corners android:radius="4dp"/>
<corners android:radius="8dp"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_fluent_alert_28_selector" android:left="2dp" android:right="2dp" android:top="2dp" android:bottom="2dp"/>
<item android:width="14dp" android:height="14dp" android:gravity="top|right">
<shape android:shape="oval">
<stroke android:color="?android:colorPrimary" android:width="2dp"/>
<solid android:color="?android:colorAccent"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:paddingBottom="16dp"
android:gravity="center_vertical"
android:layoutDirection="locale">
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:paddingVertical="8dp"
android:gravity="center_vertical"
android:textColor="?android:textColorPrimary"
android:text="@string/mo_mute_label"
android:textSize="16sp" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_weight="0"
android:layout_marginEnd="24dp"
android:maxWidth="140dp"
android:background="@drawable/bg_inline_button"
android:elevation="0dp"
android:ellipsize="middle"
android:fontFamily="sans-serif-medium"
android:singleLine="true"
android:stateListAnimator="@null"
android:textColor="?android:textColorPrimary"
android:textSize="16sp"
tools:text="@string/mute_user" />
</LinearLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/duration_indefinite" android:title="@string/mo_duration_indefinite" />
<item android:id="@+id/duration_minutes_5" android:title="@string/mo_duration_minutes_5"/>
<item android:id="@+id/duration_minutes_30" android:title="@string/mo_duration_minutes_30"/>
<item android:id="@+id/duration_hours_1" android:title="@string/mo_duration_hours_1"/>
<item android:id="@+id/duration_hours_6" android:title="@string/mo_duration_hours_6"/>
<item android:id="@+id/duration_days_1" android:title="@string/mo_duration_days_1"/>
<item android:id="@+id/duration_days_3" android:title="@string/mo_duration_days_3"/>
<item android:id="@+id/duration_days_7" android:title="@string/mo_duration_days_7"/>
</menu>

View File

@@ -27,4 +27,17 @@
<string name="mo_filtered">Gefiltert: %s</string>
<string name="mo_disable_reminder_to_add_alt_text">Erinnerung zum Hinzufügen einer Bildbeschreibung deaktivieren</string>
<string name="mo_add_custom_server_local_timeline">Füge eine lokale Timeline eines benutzerdefinierten Servers hinzu</string>
<string name="mo_notification_action_replied">Erfolgreich auf den Beitrag von %s geantwortet</string>
<string name="mo_duration_hours_1">1 Stunde</string>
<string name="mo_duration_hours_6">6 Stunden</string>
<string name="mo_duration_days_1">1 Tag</string>
<string name="mo_duration_days_3">3 Tage</string>
<string name="mo_mute_label">Dauer:</string>
<string name="mo_duration_indefinite">Unbestimmt</string>
<string name="mo_duration_minutes_5">5 Minuten</string>
<string name="mo_duration_minutes_30">30 Minuten</string>
<string name="mo_change_default_reply_visibility_to_unlisted">Standard Antwortsichtbarkeit auf nicht aufgelistet ändern</string>
<string name="mo_duration_days_7">7 Tage</string>
<string name="mo_composer_behavior">Verhalten des Verfassers</string>
<string name="mo_miscellaneous_settings">Sonstige Einstellungen</string>
</resources>

View File

@@ -22,4 +22,5 @@
<string name="mo_filtered">Filtrado: %s</string>
<string name="mo_disable_reminder_to_add_alt_text">Desactivar recordatorio para añadir descripción</string>
<string name="mo_add_custom_server_local_timeline">Añadir una cronología de un servidor</string>
<string name="mo_notification_action_replied">Respondió correctamente a la publicación de %s</string>
</resources>

View File

@@ -259,4 +259,7 @@
<string name="sk_settings_collapse_long_posts">아주 긴 게시물 접기</string>
<string name="sk_spectator_mode">관객 모드</string>
<string name="sk_settings_hide_interaction">상호작용 버튼 가리기</string>
<string name="sk_follow_as">다른 계정으로 팔로우</string>
<string name="sk_followed_as">%s 계정으로 팔로우함</string>
<string name="sk_settings_hide_fab">게시 버튼 자동으로 가리기</string>
</resources>

View File

@@ -22,4 +22,17 @@
<string name="mo_filtered">Filtrado: %s</string>
<string name="mo_disable_reminder_to_add_alt_text">Desabilitar lembrete de adicionar textos descritivos</string>
<string name="mo_add_custom_server_local_timeline">Adicionar a linha local de um servidor customizado</string>
<string name="mo_notification_action_replied">Respondeu com sucesso ao post de %s</string>
<string name="mo_composer_behavior">Comportamento do Compositor</string>
<string name="mo_duration_hours_1">1 hora</string>
<string name="mo_duration_hours_6">6 horas</string>
<string name="mo_duration_days_1">1 dia</string>
<string name="mo_duration_days_3">3 dias</string>
<string name="mo_duration_days_7">7 dias</string>
<string name="mo_mute_label">Duração:</string>
<string name="mo_duration_indefinite">Indefinido</string>
<string name="mo_duration_minutes_5">5 minutos</string>
<string name="mo_duration_minutes_30">30 minutos</string>
<string name="mo_change_default_reply_visibility_to_unlisted">Mudar visibilidade padrão das respostas para não listado</string>
<string name="mo_miscellaneous_settings">Configurações Diversas</string>
</resources>

View File

@@ -22,4 +22,17 @@
<string name="mo_filtered">已过滤:%s</string>
<string name="mo_disable_reminder_to_add_alt_text">禁用添加ALT文本的提醒</string>
<string name="mo_add_custom_server_local_timeline">添加自定义实例的本地时间线</string>
<string name="mo_notification_action_replied">成功回复了 %s 的帖文</string>
<string name="mo_duration_minutes_5">5分钟</string>
<string name="mo_duration_hours_6">6小时</string>
<string name="mo_duration_days_1">1天</string>
<string name="mo_duration_days_3">3天</string>
<string name="mo_mute_label">持续时间:</string>
<string name="mo_duration_indefinite">无限</string>
<string name="mo_duration_minutes_30">30分钟</string>
<string name="mo_duration_hours_1">1小时</string>
<string name="mo_change_default_reply_visibility_to_unlisted">将回复的默认可见性改为“不公开列出”</string>
<string name="mo_duration_days_7">7天</string>
<string name="mo_composer_behavior">作者的行为</string>
<string name="mo_miscellaneous_settings">杂项设置</string>
</resources>

View File

@@ -26,10 +26,26 @@
<string name="mo_disable_relocate_publish_button_to_enable_customization">Disable "Relocate publish button" to allow customization</string>
<string name="mo_disable_reminder_to_add_alt_text">Disable reminder to add alt text</string>
<string name="mo_add_custom_server_local_timeline">Add a custom server\'s local timeline</string>
<string name="mo_notification_action_replied">Successfully replied to the post by %s</string>
<string name="mo_change_default_reply_visibility_to_unlisted">Change default reply visibility to unlisted</string>
<string name="mo_composer_behavior">Composer\'s Behavior</string>
<string name="mo_miscellaneous_settings">Miscellaneous Settings</string>
<!-- accessibility labels-->
<string name="mo_poll_option_add">Add new poll option</string>
<string name="mo_fab_compose">Compose</string>
<string name="mo_sending_error">Error publishing</string>
<!-- duration labels-->
<string name="mo_mute_label">Duration:</string>
<string name="mo_duration_indefinite">Indefinite</string>
<string name="mo_duration_minutes_5">5 minutes</string>
<string name="mo_duration_minutes_30">30 minutes</string>
<string name="mo_duration_hours_1">1 hour</string>
<string name="mo_duration_hours_6">6 hours</string>
<string name="mo_duration_days_1">1 day</string>
<string name="mo_duration_days_3">3 days</string>
<string name="mo_duration_days_7">7 days</string>
</resources>

View File

@@ -0,0 +1,3 @@
Version 97 fügt hinzu:
- Die neue Funktion "Benutzerdefinierte lokale Zeitleisten". Sie kann über das Menü "Zeitleisten hinzufügen" aufgerufen werden.
- Kleinere Korrekturen und Verbesserungen

View File

@@ -0,0 +1 @@
Erste Veröffentlichung im Play Store

View File

@@ -0,0 +1,6 @@
New things for release 99:
- Add notification actions
- Add option to enable unlisted replies by default
- Add mute timer
- Add notification badge if there are unread notifications
- Minor bugfixes and usability improvements

View File

@@ -0,0 +1,6 @@
- Añadir selector de idioma
- Añadir función de traducción
- Mejorar la semántica para votar en las encuestas (botones de radio y casillas de verificación)
- Añadir la opción de permitir la votación de múltiples opciones en las encuestas
- Nueva pantalla de inicio de sesión
- Corrección de errores

View File

@@ -0,0 +1,5 @@
- Nuevos esquemas de color: Material You y Rojo
- Nuevos tonos gris oscuro para todos los esquemas
- Icono de impulso ahora más distinguible
- Animaciones para botones de interacción.
- Corrección de errores (bloqueo en algunas publicaciones, "listas de", idioma predeterminado para nuevas publicaciones)

View File

@@ -0,0 +1,11 @@
- Botón de publicación personalizable
- Abrir enlaces de Fediverse en la aplicación
- Botón boost de pulsación larga para "citar" un post
- Copiar la URL de la publicación al pulsar prolongadamente el botón de compartir
- Implementar la eliminación de notificaciones (desactivada por defecto)
- Iconos específicos para los distintos tipos de notificaciones
- Nuevos colores grises
- Añadir la opción de desactivar el deslizamiento entre pestañas.
- Añadir varios enlaces a la configuración de la cuenta
- Mostrar/ocultar el botón de traducción en la línea de tiempo
- Corrección de errores y ajustes

View File

@@ -0,0 +1,6 @@
- Opción para seleccionar la visibilidad manteniendo presionado el botón de reblog
- Ahora se muestra la visibilidad de los reblogs propios.
- Lista agregada de hashtags seguidos
- Mantenga presionado a la izquierda para copiarlos
- Opción de abrir publicaciones con otra cuenta
- Corrección de errores y ajustes menores

View File

@@ -0,0 +1,4 @@
- 팔로우 버튼을 길게 눌러 다른 계정으로 프로필 팔로우
- 다른 계정으로 프로필을 열 수 있는 옵션
- 타임라인을 아래로 스크롤할 때 게시 버튼 자동으로 가리기
- 서버 관리자 프로필로 앱을 열 때 발생하는 오류 수정

View File

@@ -0,0 +1,16 @@
Moshidon é uma versão modificada do aplicativo Mastodon oficial para Android adicionando recursos importantes que estão faltando no aplicativo oficial, como o federado linha do tempo, postagem não listada e um visualizador de descrição de imagem.
<b>Principais recursos<b>
- <b>Muitas cores<b>: Traz material do seu tema e muitas opções coloridas de temas!
- <b>Postagens filtradas!<b>: A capacidade de exibir postagens filtradas com um aviso!
- <b>Botão Traduzir<b>: Traz um botão traduzir!
- <b>Seletor de idioma do toot<b>: Traz um seletor de idioma do toot!
- <b>Postagem não listada<b>: Poste publicamente sem que sua postagem apareça em tendências, hashtags ou cronogramas públicos.
- <b>Linha do tempo federada<b>: Veja todas as postagens públicas de pessoas em todos os outros bairros do Fediverse aos quais sua instância inicial está conectada.
- <b>Visualizador de descrição de imagem<b>: Verifique rapidamente se uma imagem ou vídeo tem um texto alternativo anexado a ele.
- <b>Pinagem de postagens<b>: Fixe suas postagens mais importantes em seu perfil e veja o que outras pessoas fixaram usando a guia "Fixadas".
- <b>Seguir hashtags<b>: veja novas postagens de hashtags específicas diretamente em sua linha do tempo inicial, seguindo-as.
- <b>Responder a solicitações de acompanhamento<b>: Aceite ou recuse solicitações de acompanhamento de suas notificações ou da lista dedicada de solicitações de acompanhamento.
- <b>Excluir e rediscutir<b>: O recurso muito apreciado que tornou a edição possível sem uma função de edição real.
- <b>Extras<b>: Traz muitos recursos extras de UI, como ícones de interação nas Notificações e remove muitos incômodos com a UI original!<b>

View File

@@ -0,0 +1 @@
Mastodon para Android mas é Material You e tem mais recursos

1
metadata/pt-BR/title.txt Normal file
View File

@@ -0,0 +1 @@
Moshidon

View File

@@ -0,0 +1,6 @@
新增语言选择器
- 新增翻译功能
- 改进投票贴文语义 (单选/多选)
- 新增允许在投票中设置多选的功能
- 新登录界面
- 修复部分bug

View File

@@ -0,0 +1,5 @@
- 新增颜色主题Material You和红色主题
- 为全部主题新增深灰色调
- 转发图标改为更醒目的填充式图标
- 为互动按钮添加了动画
- 修复部分bug发布部分贴文时崩溃“特定列表”贴文默认语言

View File

@@ -0,0 +1,11 @@
- 可自定义发布按钮
- 在应用中打开Fedivese链接
- 长按转发按钮可引用一篇帖子
- 长按分享按钮可复制贴文URL
- 实现了删除通知功能(默认禁用)
- 为不同类型通知提供了专门的图标
- 新增灰色色调
- 添加禁用滑动切换选项卡的设置
- 添加各种链接到账户设置
- 添加在时间轴上显示/隐藏翻译按钮的开关
- 修复bug与程序微调

View File

@@ -0,0 +1,6 @@
- 长按可选选择特定转发的可见性
- 显示自己转发的可见性
- 添加已关注的标签列表
- 长按复制链接
- 添加使用其它账户打开帖子的选项
- 修复bug与程序微调

View File

@@ -0,0 +1,10 @@
- 草稿和定时发布功能
- 回复时显示原帖
- 与Mastodon 4.0兼容的过滤器(目前还没有“隐藏并警告功能”)
- 长按可通过其它已登录账户与贴文交互
- 在所有菜单中添加图标
- 新增转发举报的开关
- 添加使用“发布关于此事的贴文”功能时的提及(@)功能
- 添加使用统一通知图标而非不同图标的设置项
- 添加从设置中访问应用内规则列表的选项
- 修复bug

View File

@@ -0,0 +1,10 @@
- 新的主页选项卡,包含公共时间轴
- 显示服务器公告
- 根据系统设置进行文本缩放
- 改进了过滤功能(目前还没有“带警告标识并隐藏”功能)(由@thiagojedi实现
- 列表管理功能
- 使用“软拉黑”移除关注你的用户
- 不允许与法西斯主义者建立联系
- 在连接到Akkoma实例时修复图像加载问题
- 修复bug和UI调整
- 更新日志刷新器(由@LucasGGamerM实现

View File

@@ -0,0 +1,9 @@
- 时间轴可以被固定和重新排列
- 支持仅在本地服务器发布
- 新增缺失alt文本的提示
- 改进alt文本编辑器
- 新增标题:时间轴中关注的标签
- 更多通知分类
- 重新添加文件打开器
- 在保存已编辑的草稿时提示
- 新增禁用“查看新帖子”按钮的选项

View File

@@ -0,0 +1,6 @@
- 改进过滤器,包括兼容“警告并隐藏”
- 重新设计个人资料页面,元信息直接显示在自我介绍下方
- 针对非常长的帖子的折叠/展开功能
- 自动为回复加上“re:”前缀的选项
- 新增在时间轴中隐藏互动按钮的选项
- 各种错误修复、调整和改进

View File

@@ -0,0 +1,4 @@
- 长按关注按钮可从其他帐户关注个人资料
- 新增从其他帐户打开个人资料的选项
- 向下滚动时间轴时自动隐藏发帖按钮
- 修复打开服务器管理员资料时崩溃的问题

View File

@@ -0,0 +1,5 @@
版本91的新功能
- 新增为带过滤标签的帖子显示警告的功能
- 修复了自动更新程序的问题
- 修复了一些与过滤系统相关的崩溃问题
- 进行了小规模的优化,提高用户体验

View File

@@ -0,0 +1,4 @@
版本92的更新内容
- 更好的过滤器
- 新的个人资料页面布局
- 大量微小的调整和改进

View File

@@ -0,0 +1,5 @@
版本94的更新内容
- 改进浮动操作按钮的行为
- 对启动器图标进行了微小的更改
- 改进通知行为
- 其它小修复与改进

View File

@@ -0,0 +1,3 @@
版本95的更新内容
- 增加在时间轴中添加其他服务器的本地时间轴的功能
- 一些小修复和改进

View File

@@ -0,0 +1,3 @@
版本96的更新内容
- 改进在时间轴中添加其他服务器的本地时间轴的功能
- 一些小修复和改进

View File

@@ -0,0 +1,3 @@
版本97的更新内容
- 新增自定义本地时间轴功能。可以在添加时间轴菜单中访问。
- 一些小修复和改进

View File

@@ -0,0 +1 @@
首个Play Store发布版本

View File

@@ -3,6 +3,7 @@ Moshidon 是<a href="https://github.com/mastodon/mastodon-android">官方 Mastod
<b>主要特点</b>
- <b>许多颜色</b>:为您提供 material you 主题和许多丰富多彩的主题选项!
- <b>过滤贴文</b>:可为带过滤内容标记的贴文显示敏感内容警告!
- <b>翻译按钮</b>:带来翻译按钮!
- <b>嘟文语言选择器</b>:引入了嘟文语言选择器!
- <b>不公开发帖</b>:公开发布而不让您的嘟文出现在趋势、主题标签或公共时间轴中。