Compare commits
47 Commits
v1.1.4+for
...
v1.1.4+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58abdad62a | ||
|
|
c693414cc3 | ||
|
|
ee158e1aba | ||
|
|
40d478aaec | ||
|
|
e7fb96b3ff | ||
|
|
ef75427b45 | ||
|
|
2ff4f00774 | ||
|
|
534fd8c119 | ||
|
|
2d2cd89454 | ||
|
|
9f3f5ca7c1 | ||
|
|
c0e6f17c83 | ||
|
|
677f1cb42d | ||
|
|
1ac6a04a46 | ||
|
|
21927d2e25 | ||
|
|
c35441f5f7 | ||
|
|
3718fe6601 | ||
|
|
095f234bd5 | ||
|
|
f10c0e06db | ||
|
|
ebbd5d1fa3 | ||
|
|
c8abf26040 | ||
|
|
bc733af147 | ||
|
|
77a2fd2a60 | ||
|
|
5cfc5eb08a | ||
|
|
b832d2df26 | ||
|
|
db34dc40ba | ||
|
|
bfa48c2d3e | ||
|
|
b5e229a84d | ||
|
|
ef207f885b | ||
|
|
c4eee28335 | ||
|
|
6fe466779e | ||
|
|
e71db1b883 | ||
|
|
b6efafe99d | ||
|
|
688d466f8e | ||
|
|
3c5797932e | ||
|
|
48a5e262ce | ||
|
|
63b0365208 | ||
|
|
972c05d60b | ||
|
|
acb5778e0b | ||
|
|
7694c50358 | ||
|
|
7ffa368d10 | ||
|
|
53f8f41d88 | ||
|
|
93d57d847e | ||
|
|
83a4f5eec2 | ||
|
|
836c2dba8d | ||
|
|
13ae8d2ebe | ||
|
|
98dafb4e49 | ||
|
|
85b8bae42e |
43
README.md
43
README.md
@@ -1,34 +1,47 @@
|
||||

|
||||
|
||||
# Mastodon for Android Fork
|
||||
# Mastodos
|
||||
|
||||
> A fork of the [official Mastodon Android app](https://github.com/mastodon/mastodon-android) adding important features that are missing in the official app and possibly won’t ever be implemented, such as the federated timeline, unlisted posting, bookmarks and an image description viewer.
|
||||
|
||||
[](https://github.com/sk22/mastodon-android-fork/releases/latest/download/mastodos.apk)
|
||||
|
||||
## Changes
|
||||
|
||||
* [Enable "Unlisted" as a visibility option](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted)
|
||||
([Pull request](https://github.com/mastodon/mastodon-android/pull/103)) and
|
||||
[set as default](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted-as-default)
|
||||
* [Add "Federation" tab and change Discover tab order](https://github.com/sk22/mastodon-android-fork/tree/feature/add-federated-timeline) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/8))
|
||||
### Features
|
||||
|
||||
* [Add “Unlisted” as a post visibility option](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted)
|
||||
([Pull request](https://github.com/mastodon/mastodon-android/pull/103))
|
||||
* [Add “Federation” tab and change Discover tab order](https://github.com/sk22/mastodon-android-fork/tree/feature/add-federated-timeline) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/8))
|
||||
* [Add image description button and viewer](https://github.com/sk22/mastodon-android-fork/tree/feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
|
||||
* [Implement pinning posts and displaying pinned posts](https://github.com/sk22/mastodon-android-fork/tree/feature/pin-posts) ([Pull request](https://github.com/mastodon/mastodon-android/pull/140))
|
||||
* [Display full image when adding image description](https://github.com/sk22/mastodon-android-fork/tree/feature/compose-image-description-full-image) ([Pull request](https://github.com/mastodon/mastodon-android/pull/182))
|
||||
* [Always preserve content warnings when replying](https://github.com/sk22/mastodon-android-fork/tree/feature/always-preserve-cw) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/113))
|
||||
* [Make back button return to the home tab before exiting the app](https://github.com/sk22/mastodon-android-fork/tree/feature/back-returns-home) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/118))
|
||||
* [Implement a bookmark button and list](https://github.com/sk22/mastodon-android-fork/tree/feature/bookmarks) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/22))
|
||||
* [Add “Mark media as sensitive” option](https://github.com/sk22/mastodon-android-fork/tree/feature/mark-media-as-sensitive)
|
||||
* [Add “Check for update” button in addition to integrated update checker](https://github.com/sk22/mastodon-android-fork/commits/feature/check-for-update-button)
|
||||
|
||||
### Behavior
|
||||
|
||||
* [Make back button return to the home tab before exiting the app](https://github.com/sk22/mastodon-android-fork/tree/feature/back-returns-home) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/118))
|
||||
* [Always preserve content warnings when replying](https://github.com/sk22/mastodon-android-fork/tree/feature/always-preserve-cw) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/113))
|
||||
* [Display full image when adding image description](https://github.com/sk22/mastodon-android-fork/tree/feature/compose-image-description-full-image) ([Pull request](https://github.com/mastodon/mastodon-android/pull/182))
|
||||
* [Implement deleting and re-drafting](https://github.com/sk22/mastodon-android-fork/tree/feature/delete-redraft) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/21))
|
||||
* [Set spoiler height independently to content height](https://github.com/sk22/mastodon-android-fork/commits/spoiler-height-independent) ([Fixes issue](https://github.com/mastodon/mastodon-android/issues/166))
|
||||
|
||||
## Fork-specific changes
|
||||
### Installation
|
||||
|
||||
* Custom app name
|
||||
To install this app on your Android device, download the [latest release from GitHub](https://github.com/sk22/mastodon-android-fork/releases/latest/download/mastodos.apk) and open it. You might have to accept installing APK files from your browser when trying to install it. You can also take a look at all releases on the [Releases](https://github.com/sk22/mastodon-android-fork/releases) page.
|
||||
|
||||
Mastodos makes use of [Mastodon for Android](https://github.com/mastodon/mastodon-android)’s automatic update checker. Mastodos will check for new updates available on GitHub and offer to download and install them. You can also manually press “Check for updates” at the bottom of the settings page!
|
||||
|
||||
### Branding
|
||||
|
||||
* App name “Mastodos”
|
||||
* Pink primary color
|
||||
* Custom icon: Modulate upstream icon using ImageMagick
|
||||
|
||||
```bash
|
||||
mogrify -modulate 90,100,140 mastodon/src/main/res/mipmap-*/ic_launcher*.png
|
||||
```
|
||||
|
||||
* Custom primary color: Hue of all `primary` colors in `colors.xml` is rotated, on basis of upstream Mastodon's [old branding](https://github.com/mastodon/mastodon-android/commit/74f03026cfcfcfd23237c38ff47d2b2a98a6f92a#diff-59134ec2a1cf3761f80b0ecccbbf8b9e433d9780d2f5c5d6ac3ac8cc254e808f)
|
||||
by `109.8°` (equivalent of `161%`, done by hand using
|
||||
[PineTools](https://pinetools.com/shift-hue-color))
|
||||
|
||||
## Building
|
||||
|
||||
As this app is using Java 17 features, you need JDK 17 or newer to build it. Other than that, everything is pretty standard. You can either import the project into Android Studio and build it from there, or run the following command in the project directory:
|
||||
|
||||
@@ -9,9 +9,13 @@ android {
|
||||
applicationId "org.joinmastodon.android.sk"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 25
|
||||
versionName "1.1.4+fork.25"
|
||||
versionCode 30
|
||||
versionName "1.1.4+fork.30"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
resConfigs "en", "ar-rSA", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES",
|
||||
"eu-rES", "fi-rFI", "fr-rFR", "gl-rES", "hr-rHR", "hy-rAM", "it-rIT", "iw-rIL",
|
||||
"ja-rJP", "kab", "ko-rKR", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ru-rRU",
|
||||
"sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
||||
@@ -26,6 +26,8 @@ import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -36,7 +38,7 @@ import okhttp3.Response;
|
||||
|
||||
@Keep
|
||||
public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
|
||||
private static final long CHECK_PERIOD=24*3600*1000L;
|
||||
private static final long CHECK_PERIOD=6*3600*1000L;
|
||||
private static final String TAG="GithubSelfUpdater";
|
||||
|
||||
private UpdateState state=UpdateState.NO_UPDATE;
|
||||
@@ -101,6 +103,12 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkForUpdates() {
|
||||
setState(UpdateState.CHECKING);
|
||||
MastodonAPIController.runInBackground(this::actuallyCheckForUpdates);
|
||||
}
|
||||
|
||||
private void actuallyCheckForUpdates(){
|
||||
Request req=new Request.Builder()
|
||||
.url("https://api.github.com/repos/sk22/mastodon-android-fork/releases/latest")
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/Theme.Mastodon.AutoLightDark"
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.joinmastodon.android.model.Status;
|
||||
|
||||
public class StatusCountersUpdatedEvent{
|
||||
public String id;
|
||||
public int favorites, reblogs, replies;
|
||||
public long favorites, reblogs, replies;
|
||||
public boolean favorited, reblogged, pinned;
|
||||
|
||||
public StatusCountersUpdatedEvent(Status s){
|
||||
|
||||
@@ -161,11 +161,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
|
||||
private Button publishButton;
|
||||
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
|
||||
private ImageView sensitiveIcon;
|
||||
private ComposeMediaLayout attachmentsView;
|
||||
private TextView replyText;
|
||||
private ReorderableLinearLayout pollOptionsView;
|
||||
private View pollWrap;
|
||||
private View addPollOptionBtn;
|
||||
private View sensitiveItem;
|
||||
private TextView pollDurationView;
|
||||
|
||||
private ArrayList<DraftPollOption> pollOptions=new ArrayList<>();
|
||||
@@ -181,11 +183,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private String pollDurationStr;
|
||||
private EditText spoilerEdit;
|
||||
private boolean hasSpoiler;
|
||||
private boolean sensitive;
|
||||
private ProgressBar sendProgress;
|
||||
private ImageView sendError;
|
||||
private View sendingOverlay;
|
||||
private WindowManager wm;
|
||||
private StatusPrivacy statusVisibility=StatusPrivacy.UNLISTED;
|
||||
private StatusPrivacy statusVisibility=StatusPrivacy.PUBLIC;
|
||||
private ComposeAutocompleteSpan currentAutocompleteSpan;
|
||||
private FrameLayout mainEditTextWrap;
|
||||
private ComposeAutocompleteViewController autocompleteViewController;
|
||||
@@ -290,6 +293,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
emojiBtn=view.findViewById(R.id.btn_emoji);
|
||||
spoilerBtn=view.findViewById(R.id.btn_spoiler);
|
||||
visibilityBtn=view.findViewById(R.id.btn_visibility);
|
||||
sensitiveIcon=view.findViewById(R.id.sensitive_icon);
|
||||
sensitiveItem=view.findViewById(R.id.sensitive_item);
|
||||
replyText=view.findViewById(R.id.reply_text);
|
||||
|
||||
mediaBtn.setOnClickListener(v->openFilePicker());
|
||||
@@ -297,6 +302,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
emojiBtn.setOnClickListener(v->emojiKeyboard.toggleKeyboardPopup(mainEditText));
|
||||
spoilerBtn.setOnClickListener(v->toggleSpoiler());
|
||||
visibilityBtn.setOnClickListener(this::onVisibilityClick);
|
||||
sensitiveItem.setOnClickListener(v->toggleSensitive());
|
||||
emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){
|
||||
@Override
|
||||
public void onIconChanged(int icon){
|
||||
@@ -362,11 +368,16 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
spoilerEdit.setVisibility(View.VISIBLE);
|
||||
spoilerBtn.setSelected(true);
|
||||
}else if(editingStatus!=null && !TextUtils.isEmpty(editingStatus.spoilerText)){
|
||||
hasSpoiler=true;
|
||||
spoilerEdit.setVisibility(View.VISIBLE);
|
||||
spoilerEdit.setText(getArguments().getString("sourceSpoiler", editingStatus.spoilerText));
|
||||
spoilerBtn.setSelected(true);
|
||||
}
|
||||
|
||||
sensitive = editingStatus != null ? editingStatus.sensitive
|
||||
: (savedInstanceState != null && savedInstanceState.getBoolean("sensitive", false));
|
||||
sensitiveIcon.setSelected(sensitive);
|
||||
|
||||
ArrayList<Parcelable> serializedAttachments=(savedInstanceState!=null ? savedInstanceState : getArguments())
|
||||
.getParcelableArrayList("attachments");
|
||||
if(serializedAttachments!=null){
|
||||
@@ -386,6 +397,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
if(editingStatus!=null && editingStatus.visibility!=null) {
|
||||
statusVisibility=editingStatus.visibility;
|
||||
}
|
||||
|
||||
updateVisibilityIcon();
|
||||
|
||||
autocompleteViewController=new ComposeAutocompleteViewController(getActivity(), accountID);
|
||||
@@ -420,6 +432,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
}
|
||||
outState.putSerializable("visibility", statusVisibility);
|
||||
}
|
||||
outState.putBoolean("sensitive", sensitive);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -567,8 +580,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
}
|
||||
}
|
||||
|
||||
updateSensitive();
|
||||
|
||||
if(editingStatus!=null){
|
||||
updateCharCounter();
|
||||
visibilityBtn.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,6 +692,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
CreateStatus.Request req=new CreateStatus.Request();
|
||||
req.status=text;
|
||||
req.visibility=statusVisibility;
|
||||
req.sensitive=sensitive;
|
||||
if(!attachments.isEmpty()){
|
||||
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
|
||||
}
|
||||
@@ -882,6 +899,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
uploadNextQueuedAttachment();
|
||||
}
|
||||
updatePublishButtonState();
|
||||
updateSensitive();
|
||||
if(getMediaAttachmentsCount()==MAX_ATTACHMENTS)
|
||||
mediaBtn.setEnabled(false);
|
||||
return true;
|
||||
@@ -1056,6 +1074,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
updatePublishButtonState();
|
||||
pollBtn.setEnabled(attachments.isEmpty());
|
||||
mediaBtn.setEnabled(true);
|
||||
updateSensitive();
|
||||
}
|
||||
|
||||
private void onRetryOrCancelMediaUploadClick(View v){
|
||||
@@ -1257,7 +1276,20 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
spoilerBtn.setSelected(false);
|
||||
mainEditText.requestFocus();
|
||||
updateCharCounter();
|
||||
sensitiveIcon.setVisibility(getMediaAttachmentsCount() > 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
updateSensitive();
|
||||
}
|
||||
|
||||
private void toggleSensitive() {
|
||||
sensitive=!sensitive;
|
||||
sensitiveIcon.setSelected(sensitive);
|
||||
}
|
||||
|
||||
private void updateSensitive() {
|
||||
sensitiveItem.setVisibility(View.GONE);
|
||||
if (!attachments.isEmpty() && !hasSpoiler) sensitiveItem.setVisibility(View.VISIBLE);
|
||||
if (attachments.isEmpty()) sensitive = false;
|
||||
}
|
||||
|
||||
private int getMediaAttachmentsCount(){
|
||||
|
||||
@@ -142,7 +142,6 @@ public class HomeTimelineFragment extends StatusListFragment{
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusCreated(StatusCreatedEvent ev){
|
||||
prependItems(Collections.singletonList(ev.status), true);
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
|
||||
private void bindHeaderView(){
|
||||
setTitle(account.displayName);
|
||||
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, account.statusesCount, account.statusesCount));
|
||||
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, (int)(account.statusesCount%1000), account.statusesCount));
|
||||
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(100), V.dp(100)));
|
||||
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000));
|
||||
SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName);
|
||||
@@ -451,9 +451,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
followersCount.setText(UiUtils.abbreviateNumber(account.followersCount));
|
||||
followingCount.setText(UiUtils.abbreviateNumber(account.followingCount));
|
||||
postsCount.setText(UiUtils.abbreviateNumber(account.statusesCount));
|
||||
followersLabel.setText(getResources().getQuantityString(R.plurals.followers, Math.min(999, account.followersCount)));
|
||||
followingLabel.setText(getResources().getQuantityString(R.plurals.following, Math.min(999, account.followingCount)));
|
||||
postsLabel.setText(getResources().getQuantityString(R.plurals.posts, Math.min(999, account.statusesCount)));
|
||||
followersLabel.setText(getResources().getQuantityString(R.plurals.followers, (int)Math.min(999, account.followersCount)));
|
||||
followingLabel.setText(getResources().getQuantityString(R.plurals.following, (int)Math.min(999, account.followingCount)));
|
||||
postsLabel.setText(getResources().getQuantityString(R.plurals.posts, (int)Math.min(999, account.statusesCount)));
|
||||
|
||||
UiUtils.loadCustomEmojiInTextView(name);
|
||||
UiUtils.loadCustomEmojiInTextView(bio);
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
@@ -71,6 +72,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
private PushSubscription pushSubscription;
|
||||
|
||||
private ImageView themeTransitionWindowView;
|
||||
private TextItem checkForUpdateItem;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
@@ -118,6 +120,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
items.add(new TextItem(R.string.settings_privacy_policy, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms")));
|
||||
|
||||
items.add(new RedHeaderItem(R.string.settings_spicy));
|
||||
if (GithubSelfUpdater.needSelfUpdating()) {
|
||||
checkForUpdateItem = new TextItem(R.string.check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates);
|
||||
items.add(checkForUpdateItem);
|
||||
}
|
||||
items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache));
|
||||
items.add(new TextItem(R.string.log_out, this::confirmLogOut));
|
||||
|
||||
@@ -326,11 +332,25 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
|
||||
@Subscribe
|
||||
public void onSelfUpdateStateChanged(SelfUpdateStateChangedEvent ev){
|
||||
if(items.get(0) instanceof UpdateItem item){
|
||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(0);
|
||||
if(holder instanceof UpdateViewHolder uvh){
|
||||
uvh.bind(item);
|
||||
}
|
||||
checkForUpdateItem.loading = ev.state == GithubSelfUpdater.UpdateState.CHECKING;
|
||||
if (list.findViewHolderForAdapterPosition(items.indexOf(checkForUpdateItem)) instanceof TextViewHolder tvh) tvh.rebind();
|
||||
|
||||
UpdateItem updateItem = null;
|
||||
if(items.get(0) instanceof UpdateItem item0) {
|
||||
updateItem = item0;
|
||||
} else if (ev.state != GithubSelfUpdater.UpdateState.CHECKING
|
||||
&& ev.state != GithubSelfUpdater.UpdateState.NO_UPDATE) {
|
||||
updateItem = new UpdateItem();
|
||||
items.add(0, updateItem);
|
||||
list.setAdapter(new SettingsAdapter());
|
||||
}
|
||||
|
||||
if(updateItem != null && list.findViewHolderForAdapterPosition(0) instanceof UpdateViewHolder uvh){
|
||||
uvh.bind(updateItem);
|
||||
}
|
||||
|
||||
if (ev.state == GithubSelfUpdater.UpdateState.NO_UPDATE) {
|
||||
Toast.makeText(getActivity(), R.string.no_update_available, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,10 +418,16 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
private class TextItem extends Item{
|
||||
private String text;
|
||||
private Runnable onClick;
|
||||
private boolean loading;
|
||||
|
||||
public TextItem(@StringRes int text, Runnable onClick){
|
||||
public TextItem(@StringRes int text, Runnable onClick) {
|
||||
this(text, onClick, false);
|
||||
}
|
||||
|
||||
public TextItem(@StringRes int text, Runnable onClick, boolean loading){
|
||||
this.text=getString(text);
|
||||
this.onClick=onClick;
|
||||
this.loading=loading;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -630,14 +656,18 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
|
||||
private class TextViewHolder extends BindableViewHolder<TextItem> implements UsableRecyclerView.Clickable{
|
||||
private final TextView text;
|
||||
private final ProgressBar progress;
|
||||
|
||||
public TextViewHolder(){
|
||||
super(getActivity(), R.layout.item_settings_text, list);
|
||||
text=(TextView) itemView;
|
||||
text = itemView.findViewById(R.id.text);
|
||||
progress = itemView.findViewById(R.id.progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(TextItem item){
|
||||
text.setText(item.text);
|
||||
progress.animate().alpha(item.loading ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -692,8 +722,9 @@ public class SettingsFragment extends MastodonToolbarFragment{
|
||||
@Override
|
||||
public void onBind(UpdateItem item){
|
||||
GithubSelfUpdater updater=GithubSelfUpdater.getInstance();
|
||||
GithubSelfUpdater.UpdateInfo info=updater.getUpdateInfo();
|
||||
GithubSelfUpdater.UpdateState state=updater.getState();
|
||||
if (state == GithubSelfUpdater.UpdateState.CHECKING) return;
|
||||
GithubSelfUpdater.UpdateInfo info=updater.getUpdateInfo();
|
||||
if(state!=GithubSelfUpdater.UpdateState.DOWNLOADED){
|
||||
text.setText(getString(R.string.update_available, info.version));
|
||||
button.setText(getString(R.string.download_update, UiUtils.formatFileSize(getActivity(), info.size, false)));
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||
import org.joinmastodon.android.events.StatusUpdatedEvent;
|
||||
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||
@@ -63,6 +62,59 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
|
||||
protected void onStatusCreated(StatusCreatedEvent ev){}
|
||||
|
||||
protected void onStatusUpdated(StatusUpdatedEvent ev){
|
||||
ArrayList<Status> statusesForDisplayItems=new ArrayList<>();
|
||||
for(int i=0;i<data.size();i++){
|
||||
Status s=data.get(i);
|
||||
if(s.reblog!=null && s.reblog.id.equals(ev.status.id)){
|
||||
s.reblog=ev.status;
|
||||
statusesForDisplayItems.add(s);
|
||||
}else if(s.id.equals(ev.status.id)){
|
||||
data.set(i, ev.status);
|
||||
statusesForDisplayItems.add(ev.status);
|
||||
}
|
||||
}
|
||||
for(int i=0;i<preloadedData.size();i++){
|
||||
Status s=preloadedData.get(i);
|
||||
if(s.reblog!=null && s.reblog.id.equals(ev.status.id)){
|
||||
s.reblog=ev.status;
|
||||
}else if(s.id.equals(ev.status.id)){
|
||||
preloadedData.set(i, ev.status);
|
||||
}
|
||||
}
|
||||
|
||||
if(statusesForDisplayItems.isEmpty())
|
||||
return;
|
||||
|
||||
for(Status s:statusesForDisplayItems){
|
||||
int i=0;
|
||||
for(StatusDisplayItem item:displayItems){
|
||||
if(item.parentID.equals(s.id)){
|
||||
int start=i;
|
||||
for(;i<displayItems.size();i++){
|
||||
if(!displayItems.get(i).parentID.equals(s.id))
|
||||
break;
|
||||
}
|
||||
List<StatusDisplayItem> postItems=displayItems.subList(start, i);
|
||||
postItems.clear();
|
||||
postItems.addAll(buildDisplayItems(s));
|
||||
int oldSize=i-start, newSize=postItems.size();
|
||||
if(oldSize==newSize){
|
||||
adapter.notifyItemRangeChanged(start, newSize);
|
||||
}else if(oldSize<newSize){
|
||||
adapter.notifyItemRangeChanged(start, oldSize);
|
||||
adapter.notifyItemRangeInserted(start+oldSize, newSize-oldSize);
|
||||
}else{
|
||||
adapter.notifyItemRangeChanged(start, newSize);
|
||||
adapter.notifyItemRangeRemoved(start+newSize, oldSize-newSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Status getContentStatusByID(String id){
|
||||
Status s=getStatusByID(id);
|
||||
return s==null ? null : s.getContentStatus();
|
||||
@@ -138,6 +190,11 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
StatusListFragment.this.onStatusCreated(ev);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusUpdated(StatusUpdatedEvent ev){
|
||||
StatusListFragment.this.onStatusUpdated(ev);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPollUpdated(PollUpdatedEvent ev){
|
||||
if(!ev.accountID.equals(accountID))
|
||||
|
||||
@@ -12,7 +12,7 @@ public class FollowerListFragment extends AccountRelatedAccountListFragment{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setSubtitle(getResources().getQuantityString(R.plurals.x_followers, account.followersCount, account.followersCount));
|
||||
setSubtitle(getResources().getQuantityString(R.plurals.x_followers, (int)(account.followersCount%1000), account.followersCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,7 +12,7 @@ public class FollowingListFragment extends AccountRelatedAccountListFragment{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setSubtitle(getResources().getQuantityString(R.plurals.x_following, account.followingCount, account.followingCount));
|
||||
setSubtitle(getResources().getQuantityString(R.plurals.x_following, (int)(account.followingCount%1000), account.followingCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,7 +11,7 @@ public class StatusFavoritesListFragment extends StatusRelatedAccountListFragmen
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(getResources().getQuantityString(R.plurals.x_favorites, status.favouritesCount, status.favouritesCount));
|
||||
setTitle(getResources().getQuantityString(R.plurals.x_favorites, (int)(status.favouritesCount%1000), status.favouritesCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,7 +11,7 @@ public class StatusReblogsListFragment extends StatusRelatedAccountListFragment{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(getResources().getQuantityString(R.plurals.x_reblogs, status.reblogsCount, status.reblogsCount));
|
||||
setTitle(getResources().getQuantityString(R.plurals.x_reblogs, (int)(status.reblogsCount%1000), status.reblogsCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -220,9 +220,9 @@ public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccou
|
||||
followersCount.setText(UiUtils.abbreviateNumber(item.account.followersCount));
|
||||
followingCount.setText(UiUtils.abbreviateNumber(item.account.followingCount));
|
||||
postsCount.setText(UiUtils.abbreviateNumber(item.account.statusesCount));
|
||||
followersLabel.setText(getResources().getQuantityString(R.plurals.followers, Math.min(999, item.account.followersCount)));
|
||||
followingLabel.setText(getResources().getQuantityString(R.plurals.following, Math.min(999, item.account.followingCount)));
|
||||
postsLabel.setText(getResources().getQuantityString(R.plurals.posts, Math.min(999, item.account.statusesCount)));
|
||||
followersLabel.setText(getResources().getQuantityString(R.plurals.followers, (int)Math.min(999, item.account.followersCount)));
|
||||
followingLabel.setText(getResources().getQuantityString(R.plurals.following, (int)Math.min(999, item.account.followingCount)));
|
||||
postsLabel.setText(getResources().getQuantityString(R.plurals.posts, (int)Math.min(999, item.account.statusesCount)));
|
||||
relationship=relationships.get(item.account.id);
|
||||
if(relationship==null){
|
||||
actionWrap.setVisibility(View.GONE);
|
||||
|
||||
@@ -96,15 +96,15 @@ public class Account extends BaseModel{
|
||||
/**
|
||||
* How many statuses are attached to this account.
|
||||
*/
|
||||
public int statusesCount;
|
||||
public long statusesCount;
|
||||
/**
|
||||
* The reported followers of this profile.
|
||||
*/
|
||||
public int followersCount;
|
||||
public long followersCount;
|
||||
/**
|
||||
* The reported follows of this profile.
|
||||
*/
|
||||
public int followingCount;
|
||||
public long followingCount;
|
||||
|
||||
// Optional attributes
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
||||
public List<Hashtag> tags;
|
||||
@RequiredField
|
||||
public List<Emoji> emojis;
|
||||
public int reblogsCount;
|
||||
public int favouritesCount;
|
||||
public int repliesCount;
|
||||
public long reblogsCount;
|
||||
public long favouritesCount;
|
||||
public long repliesCount;
|
||||
public Instant editedAt;
|
||||
|
||||
public String url;
|
||||
|
||||
@@ -115,9 +115,9 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
|
||||
followersCount.setText(UiUtils.abbreviateNumber(item.account.followersCount));
|
||||
followingCount.setText(UiUtils.abbreviateNumber(item.account.followingCount));
|
||||
postsCount.setText(UiUtils.abbreviateNumber(item.account.statusesCount));
|
||||
followersLabel.setText(item.parentFragment.getResources().getQuantityString(R.plurals.followers, Math.min(999, item.account.followersCount)));
|
||||
followingLabel.setText(item.parentFragment.getResources().getQuantityString(R.plurals.following, Math.min(999, item.account.followingCount)));
|
||||
postsLabel.setText(item.parentFragment.getResources().getQuantityString(R.plurals.posts, Math.min(999, item.account.statusesCount)));
|
||||
followersLabel.setText(item.parentFragment.getResources().getQuantityString(R.plurals.followers, (int)Math.min(999, item.account.followersCount)));
|
||||
followingLabel.setText(item.parentFragment.getResources().getQuantityString(R.plurals.following, (int)Math.min(999, item.account.followingCount)));
|
||||
postsLabel.setText(item.parentFragment.getResources().getQuantityString(R.plurals.posts, (int)Math.min(999, item.account.statusesCount)));
|
||||
relationship=item.parentFragment.getRelationship(item.account.id);
|
||||
if(relationship==null){
|
||||
actionWrap.setVisibility(View.GONE);
|
||||
|
||||
@@ -97,7 +97,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
|| (item.status.visibility==StatusPrivacy.PRIVATE && item.status.account.id.equals(AccountSessionManager.getInstance().getAccount(item.accountID).self.id)));
|
||||
}
|
||||
|
||||
private void bindButton(TextView btn, int count){
|
||||
private void bindButton(TextView btn, long count){
|
||||
if(count>0 && !item.hideCounts){
|
||||
btn.setText(DecimalFormat.getIntegerInstance().format(count));
|
||||
btn.setCompoundDrawablePadding(V.dp(8));
|
||||
|
||||
@@ -83,7 +83,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
itemView.setClickable(false);
|
||||
}else{
|
||||
spoilerOverlay.setVisibility(View.VISIBLE);
|
||||
text.setVisibility(View.INVISIBLE);
|
||||
text.setVisibility(View.GONE);
|
||||
itemView.setClickable(true);
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -193,6 +193,15 @@ public class UiUtils{
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public static String abbreviateNumber(long n){
|
||||
if(n<1_000_000_000L)
|
||||
return abbreviateNumber((int)n);
|
||||
|
||||
double a=n/1_000_000_000.0;
|
||||
return a>99f ? String.format("%,dB", (int)Math.floor(a)) : String.format("%,.1fB", n/1_000_000_000.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Android 6.0 has a bug where start and end compound drawables don't get tinted.
|
||||
* This works around it by setting the tint colors directly to the drawables.
|
||||
|
||||
@@ -23,6 +23,8 @@ public abstract class GithubSelfUpdater{
|
||||
return BuildConfig.BUILD_TYPE.equals("githubRelease") || BuildConfig.BUILD_TYPE.equals("debug");
|
||||
}
|
||||
|
||||
public abstract void checkForUpdates();
|
||||
|
||||
public abstract void maybeCheckForUpdates();
|
||||
|
||||
public abstract GithubSelfUpdater.UpdateState getState();
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M3 3.748c0-0.414 0.336-0.75 0.75-0.75h16.504c0.618 0 0.971 0.706 0.6 1.2L16.69 9.75l4.164 5.551c0.371 0.495 0.018 1.2-0.6 1.2H4.5v4.75c0 0.38-0.282 0.693-0.648 0.743L3.75 22c-0.38 0-0.693-0.282-0.743-0.648L3 21.25V3.748z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,3 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M3 3.748c0-0.414 0.336-0.75 0.75-0.75h16.504c0.618 0 0.971 0.706 0.6 1.2L16.69 9.75l4.164 5.551c0.371 0.495 0.018 1.2-0.6 1.2H4.5v4.75c0 0.38-0.282 0.693-0.648 0.743L3.75 22c-0.38 0-0.693-0.282-0.743-0.648L3 21.25V3.748zm15.754 0.75H4.5v10.503h14.254l-3.602-4.802c-0.2-0.266-0.2-0.633 0-0.9l3.602-4.8z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--~ Copyright (c) 2022. ~ Microsoft Corporation. All rights reserved.-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_fluent_flag_24_filled" android:state_activated="true"/>
|
||||
<item android:drawable="@drawable/ic_fluent_flag_24_filled" android:state_checked="true"/>
|
||||
<item android:drawable="@drawable/ic_fluent_flag_24_filled" android:state_selected="true"/>
|
||||
<item android:drawable="@drawable/ic_fluent_flag_24_regular"/>
|
||||
</selector>
|
||||
@@ -20,6 +20,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingVertical="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -154,6 +154,38 @@
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sensitive_item"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layoutDirection="locale"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/sensitive_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:src="@drawable/ic_fluent_flag_24_selector"
|
||||
android:tint="?android:textColorPrimary"
|
||||
android:importantForAccessibility="no"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/mark_media_as_sensitive" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="daffdsa"/>
|
||||
android:layoutDirection="locale">
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="48dp"
|
||||
android:paddingRight="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
tools:text="Account settings"/>
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:alpha="0"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -271,7 +271,7 @@
|
||||
<string name="settings_privacy_policy">Datenschutzbestimmungen</string>
|
||||
<string name="settings_spicy">Gefährliches</string>
|
||||
<string name="settings_clear_cache">Medien-Cache leeren</string>
|
||||
<string name="settings_app_version">Mastodon für Android v%1$s (%2$d)</string>
|
||||
<string name="settings_app_version">Mastodos v%1$s (%2$d)</string>
|
||||
<string name="media_cache_cleared">Medien-Cache geleert</string>
|
||||
<string name="confirm_log_out">Bist du dir sicher, dass du dich abmelden möchtest?</string>
|
||||
<string name="sensitive_content">Sensibler Inhalt</string>
|
||||
@@ -288,6 +288,7 @@
|
||||
<string name="button_share">Teilen</string>
|
||||
<string name="media_no_description">Medien ohne Beschreibung</string>
|
||||
<string name="add_media">Medien hinzufügen</string>
|
||||
<string name="mark_media_as_sensitive">Medien als NSFW markieren</string>
|
||||
<string name="add_poll">Umfrage hinzufügen</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="post_visibility">Sichtbarkeit des Beitrages</string>
|
||||
@@ -315,10 +316,12 @@
|
||||
<string name="downloading">wird heruntergeladen …</string>
|
||||
<string name="no_app_to_handle_action">Es gibt keine App, um diese Aktion auszuführen</string>
|
||||
<string name="local_timeline">Community</string>
|
||||
<string name="federated_timeline">Föderation</string>
|
||||
<string name="trending_posts_info_banner">Dies sind Beiträge, die auf deinem Mastodon-Server gerade angesagt sind.</string>
|
||||
<string name="trending_hashtags_info_banner">Dies sind Hashtags, die auf deinem Mastodon-Server gerade angesagt sind.</string>
|
||||
<string name="trending_links_info_banner">Dies sind journalistische Nachrichten, die auf deinem Mastodon-Server gerade am häufigsten geteilt werden.</string>
|
||||
<string name="local_timeline_info_banner">Dies sind die neuesten Beiträge der Leute, die den gleichen Mastodon-Server verwenden wie du.</string>
|
||||
<string name="federated_timeline_info_banner">Dies sind die neusten Beiträge der Leute, die in der Föderation deines Servers sind.</string>
|
||||
<string name="dismiss">Verwerfen</string>
|
||||
<string name="see_new_posts">Neue Beiträge anzeigen</string>
|
||||
<string name="load_missing_posts">Weitere Beiträge laden</string>
|
||||
@@ -387,10 +390,12 @@
|
||||
<string name="upload_error_connection_lost">Dein Gerät hat gerade keinen Zugang zum Internet</string>
|
||||
<string name="upload_processing">wird verarbeitet …</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_available">Mastodon für Android %s kann nun heruntergeladen werden.</string>
|
||||
<string name="update_available">Mastodos %s kann nun heruntergeladen werden.</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_ready">Mastodon für Android %s wurde heruntergeladen und kann nun installiert werden.</string>
|
||||
<string name="update_ready">Mastodos %s wurde heruntergeladen und kann nun installiert werden.</string>
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">Download (%s)</string>
|
||||
<string name="install_update">Installieren</string>
|
||||
<string name="check_for_update">Auf Update prüfen</string>
|
||||
<string name="no_update_available">Kein Update verfügbar</string>
|
||||
</resources>
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
<string name="settings_privacy_policy">Privacy policy</string>
|
||||
<string name="settings_spicy">The spicy zone</string>
|
||||
<string name="settings_clear_cache">Clear media cache</string>
|
||||
<string name="settings_app_version">Mastodon for Android v%1$s (%2$d)</string>
|
||||
<string name="settings_app_version">Mastodos v%1$s (%2$d)</string>
|
||||
<string name="media_cache_cleared">Media cache cleared</string>
|
||||
<string name="confirm_log_out">Are you sure you want to sign out?</string>
|
||||
<string name="sensitive_content">Sensitive content</string>
|
||||
@@ -294,6 +294,7 @@
|
||||
<string name="bookmarks">Bookmarks</string>
|
||||
<string name="media_no_description">Media without description</string>
|
||||
<string name="add_media">Add media</string>
|
||||
<string name="mark_media_as_sensitive">Mark media as sensitive</string>
|
||||
<string name="add_poll">Add a poll</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="post_visibility">Post visibility</string>
|
||||
@@ -396,12 +397,14 @@
|
||||
<string name="upload_error_connection_lost">Your device lost connection to the internet</string>
|
||||
<string name="upload_processing">Processing…</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_available">Mastodon for Android %s is ready to download.</string>
|
||||
<string name="update_available">Mastodos %s is ready to download.</string>
|
||||
<!-- %s is version like 1.2.3 -->
|
||||
<string name="update_ready">Mastodon for Android %s is downloaded and ready to install.</string>
|
||||
<string name="update_ready">Mastodos %s is downloaded and ready to install.</string>
|
||||
<!-- %s is file size -->
|
||||
<string name="download_update">Download (%s)</string>
|
||||
<string name="install_update">Install</string>
|
||||
<string name="check_for_update">Check for update</string>
|
||||
<string name="no_update_available">No update available</string>
|
||||
<string name="privacy_policy_title">Mastodon and your privacy</string>
|
||||
<string name="privacy_policy_subtitle">Although the Mastodon app does not collect any data, the server you sign up through may have a different policy. Take a minute to review and agree to the Mastodon app privacy policy and your server\'s privacy policy.</string>
|
||||
<string name="i_agree">I Agree</string>
|
||||
|
||||
34
mastodon/src/main/res/xml/locales_config.xml
Normal file
34
mastodon/src/main/res/xml/locales_config.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<locale android:name="en" />
|
||||
<locale android:name="ar" />
|
||||
<locale android:name="bs" />
|
||||
<locale android:name="ca" />
|
||||
<locale android:name="cs" />
|
||||
<locale android:name="de" />
|
||||
<locale android:name="el" />
|
||||
<locale android:name="es" />
|
||||
<locale android:name="eu" />
|
||||
<locale android:name="fi" />
|
||||
<locale android:name="fr" />
|
||||
<locale android:name="gl" />
|
||||
<locale android:name="hr" />
|
||||
<locale android:name="hy" />
|
||||
<locale android:name="it" />
|
||||
<locale android:name="iw" />
|
||||
<locale android:name="ja" />
|
||||
<locale android:name="kab" />
|
||||
<locale android:name="ko" />
|
||||
<locale android:name="oc" />
|
||||
<locale android:name="pl" />
|
||||
<locale android:name="pt-BR" />
|
||||
<locale android:name="pt-PT" />
|
||||
<locale android:name="ru" />
|
||||
<locale android:name="sv" />
|
||||
<locale android:name="th" />
|
||||
<locale android:name="tr" />
|
||||
<locale android:name="uk" />
|
||||
<locale android:name="vi" />
|
||||
<locale android:name="zh-Hans" />
|
||||
<locale android:name="zh-Hant" />
|
||||
</locale-config>
|
||||
Reference in New Issue
Block a user