Compare commits
69 Commits
1.2.0+fork
...
1.2.0+fork
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d95b395cfc | ||
|
|
b41b2c8f3c | ||
|
|
289dc4bf86 | ||
|
|
c34e1e5f32 | ||
|
|
729680df8c | ||
|
|
b85b578ddd | ||
|
|
8a7d2df7b8 | ||
|
|
3ff3eb819a | ||
|
|
1ea24b5ff6 | ||
|
|
79d0ab311b | ||
|
|
79f7df089e | ||
|
|
32464f8552 | ||
|
|
7ce96a2311 | ||
|
|
a009ea212f | ||
|
|
8848b75325 | ||
|
|
2eb04a3835 | ||
|
|
b61ce8399e | ||
|
|
52392c9ed9 | ||
|
|
4b35ac6ad8 | ||
|
|
a56b603c5c | ||
|
|
48bd277769 | ||
|
|
04101eb31b | ||
|
|
34c6a76a53 | ||
|
|
3f20c6104a | ||
|
|
b5f82261b0 | ||
|
|
b9a5db7ea4 | ||
|
|
64cb6e52a8 | ||
|
|
6e96e8929f | ||
|
|
bdd48f0001 | ||
|
|
4bf19adc8e | ||
|
|
bb9ff3c33f | ||
|
|
ae11e78d78 | ||
|
|
222c3a2526 | ||
|
|
08aa64a666 | ||
|
|
f10c157598 | ||
|
|
5059d8fc4f | ||
|
|
4152179dea | ||
|
|
3619be71ab | ||
|
|
810e9eeb11 | ||
|
|
25cff94665 | ||
|
|
0e08209f4c | ||
|
|
db0b4fb615 | ||
|
|
672cfe58d6 | ||
|
|
338e164143 | ||
|
|
e964b76302 | ||
|
|
8dedc77ff8 | ||
|
|
3b762c14a1 | ||
|
|
59941fc867 | ||
|
|
50601853f5 | ||
|
|
3137f3c1e4 | ||
|
|
bfaa732544 | ||
|
|
1b7a257a48 | ||
|
|
4d40fad10d | ||
|
|
49015f3e3e | ||
|
|
77b5819c65 | ||
|
|
ac5615497b | ||
|
|
4ecd525f13 | ||
|
|
b38a460a02 | ||
|
|
bddf024ba0 | ||
|
|
be7a7acadd | ||
|
|
d05c90ca7f | ||
|
|
4187da9168 | ||
|
|
a051e636e6 | ||
|
|
360cd7b5df | ||
|
|
55d2ca4a93 | ||
|
|
c7f61291ed | ||
|
|
f404895b5c | ||
|
|
94ed0c3f49 | ||
|
|
00ffe9c41e |
19
README.md
19
README.md
@@ -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 won’t ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
|
||||
|
||||
|
||||
[](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
|
||||
[](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk)
|
||||
|
||||
[](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>
|
||||
|
||||
<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
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.joinmastodon.android.model;
|
||||
|
||||
public enum NotificationAction {
|
||||
FAVORITE,
|
||||
BOOST,
|
||||
UNBOOST,
|
||||
BOOKMARK,
|
||||
REPLY,
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="?colorPollVoted"/>
|
||||
<corners android:radius="4dp"/>
|
||||
<corners android:radius="8dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -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>
|
||||
42
mastodon/src/main/res/layout/item_mute_duration.xml
Normal file
42
mastodon/src/main/res/layout/item_mute_duration.xml
Normal 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>
|
||||
11
mastodon/src/main/res/menu/mute_duration.xml
Normal file
11
mastodon/src/main/res/menu/mute_duration.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
3
metadata/de-DE/changelogs/97.txt
Normal file
3
metadata/de-DE/changelogs/97.txt
Normal 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
|
||||
1
metadata/de-DE/changelogs/98.txt
Normal file
1
metadata/de-DE/changelogs/98.txt
Normal file
@@ -0,0 +1 @@
|
||||
Erste Veröffentlichung im Play Store
|
||||
6
metadata/en-US/changelogs/99.txt
Normal file
6
metadata/en-US/changelogs/99.txt
Normal 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
|
||||
6
metadata/es-ES/changelogs/59.txt
Normal file
6
metadata/es-ES/changelogs/59.txt
Normal 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
|
||||
5
metadata/es-ES/changelogs/61.txt
Normal file
5
metadata/es-ES/changelogs/61.txt
Normal 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)
|
||||
11
metadata/es-ES/changelogs/62.txt
Normal file
11
metadata/es-ES/changelogs/62.txt
Normal 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
|
||||
6
metadata/es-ES/changelogs/63.txt
Normal file
6
metadata/es-ES/changelogs/63.txt
Normal 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
|
||||
4
metadata/ko/changelogs/77.txt
Normal file
4
metadata/ko/changelogs/77.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
- 팔로우 버튼을 길게 눌러 다른 계정으로 프로필 팔로우
|
||||
- 다른 계정으로 프로필을 열 수 있는 옵션
|
||||
- 타임라인을 아래로 스크롤할 때 게시 버튼 자동으로 가리기
|
||||
- 서버 관리자 프로필로 앱을 열 때 발생하는 오류 수정
|
||||
16
metadata/pt-BR/full_description.txt
Normal file
16
metadata/pt-BR/full_description.txt
Normal 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>
|
||||
1
metadata/pt-BR/short_description.txt
Normal file
1
metadata/pt-BR/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
Mastodon para Android mas é Material You e tem mais recursos
|
||||
1
metadata/pt-BR/title.txt
Normal file
1
metadata/pt-BR/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
Moshidon
|
||||
6
metadata/zh-CN/changelogs/59.txt
Normal file
6
metadata/zh-CN/changelogs/59.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
‐ 新增语言选择器
|
||||
- 新增翻译功能
|
||||
- 改进投票贴文语义 (单选/多选)
|
||||
- 新增允许在投票中设置多选的功能
|
||||
- 新登录界面
|
||||
- 修复部分bug
|
||||
5
metadata/zh-CN/changelogs/61.txt
Normal file
5
metadata/zh-CN/changelogs/61.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
- 新增颜色主题:Material You和红色主题
|
||||
- 为全部主题新增深灰色调
|
||||
- 转发图标改为更醒目的填充式图标
|
||||
- 为互动按钮添加了动画
|
||||
- 修复部分bug(发布部分贴文时崩溃,“特定列表”,贴文默认语言)
|
||||
11
metadata/zh-CN/changelogs/62.txt
Normal file
11
metadata/zh-CN/changelogs/62.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
- 可自定义发布按钮
|
||||
- 在应用中打开Fedivese链接
|
||||
- 长按转发按钮可引用一篇帖子
|
||||
- 长按分享按钮可复制贴文URL
|
||||
- 实现了删除通知功能(默认禁用)
|
||||
- 为不同类型通知提供了专门的图标
|
||||
- 新增灰色色调
|
||||
- 添加禁用滑动切换选项卡的设置
|
||||
- 添加各种链接到账户设置
|
||||
- 添加在时间轴上显示/隐藏翻译按钮的开关
|
||||
- 修复bug与程序微调
|
||||
6
metadata/zh-CN/changelogs/63.txt
Normal file
6
metadata/zh-CN/changelogs/63.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
- 长按可选选择特定转发的可见性
|
||||
- 显示自己转发的可见性
|
||||
- 添加已关注的标签列表
|
||||
- 长按复制链接
|
||||
- 添加使用其它账户打开帖子的选项
|
||||
- 修复bug与程序微调
|
||||
10
metadata/zh-CN/changelogs/65.txt
Normal file
10
metadata/zh-CN/changelogs/65.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
- 草稿和定时发布功能
|
||||
- 回复时显示原帖
|
||||
- 与Mastodon 4.0兼容的过滤器(目前还没有“隐藏并警告功能”)
|
||||
- 长按可通过其它已登录账户与贴文交互
|
||||
- 在所有菜单中添加图标
|
||||
- 新增转发举报的开关
|
||||
- 添加使用“发布关于此事的贴文”功能时的提及(@)功能
|
||||
- 添加使用统一通知图标而非不同图标的设置项
|
||||
- 添加从设置中访问应用内规则列表的选项
|
||||
- 修复bug
|
||||
10
metadata/zh-CN/changelogs/67.txt
Normal file
10
metadata/zh-CN/changelogs/67.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
- 新的主页选项卡,包含公共时间轴
|
||||
- 显示服务器公告
|
||||
- 根据系统设置进行文本缩放
|
||||
- 改进了过滤功能(目前还没有“带警告标识并隐藏”功能)(由@thiagojedi实现)
|
||||
- 列表管理功能
|
||||
- 使用“软拉黑”移除关注你的用户
|
||||
- 不允许与法西斯主义者建立联系
|
||||
- 在连接到Akkoma实例时修复图像加载问题
|
||||
- 修复bug和UI调整
|
||||
- 更新日志刷新器(由@LucasGGamerM实现)
|
||||
9
metadata/zh-CN/changelogs/74.txt
Normal file
9
metadata/zh-CN/changelogs/74.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
- 时间轴可以被固定和重新排列
|
||||
- 支持仅在本地服务器发布
|
||||
- 新增缺失alt文本的提示
|
||||
- 改进alt文本编辑器
|
||||
- 新增标题:时间轴中关注的标签
|
||||
- 更多通知分类
|
||||
- 重新添加文件打开器
|
||||
- 在保存已编辑的草稿时提示
|
||||
- 新增禁用“查看新帖子”按钮的选项
|
||||
6
metadata/zh-CN/changelogs/76.txt
Normal file
6
metadata/zh-CN/changelogs/76.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
- 改进过滤器,包括兼容“警告并隐藏”
|
||||
- 重新设计个人资料页面,元信息直接显示在自我介绍下方
|
||||
- 针对非常长的帖子的折叠/展开功能
|
||||
- 自动为回复加上“re:”前缀的选项
|
||||
- 新增在时间轴中隐藏互动按钮的选项
|
||||
- 各种错误修复、调整和改进
|
||||
4
metadata/zh-CN/changelogs/77.txt
Normal file
4
metadata/zh-CN/changelogs/77.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
- 长按关注按钮可从其他帐户关注个人资料
|
||||
- 新增从其他帐户打开个人资料的选项
|
||||
- 向下滚动时间轴时自动隐藏发帖按钮
|
||||
- 修复打开服务器管理员资料时崩溃的问题
|
||||
5
metadata/zh-CN/changelogs/91.txt
Normal file
5
metadata/zh-CN/changelogs/91.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
版本91的新功能:
|
||||
- 新增为带过滤标签的帖子显示警告的功能
|
||||
- 修复了自动更新程序的问题
|
||||
- 修复了一些与过滤系统相关的崩溃问题
|
||||
- 进行了小规模的优化,提高用户体验
|
||||
4
metadata/zh-CN/changelogs/92.txt
Normal file
4
metadata/zh-CN/changelogs/92.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
版本92的更新内容:
|
||||
- 更好的过滤器
|
||||
- 新的个人资料页面布局
|
||||
- 大量微小的调整和改进
|
||||
5
metadata/zh-CN/changelogs/94.txt
Normal file
5
metadata/zh-CN/changelogs/94.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
版本94的更新内容:
|
||||
- 改进浮动操作按钮的行为
|
||||
- 对启动器图标进行了微小的更改
|
||||
- 改进通知行为
|
||||
- 其它小修复与改进
|
||||
3
metadata/zh-CN/changelogs/95.txt
Normal file
3
metadata/zh-CN/changelogs/95.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
版本95的更新内容:
|
||||
- 增加在时间轴中添加其他服务器的本地时间轴的功能
|
||||
- 一些小修复和改进
|
||||
3
metadata/zh-CN/changelogs/96.txt
Normal file
3
metadata/zh-CN/changelogs/96.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
版本96的更新内容:
|
||||
- 改进在时间轴中添加其他服务器的本地时间轴的功能
|
||||
- 一些小修复和改进
|
||||
3
metadata/zh-CN/changelogs/97.txt
Normal file
3
metadata/zh-CN/changelogs/97.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
版本97的更新内容:
|
||||
- 新增自定义本地时间轴功能。可以在添加时间轴菜单中访问。
|
||||
- 一些小修复和改进
|
||||
1
metadata/zh-CN/changelogs/98.txt
Normal file
1
metadata/zh-CN/changelogs/98.txt
Normal file
@@ -0,0 +1 @@
|
||||
首个Play Store发布版本
|
||||
@@ -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>:公开发布而不让您的嘟文出现在趋势、主题标签或公共时间轴中。
|
||||
|
||||
Reference in New Issue
Block a user