Compare commits

...

30 Commits

Author SHA1 Message Date
sk
e5fab4a555 update changelog, bump version 2022-12-09 21:25:24 +01:00
sk
abe28179ec use saved default status visibility 2022-12-09 21:23:20 +01:00
sk
60d4e4d396 use default posting language 2022-12-09 21:15:11 +01:00
sk
435e73d718 Merge branch 'feature/language-selector' 2022-12-09 20:56:09 +01:00
sk
17dc0850d5 apply language when replying 2022-12-09 20:53:56 +01:00
sk
9667a32e44 save recently used languages 2022-12-09 20:48:51 +01:00
sk
4e6ba84bb3 implement language selector 2022-12-09 19:34:43 +01:00
sk
8714b24388 bump version 2022-12-09 03:15:01 +01:00
sk
495db142d7 update readme 2022-12-09 03:14:11 +01:00
sk
ac5d11159f Merge branch 'feature/translate-button' 2022-12-09 03:05:59 +01:00
sk
d1479f142b add progress spinner 2022-12-09 03:05:17 +01:00
sk
ee6ec631e8 Merge branch 'feature/translate-button' 2022-12-09 02:46:55 +01:00
sk
dee21222a7 implement translate feature 2022-12-09 02:37:38 +01:00
sk
cd8123ca34 Merge remote-tracking branch 'upstream/master' 2022-12-08 21:41:38 +01:00
sk
ceb08ea78d fix get started button color 2022-12-08 21:36:50 +01:00
Gregory K
b79ba71228 Merge pull request #445 from sk22/better-inline-emoji-search
Improve inline emoji search
2022-12-08 23:22:24 +03:00
Grishka
2903874dbc Splash fragment redesign 2022-12-08 23:22:10 +03:00
sk
cac5b554e2 Merge remote-tracking branch 'upstream/master' 2022-12-08 21:02:45 +01:00
sk
c4adbc8e45 update changelog/readme 2022-12-08 21:02:06 +01:00
sk
bb01077c3b Merge branch 'feature/mark-media-as-sensitive' 2022-12-08 21:00:43 +01:00
sk
b370fcda6d add bottom margin to sensitive toggle 2022-12-08 21:00:30 +01:00
sk
d364ebbb2f Merge branch 'better-poll-voting' 2022-12-08 20:56:19 +01:00
sk
5b28468efd add option to allow multiple poll choices 2022-12-08 20:53:34 +01:00
sk
6fd58c9682 improve semantics for poll options 2022-12-08 19:56:04 +01:00
sk
b580743619 fix poll option displaying wrong own vote
fixes #132
2022-12-08 16:03:46 +01:00
sk
4a9cb9f2dc fix poll option displaying wrong own vote
fixes #132
2022-12-08 15:53:35 +01:00
Grishka
202a5f9581 Fix #443 again 2022-12-08 01:48:23 +03:00
sk22
145f55817f Translated using Weblate (German)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2022-12-07 18:20:46 +00:00
sk
79025c2f36 update description 2022-12-07 19:19:05 +01:00
sk
2515a8d381 add missing item to changelog 2022-12-07 19:16:14 +01:00
45 changed files with 768 additions and 146 deletions

View File

@@ -132,6 +132,9 @@ There's also a handful of custom strings exclusive to this projects that would n
* [Clickable reply/boost line above posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:clickable-boost-reply-line) * [Clickable reply/boost line above posts](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:clickable-boost-reply-line)
* [Clickable reply line while replying to open original post](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/clickable-reply-line-compose) * [Clickable reply line while replying to open original post](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/clickable-reply-line-compose)
* [Add push notification setting for post notifications](https://github.com/sk22/megalodon/commit/b190480d7739be47f23543d9e7644660f9b4b4ee) * [Add push notification setting for post notifications](https://github.com/sk22/megalodon/commit/b190480d7739be47f23543d9e7644660f9b4b4ee)
* [Add option to allow voting for multiple options on polls](https://github.com/sk22/megalodon/commit/5b28468efd49387b4f8b83f142f3adf3104ca60c)
* [Add translate function](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/translate-button)
* [Add language selector](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/language-selector)
### Behavior ### Behavior
@@ -148,6 +151,7 @@ There's also a handful of custom strings exclusive to this projects that would n
* [Show own vote after voting](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28) ([Closes issue](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28)) * [Show own vote after voting](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28) ([Closes issue](https://github.com/mastodon/mastodon-android/commit/4ab9e25fec4fd9c10b7a8ddd1be522b3cc12cf28))
* [Make inline emoji search case-insensitive and don't only search from start of emoji names](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:better-inline-emoji-search) ([Pull request](https://github.com/mastodon/mastodon-android/pull/445)) * [Make inline emoji search case-insensitive and don't only search from start of emoji names](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:better-inline-emoji-search) ([Pull request](https://github.com/mastodon/mastodon-android/pull/445))
* [Include subject line when sharing e.g. a website to Megalodon](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:external-share-include-subject) * [Include subject line when sharing e.g. a website to Megalodon](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:external-share-include-subject)
* [Improve semantics for voting on polls (radio buttons and checkboxes)](https://github.com/sk22/megalodon/commit/6fd58c96827cb1d2da329cebdc170a1425dd18d7)
### Visual ### Visual
@@ -156,6 +160,7 @@ There's also a handful of custom strings exclusive to this projects that would n
* [Improvements to the true black mode](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:true-black-improvements) * [Improvements to the true black mode](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:true-black-improvements)
* [Profile header tweaks](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:ui/profile-header-tweaks) * [Profile header tweaks](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:ui/profile-header-tweaks)
* [Custom color themes](https://github.com/sk22/megalodon/pull/124) by [@LucasGGamerM](https://github.com/LucasGGamerM) * [Custom color themes](https://github.com/sk22/megalodon/pull/124) by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Custom "megalodon" text logo](https://github.com/sk22/megalodon/commit/563afd487ca5c608cfbb00fa3909d3c27384acc0) by [@LucasGGamerM](https://github.com/LucasGGamerM)
## Building ## Building

View File

@@ -9,8 +9,8 @@ android {
applicationId "org.joinmastodon.android.sk" applicationId "org.joinmastodon.android.sk"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 33
versionCode 56 versionCode 58
versionName "1.1.4+fork.56" versionName "1.1.4+fork.58"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "en", "ar-rSA", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES", 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", "eu-rES", "fi-rFI", "fr-rFR", "gl-rES", "hr-rHR", "hy-rAM", "it-rIT", "iw-rIL",

View File

@@ -2,6 +2,14 @@ package org.joinmastodon.android;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class GlobalUserPreferences{ public class GlobalUserPreferences{
public static boolean playGifs; public static boolean playGifs;
@@ -17,6 +25,21 @@ public class GlobalUserPreferences{
public static boolean voteButtonForSingleChoice; public static boolean voteButtonForSingleChoice;
public static ThemePreference theme; public static ThemePreference theme;
public static ColorPreference color; public static ColorPreference color;
public static List<String> recentLanguages;
private static String defaultRecentLanguages;
static {
List<Locale> systemLocales = new ArrayList<>();;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
systemLocales.add(Resources.getSystem().getConfiguration().locale);
} else {
LocaleList localeList = Resources.getSystem().getConfiguration().getLocales();
for (int i = 0; i < localeList.size(); i++) systemLocales.add(localeList.get(i));
}
defaultRecentLanguages = systemLocales.stream().map(Locale::getLanguage).collect(Collectors.joining(","));
}
private static SharedPreferences getPrefs(){ private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE); return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
@@ -37,6 +60,7 @@ public class GlobalUserPreferences{
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true); voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)]; theme=ThemePreference.values()[prefs.getInt("theme", 0)];
color=ColorPreference.values()[prefs.getInt("color", 0)]; color=ColorPreference.values()[prefs.getInt("color", 0)];
recentLanguages=Arrays.stream(prefs.getString("recentLanguages", defaultRecentLanguages).split(",")).filter(s->!s.isEmpty()).collect(Collectors.toList());
} }
public static void save(){ public static void save(){
@@ -53,6 +77,7 @@ public class GlobalUserPreferences{
.putBoolean("disableMarquee", disableMarquee) .putBoolean("disableMarquee", disableMarquee)
.putInt("theme", theme.ordinal()) .putInt("theme", theme.ordinal())
.putInt("color", color.ordinal()) .putInt("color", color.ordinal())
.putString("recentLanguages", String.join(",", recentLanguages))
.apply(); .apply();
} }

View File

@@ -7,4 +7,15 @@ public class GetInstance extends MastodonAPIRequest<Instance>{
public GetInstance(){ public GetInstance(){
super(HttpMethod.GET, "/instance", Instance.class); super(HttpMethod.GET, "/instance", Instance.class);
} }
public static class V2 extends MastodonAPIRequest<Instance.V2>{
public V2(){
super(HttpMethod.GET, "/instance", Instance.V2.class);
}
@Override
protected String getPathPrefix() {
return "/api/v2";
}
}
} }

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.TranslatedStatus;
public class TranslateStatus extends MastodonAPIRequest<TranslatedStatus> {
public TranslateStatus(String id) {
super(HttpMethod.POST, "/statuses/"+id+"/translate", TranslatedStatus.class);
setRequestBody(new Object());
}
}

View File

@@ -7,6 +7,7 @@ import org.joinmastodon.android.api.StatusInteractionController;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Application; import org.joinmastodon.android.model.Application;
import org.joinmastodon.android.model.Filter; import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.PushSubscription; import org.joinmastodon.android.model.PushSubscription;
import org.joinmastodon.android.model.Token; import org.joinmastodon.android.model.Token;
@@ -28,6 +29,7 @@ public class AccountSession{
public long filtersLastUpdated; public long filtersLastUpdated;
public List<Filter> wordFilters=new ArrayList<>(); public List<Filter> wordFilters=new ArrayList<>();
public String pushAccountID; public String pushAccountID;
public Preferences preferences;
private transient MastodonAPIController apiController; private transient MastodonAPIController apiController;
private transient StatusInteractionController statusInteractionController; private transient StatusInteractionController statusInteractionController;
private transient CacheController cacheController; private transient CacheController cacheController;

View File

@@ -22,6 +22,7 @@ import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController; import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.PushSubscriptionManager; import org.joinmastodon.android.api.PushSubscriptionManager;
import org.joinmastodon.android.api.requests.accounts.GetPreferences;
import org.joinmastodon.android.api.requests.accounts.GetWordFilters; import org.joinmastodon.android.api.requests.accounts.GetWordFilters;
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis; import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount; import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
@@ -34,6 +35,7 @@ import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory; import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.model.Filter; import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.Token; import org.joinmastodon.android.model.Token;
import java.io.File; import java.io.File;
@@ -248,12 +250,13 @@ public class AccountSessionManager{
HashSet<String> domains=new HashSet<>(); HashSet<String> domains=new HashSet<>();
for(AccountSession session:sessions.values()){ for(AccountSession session:sessions.values()){
domains.add(session.domain.toLowerCase()); domains.add(session.domain.toLowerCase());
if(now-session.infoLastUpdated>24L*3600_000L){ // if(now-session.infoLastUpdated>24L*3600_000L){
updateSessionPreferences(session);
updateSessionLocalInfo(session); updateSessionLocalInfo(session);
} // }
if(now-session.filtersLastUpdated>3600_000L){ // if(now-session.filtersLastUpdated>3600_000L){
updateSessionWordFilters(session); updateSessionWordFilters(session);
} // }
} }
if(loadedInstances){ if(loadedInstances){
maybeUpdateCustomEmojis(domains); maybeUpdateCustomEmojis(domains);
@@ -263,10 +266,10 @@ public class AccountSessionManager{
private void maybeUpdateCustomEmojis(Set<String> domains){ private void maybeUpdateCustomEmojis(Set<String> domains){
long now=System.currentTimeMillis(); long now=System.currentTimeMillis();
for(String domain:domains){ for(String domain:domains){
Long lastUpdated=instancesLastUpdated.get(domain); // Long lastUpdated=instancesLastUpdated.get(domain);
if(lastUpdated==null || now-lastUpdated>24L*3600_000L){ // if(lastUpdated==null || now-lastUpdated>24L*3600_000L){
updateInstanceInfo(domain); updateInstanceInfo(domain);
} // }
} }
} }
@@ -288,6 +291,18 @@ public class AccountSessionManager{
.exec(session.getID()); .exec(session.getID());
} }
private void updateSessionPreferences(AccountSession session){
new GetPreferences().setCallback(new Callback<>() {
@Override
public void onSuccess(Preferences preferences) {
session.preferences=preferences;
}
@Override
public void onError(ErrorResponse error) {}
}).exec(session.getID());
}
private void updateSessionWordFilters(AccountSession session){ private void updateSessionWordFilters(AccountSession session){
new GetWordFilters() new GetWordFilters()
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@@ -313,6 +328,11 @@ public class AccountSessionManager{
public void onSuccess(Instance instance){ public void onSuccess(Instance instance){
instances.put(domain, instance); instances.put(domain, instance);
updateInstanceEmojis(instance, domain); updateInstanceEmojis(instance, domain);
try {
if (Integer.parseInt(instance.version.split("\\.")[0]) >= 4) {
updateInstanceInfoV2(domain);
}
} catch (Exception ignored) {}
} }
@Override @Override
@@ -323,6 +343,19 @@ public class AccountSessionManager{
.execNoAuth(domain); .execNoAuth(domain);
} }
public void updateInstanceInfoV2(String domain) {
new GetInstance.V2().setCallback(new Callback<>() {
@Override
public void onSuccess(Instance.V2 v2) {
Instance instanceInfo = instances.get(domain);
if (instanceInfo != null) instanceInfo.v2 = v2;
}
@Override
public void onError(ErrorResponse errorResponse) {}
}).execNoAuth(domain);
}
private void updateInstanceEmojis(Instance instance, String domain){ private void updateInstanceEmojis(Instance instance, String domain){
new GetCustomEmojis() new GetCustomEmojis()
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@@ -398,6 +431,10 @@ public class AccountSessionManager{
return instances.get(domain); return instances.get(domain);
} }
public Instance getInstanceInfoForAccount(String account) {
return AccountSessionManager.getInstance().getInstanceInfo(instance.getAccount(account).domain);
}
public void updateAccountInfo(String id, Account account){ public void updateAccountInfo(String id, Account account){
AccountSession session=getAccount(id); AccountSession session=getAccount(id);
session.self=account; session.self=account;

View File

@@ -29,11 +29,13 @@ import android.text.Spanned;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log; import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewOutlineProvider; import android.view.ViewOutlineProvider;
@@ -41,6 +43,7 @@ import android.view.WindowManager;
import android.view.animation.LinearInterpolator; import android.view.animation.LinearInterpolator;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
@@ -54,6 +57,7 @@ import android.widget.Toast;
import com.twitter.twittertext.TwitterTextEmojiRegex; import com.twitter.twittertext.TwitterTextEmojiRegex;
import org.joinmastodon.android.E; import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController; import org.joinmastodon.android.api.MastodonAPIController;
@@ -102,6 +106,8 @@ import java.net.SocketException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.UUID; import java.util.UUID;
@@ -129,6 +135,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
// from https://github.com/mastodon/mastodon-ios/blob/main/Mastodon/Helper/MastodonRegex.swift // from https://github.com/mastodon/mastodon-ios/blob/main/Mastodon/Helper/MastodonRegex.swift
private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))"); private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+)|:([a-zA-Z0-9_]+))");
private static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))"); private static final Pattern HIGHLIGHT_PATTERN=Pattern.compile("(?<!\\w)(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))");
private static final List<Locale> allIsoLanguages;
@SuppressLint("NewApi") // this class actually exists on 6.0 @SuppressLint("NewApi") // this class actually exists on 6.0
private final BreakIterator breakIterator=BreakIterator.getCharacterInstance(); private final BreakIterator breakIterator=BreakIterator.getCharacterInstance();
@@ -144,7 +151,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private String accountID; private String accountID;
private int charCount, charLimit, trimmedCharCount; private int charCount, charLimit, trimmedCharCount;
private Button publishButton; private Button publishButton, languageButton;
private PopupMenu languagePopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn; private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
private ImageView sensitiveIcon; private ImageView sensitiveIcon;
private ComposeMediaLayout attachmentsView; private ComposeMediaLayout attachmentsView;
@@ -153,6 +161,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private View pollWrap; private View pollWrap;
private View addPollOptionBtn; private View addPollOptionBtn;
private View sensitiveItem; private View sensitiveItem;
private View pollAllowMultipleItem;
private CheckBox pollAllowMultipleCheckbox;
private TextView pollDurationView; private TextView pollDurationView;
private ArrayList<DraftPollOption> pollOptions=new ArrayList<>(); private ArrayList<DraftPollOption> pollOptions=new ArrayList<>();
@@ -187,6 +197,24 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private boolean ignoreSelectionChanges=false; private boolean ignoreSelectionChanges=false;
private Runnable updateUploadEtaRunnable; private Runnable updateUploadEtaRunnable;
private String language;
static {
Locale[] locales = Locale.getAvailableLocales();
List<Locale> allLocales = new ArrayList<>();
List<String> addedLanguages = new ArrayList<>();
for (Locale locale : locales) {
String lang = locale.getLanguage();
if (!addedLanguages.contains(lang)) {
allLocales.add(locale);
addedLanguages.add(lang);
}
}
Collections.sort(allLocales, Comparator.comparing(l -> l.getDisplayLanguage(Locale.getDefault())));
allIsoLanguages = allLocales;
}
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -216,8 +244,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
charLimit=instance.configuration.statuses.maxCharacters; charLimit=instance.configuration.statuses.maxCharacters;
else else
charLimit=500; charLimit=500;
loadDefaultStatusVisibility(savedInstanceState);
} }
@Override @Override
@@ -297,6 +323,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
pollOptionsView=view.findViewById(R.id.poll_options); pollOptionsView=view.findViewById(R.id.poll_options);
pollWrap=view.findViewById(R.id.poll_wrap); pollWrap=view.findViewById(R.id.poll_wrap);
addPollOptionBtn=view.findViewById(R.id.add_poll_option); addPollOptionBtn=view.findViewById(R.id.add_poll_option);
pollAllowMultipleItem=view.findViewById(R.id.poll_allow_multiple);
pollAllowMultipleCheckbox=view.findViewById(R.id.poll_allow_multiple_checkbox);
pollAllowMultipleItem.setOnClickListener(v->this.togglePollAllowMultiple());
addPollOptionBtn.setOnClickListener(v->{ addPollOptionBtn.setOnClickListener(v->{
createDraftPollOption().edit.requestFocus(); createDraftPollOption().edit.requestFocus();
@@ -311,6 +340,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
pollBtn.setSelected(true); pollBtn.setSelected(true);
mediaBtn.setEnabled(false); mediaBtn.setEnabled(false);
pollWrap.setVisibility(View.VISIBLE); pollWrap.setVisibility(View.VISIBLE);
updatePollAllowMultiple(savedInstanceState.getBoolean("pollAllowMultiple", false));
for(String oldText:savedInstanceState.getStringArrayList("pollOptions")){ for(String oldText:savedInstanceState.getStringArrayList("pollOptions")){
DraftPollOption opt=createDraftPollOption(); DraftPollOption opt=createDraftPollOption();
opt.edit.setText(oldText); opt.edit.setText(oldText);
@@ -321,6 +351,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
pollBtn.setSelected(true); pollBtn.setSelected(true);
mediaBtn.setEnabled(false); mediaBtn.setEnabled(false);
pollWrap.setVisibility(View.VISIBLE); pollWrap.setVisibility(View.VISIBLE);
updatePollAllowMultiple(editingStatus.poll.multiple);
for(Poll.Option eopt:editingStatus.poll.options){ for(Poll.Option eopt:editingStatus.poll.options){
DraftPollOption opt=createDraftPollOption(); DraftPollOption opt=createDraftPollOption();
opt.edit.setText(eopt.title); opt.edit.setText(eopt.title);
@@ -367,6 +398,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
statusVisibility=editingStatus.visibility; statusVisibility=editingStatus.visibility;
} }
loadDefaultStatusVisibility(savedInstanceState);
updateVisibilityIcon(); updateVisibilityIcon();
autocompleteViewController=new ComposeAutocompleteViewController(getActivity(), accountID); autocompleteViewController=new ComposeAutocompleteViewController(getActivity(), accountID);
@@ -391,9 +423,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
outState.putStringArrayList("pollOptions", opts); outState.putStringArrayList("pollOptions", opts);
outState.putInt("pollDuration", pollDuration); outState.putInt("pollDuration", pollDuration);
outState.putString("pollDurationStr", pollDurationStr); outState.putString("pollDurationStr", pollDurationStr);
outState.putBoolean("pollAllowMultiple", pollAllowMultipleItem.isSelected());
} }
outState.putBoolean("sensitive", sensitive); outState.putBoolean("sensitive", sensitive);
outState.putBoolean("hasSpoiler", hasSpoiler); outState.putBoolean("hasSpoiler", hasSpoiler);
outState.putString("language", language);
if(!attachments.isEmpty()){ if(!attachments.isEmpty()){
ArrayList<Parcelable> serializedAttachments=new ArrayList<>(attachments.size()); ArrayList<Parcelable> serializedAttachments=new ArrayList<>(attachments.size());
for(DraftMediaAttachment att:attachments){ for(DraftMediaAttachment att:attachments){
@@ -533,6 +567,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
spoilerEdit.setText(replyTo.spoilerText); spoilerEdit.setText(replyTo.spoilerText);
spoilerBtn.setSelected(true); spoilerBtn.setSelected(true);
} }
if (replyTo.language != null && !replyTo.language.isEmpty()) updateLanguage(replyTo.language);
} }
}else if (editingStatus==null || editingStatus.inReplyToId==null){ }else if (editingStatus==null || editingStatus.inReplyToId==null){
// TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed // TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed
@@ -545,6 +580,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
ignoreSelectionChanges=true; ignoreSelectionChanges=true;
mainEditText.setSelection(mainEditText.length()); mainEditText.setSelection(mainEditText.length());
ignoreSelectionChanges=false; ignoreSelectionChanges=false;
updateLanguage(editingStatus.language);
if(!editingStatus.mediaAttachments.isEmpty()){ if(!editingStatus.mediaAttachments.isEmpty()){
attachmentsView.setVisibility(View.VISIBLE); attachmentsView.setVisibility(View.VISIBLE);
for(Attachment att:editingStatus.mediaAttachments){ for(Attachment att:editingStatus.mediaAttachments){
@@ -607,6 +643,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
sendError.setVisibility(View.GONE); sendError.setVisibility(View.GONE);
sendProgress.setVisibility(View.GONE); sendProgress.setVisibility(View.GONE);
LinearLayout.LayoutParams langParams=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
langParams.setMarginEnd(V.dp(8));
wrap.addView(buildLanguageSelector(), langParams);
wrap.addView(publishButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); wrap.addView(publishButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
wrap.setPadding(V.dp(16), V.dp(4), V.dp(16), V.dp(8)); wrap.setPadding(V.dp(16), V.dp(4), V.dp(16), V.dp(8));
wrap.setClipToPadding(false); wrap.setClipToPadding(false);
@@ -616,6 +656,59 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
updatePublishButtonState(); updatePublishButtonState();
} }
private void updateLanguage(String lang) {
updateLanguage(new Locale(lang));
}
private void updateLanguage(Locale loc) {
language = loc.getLanguage();
languageButton.setText(loc.getDisplayLanguage(loc));
languageButton.setContentDescription(getActivity().getString(R.string.sk_post_language, loc.getDisplayLanguage(Locale.getDefault())));
}
@SuppressLint("ClickableViewAccessibility")
private Button buildLanguageSelector() {
languageButton=new Button(getActivity());
TypedValue typedValue = new TypedValue();
getActivity().getTheme().resolveAttribute(android.R.attr.textColorSecondary, typedValue, true);
languageButton.setTextColor(typedValue.data);
languageButton.setBackground(getActivity().getDrawable(R.drawable.bg_text_button));
languageButton.setPadding(V.dp(8), 0, V.dp(8), 0);
languageButton.setCompoundDrawablesRelativeWithIntrinsicBounds(getActivity().getDrawable(R.drawable.ic_fluent_local_language_16_regular), null, null, null);
languageButton.setCompoundDrawableTintList(languageButton.getTextColors());
languageButton.setCompoundDrawablePadding(V.dp(6));
languagePopup=new PopupMenu(getActivity(), languageButton);
languageButton.setOnTouchListener(languagePopup.getDragToOpenListener());
languageButton.setOnClickListener(v->languagePopup.show());
Preferences prefs = AccountSessionManager.getInstance().getAccount(accountID).preferences;
String defaultLang = prefs != null ? prefs.postingDefaultLanguage : null;
if (defaultLang != null) updateLanguage(defaultLang);
else updateLanguage(Locale.getDefault());
Menu languageMenu = languagePopup.getMenu();
for (String recentLanguage : GlobalUserPreferences.recentLanguages) {
Locale loc = new Locale(recentLanguage);
languageMenu.add(0, allIsoLanguages.indexOf(loc), Menu.NONE, loc.getDisplayLanguage(Locale.getDefault()));
}
SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.sk_all_languages);
for (int i = 0; i < allIsoLanguages.size(); i++) {
Locale loc = allIsoLanguages.get(i);
allLanguagesMenu.add(0, i, Menu.NONE, loc.getDisplayLanguage(Locale.getDefault()));
}
languagePopup.setOnMenuItemClickListener(i->{
if (i.hasSubMenu()) return false;
updateLanguage(allIsoLanguages.get(i.getItemId()));
return true;
});
return languageButton;
}
@Override @Override
public boolean onOptionsItemSelected(MenuItem item){ public boolean onOptionsItemSelected(MenuItem item){
return true; return true;
@@ -689,6 +782,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.status=text; req.status=text;
req.visibility=statusVisibility; req.visibility=statusVisibility;
req.sensitive=sensitive; req.sensitive=sensitive;
req.language=language;
if(!attachments.isEmpty()){ if(!attachments.isEmpty()){
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList()); req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
} }
@@ -698,6 +792,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
if(!pollOptions.isEmpty()){ if(!pollOptions.isEmpty()){
req.poll=new CreateStatus.Request.Poll(); req.poll=new CreateStatus.Request.Poll();
req.poll.expiresIn=pollDuration; req.poll.expiresIn=pollDuration;
req.poll.multiple=pollAllowMultipleItem.isSelected();
for(DraftPollOption opt:pollOptions) for(DraftPollOption opt:pollOptions)
req.poll.options.add(opt.edit.getText().toString()); req.poll.options.add(opt.edit.getText().toString());
} }
@@ -765,6 +860,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.setCallback(resCallback) .setCallback(resCallback)
.exec(accountID); .exec(accountID);
} }
List<String> recentLanguages = new ArrayList<>(GlobalUserPreferences.recentLanguages);
recentLanguages.remove(language);
recentLanguages.add(0, language);
GlobalUserPreferences.recentLanguages = recentLanguages.stream().limit(4).collect(Collectors.toList());
GlobalUserPreferences.save();
} }
private boolean hasDraft(){ private boolean hasDraft(){
@@ -1208,6 +1309,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
option.view=LayoutInflater.from(getActivity()).inflate(R.layout.compose_poll_option, pollOptionsView, false); option.view=LayoutInflater.from(getActivity()).inflate(R.layout.compose_poll_option, pollOptionsView, false);
option.edit=option.view.findViewById(R.id.edit); option.edit=option.view.findViewById(R.id.edit);
option.dragger=option.view.findViewById(R.id.dragger_thingy); option.dragger=option.view.findViewById(R.id.dragger_thingy);
ImageView icon = option.view.findViewById(R.id.icon);
icon.setImageDrawable(getContext().getDrawable(pollAllowMultipleItem.isSelected() ?
R.drawable.ic_poll_checkbox_regular_selector :
R.drawable.ic_poll_option_button
));
option.dragger.setOnLongClickListener(v->{ option.dragger.setOnLongClickListener(v->{
pollOptionsView.startDragging(option.view); pollOptionsView.startDragging(option.view);
@@ -1343,13 +1449,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility"); statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
} }
new GetPreferences() Preferences prefs = AccountSessionManager.getInstance().getAccount(accountID).preferences;
.setCallback(new Callback<>(){ if (prefs != null) {
@Override
public void onSuccess(Preferences result){
// Only override the reply visibility if our preference is more private // Only override the reply visibility if our preference is more private
if (result.postingDefaultVisibility.isLessVisibleThan(statusVisibility)) { if (prefs.postingDefaultVisibility.isLessVisibleThan(statusVisibility)) {
statusVisibility = switch (result.postingDefaultVisibility) { statusVisibility = switch (prefs.postingDefaultVisibility) {
case PUBLIC -> StatusPrivacy.PUBLIC; case PUBLIC -> StatusPrivacy.PUBLIC;
case UNLISTED -> StatusPrivacy.UNLISTED; case UNLISTED -> StatusPrivacy.UNLISTED;
case PRIVATE -> StatusPrivacy.PRIVATE; case PRIVATE -> StatusPrivacy.PRIVATE;
@@ -1361,16 +1465,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
if(savedInstanceState !=null){ if(savedInstanceState !=null){
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility"); statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
} }
updateVisibilityIcon ();
} }
@Override
public void onError(ErrorResponse error){
Log.w(TAG, "Unable to get user preferences to set default post privacy");
}
})
.exec(accountID);
} }
private void updateVisibilityIcon(){ private void updateVisibilityIcon(){
@@ -1385,6 +1480,27 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}); });
} }
private void togglePollAllowMultiple() {
updatePollAllowMultiple(!pollAllowMultipleItem.isSelected());
}
private void updatePollAllowMultiple(boolean multiple){
pollAllowMultipleItem.setSelected(multiple);
pollAllowMultipleCheckbox.setChecked(multiple);
ImageView btn = addPollOptionBtn.findViewById(R.id.add_poll_option_icon);
btn.setImageDrawable(getContext().getDrawable(multiple ?
R.drawable.ic_fluent_add_square_24_regular :
R.drawable.ic_fluent_add_circle_24_regular
));
for (DraftPollOption opt:pollOptions) {
ImageView icon = opt.view.findViewById(R.id.icon);
icon.setImageDrawable(getContext().getDrawable(multiple ?
R.drawable.ic_poll_checkbox_regular_selector :
R.drawable.ic_poll_option_button
));
}
}
@Override @Override
public void onSelectionChanged(int start, int end){ public void onSelectionChanged(int start, int end){
if(ignoreSelectionChanges) if(ignoreSelectionChanges)

View File

@@ -159,6 +159,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
} }
items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon"))); items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon")));
items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache)); items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache));
items.add(new TextItem(R.string.sk_clear_recent_languages, ()->UiUtils.showConfirmationAlert(getActivity(), R.string.sk_clear_recent_languages, R.string.sk_confirm_clear_recent_languages, R.string.clear, ()->{
GlobalUserPreferences.recentLanguages.clear();
GlobalUserPreferences.save();
})));
items.add(new TextItem(R.string.log_out, this::confirmLogOut)); items.add(new TextItem(R.string.log_out, this::confirmLogOut));
items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE))); items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));

View File

@@ -1,11 +1,19 @@
package org.joinmastodon.android.fragments; package org.joinmastodon.android.fragments;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.text.style.ReplacementSpan;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
@@ -14,7 +22,11 @@ import org.joinmastodon.android.fragments.onboarding.InstanceChooserLoginFragmen
import org.joinmastodon.android.ui.InterpolatingMotionEffect; import org.joinmastodon.android.ui.InterpolatingMotionEffect;
import org.joinmastodon.android.ui.views.SizeListenerFrameLayout; import org.joinmastodon.android.ui.views.SizeListenerFrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager2.widget.ViewPager2;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.fragments.AppKitFragment; import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
@@ -23,12 +35,13 @@ public class SplashFragment extends AppKitFragment{
private SizeListenerFrameLayout contentView; private SizeListenerFrameLayout contentView;
private View artContainer, blueFill, greenFill; private View artContainer, blueFill, greenFill;
private InterpolatingMotionEffect motionEffect; private ViewPager2 pager;
private ViewGroup pagerDots;
private View artClouds, artPlaneElephant, artRightHill, artLeftHill, artCenterHill;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
} }
@Nullable @Nullable
@@ -37,15 +50,44 @@ public class SplashFragment extends AppKitFragment{
contentView=(SizeListenerFrameLayout) inflater.inflate(R.layout.fragment_splash, container, false); contentView=(SizeListenerFrameLayout) inflater.inflate(R.layout.fragment_splash, container, false);
contentView.findViewById(R.id.btn_get_started).setOnClickListener(this::onButtonClick); contentView.findViewById(R.id.btn_get_started).setOnClickListener(this::onButtonClick);
contentView.findViewById(R.id.btn_log_in).setOnClickListener(this::onButtonClick); contentView.findViewById(R.id.btn_log_in).setOnClickListener(this::onButtonClick);
artClouds=contentView.findViewById(R.id.art_clouds);
artPlaneElephant=contentView.findViewById(R.id.art_plane_elephant);
artRightHill=contentView.findViewById(R.id.art_right_hill);
artLeftHill=contentView.findViewById(R.id.art_left_hill);
artCenterHill=contentView.findViewById(R.id.art_center_hill);
pager=contentView.findViewById(R.id.pager);
pagerDots=contentView.findViewById(R.id.pager_dots);
pager.setAdapter(new PagerAdapter());
pager.setOffscreenPageLimit(3);
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback(){
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
for(int i=0;i<pagerDots.getChildCount();i++){
float alpha;
if(i==position){
alpha=0.3f+0.7f*(1f-positionOffset);
}else if(i==position+1){
alpha=0.3f+0.7f*positionOffset;
}else{
alpha=0.3f;
}
pagerDots.getChildAt(i).setAlpha(alpha);
}
float parallaxProgress=(position+positionOffset)/2f;
artClouds.setTranslationX(V.dp(-27)*(position>=1 ? 1f : positionOffset));
artPlaneElephant.setTranslationX(V.dp(101.55f)*parallaxProgress);
artLeftHill.setTranslationX(V.dp(-88)*parallaxProgress);
artLeftHill.setTranslationY(V.dp(24)*parallaxProgress);
artRightHill.setTranslationX(V.dp(-88)*parallaxProgress);
artRightHill.setTranslationY(V.dp(-24)*parallaxProgress);
artCenterHill.setTranslationX(V.dp(-40)*parallaxProgress);
}
});
artContainer=contentView.findViewById(R.id.art_container); artContainer=contentView.findViewById(R.id.art_container);
blueFill=contentView.findViewById(R.id.blue_fill); blueFill=contentView.findViewById(R.id.blue_fill);
greenFill=contentView.findViewById(R.id.green_fill); greenFill=contentView.findViewById(R.id.green_fill);
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_clouds), V.dp(-5), V.dp(5), V.dp(-5), V.dp(5)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_right_hill), V.dp(-15), V.dp(25), V.dp(-10), V.dp(10)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_left_hill), V.dp(-25), V.dp(15), V.dp(-15), V.dp(15)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_center_hill), V.dp(-14), V.dp(14), V.dp(-5), V.dp(25)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_plane_elephant), V.dp(-20), V.dp(12), V.dp(-20), V.dp(12)));
contentView.setSizeListener(new SizeListenerFrameLayout.OnSizeChangedListener(){ contentView.setSizeListener(new SizeListenerFrameLayout.OnSizeChangedListener(){
@Override @Override
@@ -72,10 +114,10 @@ public class SplashFragment extends AppKitFragment{
} }
private void updateArtSize(int w, int h){ private void updateArtSize(int w, int h){
float scale=w/(float)V.dp(412); float scale=w/(float)V.dp(360);
artContainer.setScaleX(scale); artContainer.setScaleX(scale);
artContainer.setScaleY(scale); artContainer.setScaleY(scale);
blueFill.setScaleY(h/2f); blueFill.setScaleY(artContainer.getBottom()-V.dp(90));
greenFill.setScaleY(h-artContainer.getBottom()+V.dp(90)); greenFill.setScaleY(h-artContainer.getBottom()+V.dp(90));
} }
@@ -101,15 +143,91 @@ public class SplashFragment extends AppKitFragment{
return true; return true;
} }
private class PagerAdapter extends RecyclerView.Adapter<PagerViewHolder>{
@NonNull
@Override @Override
protected void onShown(){ public PagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
super.onShown(); return new PagerViewHolder(viewType);
motionEffect.activate();
} }
@Override @Override
protected void onHidden(){ public void onBindViewHolder(@NonNull PagerViewHolder holder, int position){}
super.onHidden();
motionEffect.deactivate(); @Override
public int getItemCount(){
return 3;
}
@Override
public int getItemViewType(int position){
return position;
}
}
private class PagerViewHolder extends RecyclerView.ViewHolder{
public PagerViewHolder(int page){
super(new LinearLayout(getActivity()));
LinearLayout ll=(LinearLayout) itemView;
ll.setOrientation(LinearLayout.VERTICAL);
int pad=V.dp(16);
ll.setPadding(pad, pad, pad, pad);
ll.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
TextView title=new TextView(getActivity());
title.setTextAppearance(R.style.m3_headline_medium);
title.setText(switch(page){
case 0 -> {
String src=getString(R.string.welcome_page1_title);
SpannableString ss=new SpannableString(src);
int start=src.indexOf("{logo}");
if(start!=-1){
LogoSpan span=new LogoSpan(getResources().getDrawable(R.drawable.splash_logo, getActivity().getTheme()));
ss.setSpan(span, start, start+6, 0);
}
yield ss;
}
case 1 -> getString(R.string.welcome_page2_title);
case 2 -> getString(R.string.welcome_page3_title);
default -> throw new IllegalStateException("Unexpected value: "+page);
});
title.setTextColor(0xFF17063B);
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(page==0 ? 46 : 36));
lp.bottomMargin=V.dp(page==0 ? 4 : 14);
ll.addView(title, lp);
TextView text=new TextView(getActivity());
text.setTextAppearance(R.style.m3_body_medium);
text.setText(switch(page){
case 0 -> R.string.welcome_page1_text;
case 1 -> R.string.welcome_page2_text;
case 2 -> R.string.welcome_page3_text;
default -> throw new IllegalStateException("Unexpected value: "+page);
});
text.setTextColor(0xFF17063B);
ll.addView(text, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
private class LogoSpan extends ReplacementSpan{
private final Drawable drawable;
private LogoSpan(Drawable drawable){
this.drawable=drawable;
}
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm){
return drawable.getIntrinsicWidth();
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint){
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
canvas.save();
canvas.translate(x, y-V.dp(20));
drawable.draw(canvas);
canvas.restore();
}
} }
} }

View File

@@ -240,13 +240,17 @@ public class InstanceChooserLoginFragment extends InstanceCatalogFragment{
if(chosenInstance!=null){ if(chosenInstance!=null){
int idx=filteredData.indexOf(chosenInstance); int idx=filteredData.indexOf(chosenInstance);
if(idx!=-1){ if(idx!=-1){
boolean found=false;
for(int i=0;i<list.getChildCount();i++){ for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i)); RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder.getAbsoluteAdapterPosition()==mergeAdapter.getPositionForAdapter(adapter)+idx && holder instanceof InstanceViewHolder ivh){ if(holder.getAbsoluteAdapterPosition()==mergeAdapter.getPositionForAdapter(adapter)+idx && holder instanceof InstanceViewHolder ivh){
ivh.radioButton.setChecked(false); ivh.radioButton.setChecked(false);
found=true;
break; break;
} }
} }
if(!found)
adapter.notifyItemChanged(idx);
} }
} }
radioButton.setChecked(true); radioButton.setChecked(true);

View File

@@ -82,6 +82,8 @@ public class Instance extends BaseModel{
// non-standard field in some Mastodon forks // non-standard field in some Mastodon forks
public int maxTootChars; public int maxTootChars;
public V2 v2;
@Override @Override
public void postprocess() throws ObjectValidationException{ public void postprocess() throws ObjectValidationException{
super.postprocess(); super.postprocess();
@@ -176,4 +178,19 @@ public class Instance extends BaseModel{
public int minExpiration; public int minExpiration;
public int maxExpiration; public int maxExpiration;
} }
@Parcel
public static class V2 extends BaseModel {
public V2.Configuration configuration;
@Parcel
public static class Configuration {
public TranslationConfiguration translation;
}
@Parcel
public static class TranslationConfiguration{
public boolean enabled;
}
}
} }

View File

@@ -0,0 +1,7 @@
package org.joinmastodon.android.model;
public class TranslatedStatus extends BaseModel {
public String content;
public String detectedSourceLanguage;
public String provider;
}

View File

@@ -5,6 +5,7 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
@@ -60,7 +61,8 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<PollOptionStatusDisplayItem> implements ImageLoaderViewHolder{ public static class Holder extends StatusDisplayItem.Holder<PollOptionStatusDisplayItem> implements ImageLoaderViewHolder{
private final TextView text, percent; private final TextView text, percent;
private final View icon, button; private final View button;
private final ImageView icon;
private final Drawable progressBg; private final Drawable progressBg;
public Holder(Activity activity, ViewGroup parent){ public Holder(Activity activity, ViewGroup parent){
@@ -76,14 +78,17 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public void onBind(PollOptionStatusDisplayItem item){ public void onBind(PollOptionStatusDisplayItem item){
text.setText(item.text); text.setText(item.text);
// icon.setVisibility(item.showResults ? View.GONE : View.VISIBLE);
percent.setVisibility(item.showResults ? View.VISIBLE : View.GONE); percent.setVisibility(item.showResults ? View.VISIBLE : View.GONE);
itemView.setClickable(!item.showResults); itemView.setClickable(!item.showResults);
icon.setImageDrawable(itemView.getContext().getDrawable(item.poll.multiple ?
item.showResults ? R.drawable.ic_poll_checkbox_regular_selector : R.drawable.ic_poll_checkbox_filled_selector :
item.showResults ? R.drawable.ic_poll_option_button : R.drawable.ic_fluent_radio_button_24_selector
));
if(item.showResults){ if(item.showResults){
icon.setSelected(item.poll.ownVotes.contains(item.poll.options.indexOf(item.option)));
progressBg.setLevel(Math.round(10000f*item.votesFraction)); progressBg.setLevel(Math.round(10000f*item.votesFraction));
button.setBackground(progressBg); button.setBackground(progressBg);
itemView.setSelected(item.isMostVoted); itemView.setSelected(item.isMostVoted);
icon.setSelected(item.poll.ownVotes.contains(item.poll.options.indexOf(item.option)));
percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f))); percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f)));
}else{ }else{
itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option)); itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option));

View File

@@ -9,16 +9,25 @@ import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.TranslateStatus;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.drawables.SpoilerStripesDrawable; import org.joinmastodon.android.ui.drawables.SpoilerStripesDrawable;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.model.TranslatedStatus;
import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper; import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.views.LinkedTextView; import org.joinmastodon.android.ui.views.LinkedTextView;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.MovieDrawable; import me.grishka.appkit.imageloader.MovieDrawable;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
@@ -30,6 +39,12 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
private CharSequence parsedSpoilerText; private CharSequence parsedSpoilerText;
public boolean textSelectable; public boolean textSelectable;
public final Status status; public final Status status;
public boolean translated = false;
public TranslatedStatus translation = null;
private AccountSession session;
private Instance instanceInfo;
private boolean translateEnabled;
public TextStatusDisplayItem(String parentID, CharSequence text, BaseStatusListFragment parentFragment, Status status){ public TextStatusDisplayItem(String parentID, CharSequence text, BaseStatusListFragment parentFragment, Status status){
super(parentID, parentFragment); super(parentID, parentFragment);
@@ -41,6 +56,9 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
spoilerEmojiHelper=new CustomEmojiHelper(); spoilerEmojiHelper=new CustomEmojiHelper();
spoilerEmojiHelper.setText(parsedSpoilerText); spoilerEmojiHelper.setText(parsedSpoilerText);
} }
session = AccountSessionManager.getInstance().getAccount(parentFragment.getAccountID());
instanceInfo = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
translateEnabled = instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null && instanceInfo.v2.configuration.translation.enabled;
} }
@Override @Override
@@ -65,9 +83,10 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<TextStatusDisplayItem> implements ImageLoaderViewHolder{ public static class Holder extends StatusDisplayItem.Holder<TextStatusDisplayItem> implements ImageLoaderViewHolder{
private final LinkedTextView text; private final LinkedTextView text;
private final LinearLayout spoilerHeader; private final LinearLayout spoilerHeader;
private final TextView spoilerTitle, spoilerTitleInline; private final TextView spoilerTitle, spoilerTitleInline, translateInfo;
private final View spoilerOverlay, borderTop, borderBottom; private final View spoilerOverlay, borderTop, borderBottom, textWrap, translateWrap, translateProgress;
private final Drawable backgroundColor, borderColor; private final Drawable backgroundColor, borderColor;
private final Button translateButton;
public Holder(Activity activity, ViewGroup parent){ public Holder(Activity activity, ViewGroup parent){
super(activity, R.layout.display_item_text, parent); super(activity, R.layout.display_item_text, parent);
@@ -78,6 +97,11 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
spoilerOverlay=findViewById(R.id.spoiler_overlay); spoilerOverlay=findViewById(R.id.spoiler_overlay);
borderTop=findViewById(R.id.border_top); borderTop=findViewById(R.id.border_top);
borderBottom=findViewById(R.id.border_bottom); borderBottom=findViewById(R.id.border_bottom);
textWrap=findViewById(R.id.text_wrap);
translateWrap=findViewById(R.id.translate_wrap);
translateButton=findViewById(R.id.translate_btn);
translateInfo=findViewById(R.id.translate_info);
translateProgress=findViewById(R.id.translate_progress);
itemView.setOnClickListener(v->item.parentFragment.onRevealSpoilerClick(this)); itemView.setOnClickListener(v->item.parentFragment.onRevealSpoilerClick(this));
TypedValue outValue=new TypedValue(); TypedValue outValue=new TypedValue();
@@ -91,7 +115,9 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public void onBind(TextStatusDisplayItem item){ public void onBind(TextStatusDisplayItem item){
text.setText(item.text); text.setText(item.translated
? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
: item.text);
text.setTextIsSelectable(item.textSelectable); text.setTextIsSelectable(item.textSelectable);
spoilerTitleInline.setTextIsSelectable(item.textSelectable); spoilerTitleInline.setTextIsSelectable(item.textSelectable);
text.setInvalidateOnEveryFrame(false); text.setInvalidateOnEveryFrame(false);
@@ -105,20 +131,53 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
if(item.status.spoilerRevealed){ if(item.status.spoilerRevealed){
spoilerOverlay.setVisibility(View.GONE); spoilerOverlay.setVisibility(View.GONE);
spoilerHeader.setVisibility(View.VISIBLE); spoilerHeader.setVisibility(View.VISIBLE);
text.setVisibility(View.VISIBLE); textWrap.setVisibility(View.VISIBLE);
itemView.setClickable(false); itemView.setClickable(false);
}else{ }else{
spoilerOverlay.setVisibility(View.VISIBLE); spoilerOverlay.setVisibility(View.VISIBLE);
spoilerHeader.setVisibility(View.GONE); spoilerHeader.setVisibility(View.GONE);
text.setVisibility(View.GONE); textWrap.setVisibility(View.GONE);
itemView.setClickable(true); itemView.setClickable(true);
} }
}else{ }else{
spoilerOverlay.setVisibility(View.GONE); spoilerOverlay.setVisibility(View.GONE);
spoilerHeader.setVisibility(View.GONE); spoilerHeader.setVisibility(View.GONE);
text.setVisibility(View.VISIBLE); textWrap.setVisibility(View.VISIBLE);
itemView.setClickable(false); itemView.setClickable(false);
} }
translateWrap.setVisibility(item.textSelectable && item.translateEnabled &&
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
(item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage))
? View.VISIBLE : View.GONE);
translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post);
translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, item.translation.provider) : "");
translateButton.setOnClickListener(v->{
if (item.translation == null) {
translateProgress.setVisibility(View.VISIBLE);
translateButton.setClickable(false);
new TranslateStatus(item.status.id).setCallback(new Callback<>() {
@Override
public void onSuccess(TranslatedStatus translatedStatus) {
item.translation = translatedStatus;
item.translated = true;
translateProgress.setVisibility(View.GONE);
translateButton.setClickable(true);
rebind();
}
@Override
public void onError(ErrorResponse error) {
translateProgress.setVisibility(View.GONE);
translateButton.setClickable(true);
error.showToast(itemView.getContext());
}
}).exec(item.parentFragment.getAccountID());
} else {
item.translated = !item.translated;
rebind();
}
});
} }
@Override @Override

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorM3Primary" android:state_enabled="true"/>
<item android:color="?colorM3OnSurface" android:alpha="0.38"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorSecondary" android:state_enabled="true"/> <item android:color="@color/gray_50" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/> <item android:color="?colorTabInactive"/>
</selector> </selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorButtonText" android:state_enabled="true"/> <item android:color="@color/gray_800" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/> <item android:color="?colorTabInactive"/>
</selector> </selector>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorM3Primary" android:alpha="0.12"/>
</selector>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="@color/m3_primary_overlay" xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000"/>
<corners android:radius="20dp"/>
</shape>
</item>
</ripple>

View File

@@ -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="M12 7c0.414 0 0.75 0.336 0.75 0.75v3.5h3.5c0.414 0 0.75 0.336 0.75 0.75s-0.336 0.75-0.75 0.75h-3.5v3.5c0 0.414-0.336 0.75-0.75 0.75s-0.75-0.336-0.75-0.75v-3.5h-3.5C7.336 12.75 7 12.414 7 12s0.336-0.75 0.75-0.75h3.5v-3.5C11.25 7.336 11.586 7 12 7zM3 6.25C3 4.455 4.455 3 6.25 3h11.5C19.545 3 21 4.455 21 6.25v11.5c0 1.795-1.455 3.25-3.25 3.25H6.25C4.455 21 3 19.545 3 17.75V6.25zM6.25 4.5C5.284 4.5 4.5 5.284 4.5 6.25v11.5c0 0.966 0.784 1.75 1.75 1.75h11.5c0.966 0 1.75-0.784 1.75-1.75V6.25c0-0.966-0.784-1.75-1.75-1.75H6.25z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -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="M6.25 3C4.455 3 3 4.455 3 6.25v11.5C3 19.545 4.455 21 6.25 21h11.5c1.795 0 3.25-1.455 3.25-3.25V6.25C21 4.455 19.545 3 17.75 3H6.25zm11.03 6.28l-6.754 6.747c-0.293 0.292-0.767 0.292-1.06 0L6.72 13.28c-0.293-0.293-0.293-0.768 0-1.06 0.293-0.293 0.768-0.293 1.06 0l2.217 2.216 6.223-6.217c0.293-0.292 0.768-0.292 1.06 0.001 0.293 0.293 0.293 0.768 0 1.06z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -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="M6.25 3C4.455 3 3 4.455 3 6.25v11.5C3 19.545 4.455 21 6.25 21h11.5c1.795 0 3.25-1.455 3.25-3.25V6.25C21 4.455 19.545 3 17.75 3H6.25zM4.5 6.25c0-0.966 0.784-1.75 1.75-1.75h11.5c0.966 0 1.75 0.784 1.75 1.75v11.5c0 0.966-0.784 1.75-1.75 1.75H6.25c-0.966 0-1.75-0.784-1.75-1.75V6.25zm12.78 3.03c0.293-0.292 0.293-0.767 0-1.06-0.292-0.293-0.767-0.293-1.06 0l-6.223 6.216L7.78 12.22c-0.293-0.293-0.768-0.293-1.06 0-0.294 0.292-0.294 0.767 0 1.06l2.745 2.746c0.293 0.293 0.767 0.293 1.06 0l6.754-6.745z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -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 6.25C3 4.455 4.455 3 6.25 3h11.5C19.545 3 21 4.455 21 6.25v11.5c0 1.795-1.455 3.25-3.25 3.25H6.25C4.455 21 3 19.545 3 17.75V6.25zM6.25 5C5.56 5 5 5.56 5 6.25v11.5C5 18.44 5.56 19 6.25 19h11.5c0.69 0 1.25-0.56 1.25-1.25V6.25C19 5.56 18.44 5 17.75 5H6.25z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -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 6.25C3 4.455 4.455 3 6.25 3h11.5C19.545 3 21 4.455 21 6.25v11.5c0 1.795-1.455 3.25-3.25 3.25H6.25C4.455 21 3 19.545 3 17.75V6.25zM6.25 4.5C5.284 4.5 4.5 5.284 4.5 6.25v11.5c0 0.966 0.784 1.75 1.75 1.75h11.5c0.966 0 1.75-0.784 1.75-1.75V6.25c0-0.966-0.784-1.75-1.75-1.75H6.25z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -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="M12 1.999c5.524 0 10.002 4.478 10.002 10.002 0 5.523-4.478 10.001-10.002 10.001-5.524 0-10.002-4.478-10.002-10.001C1.998 6.477 6.476 1.999 12 1.999zm0 1.5c-4.695 0-8.502 3.806-8.502 8.502 0 4.695 3.807 8.501 8.502 8.501s8.502-3.806 8.502-8.501c0-4.696-3.807-8.502-8.502-8.502zm-0.003 2.5c3.312 0 5.998 2.686 5.998 5.998 0 3.313-2.686 5.998-5.998 5.998-3.313 0-5.999-2.685-5.999-5.998S8.684 6 11.997 6z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -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_radio_button_24_filled" android:state_activated="true"/>
<item android:drawable="@drawable/ic_fluent_radio_button_24_filled" android:state_checked="true"/>
<item android:drawable="@drawable/ic_fluent_radio_button_24_filled" android:state_selected="true"/>
<item android:drawable="@drawable/ic_fluent_radio_button_24_regular"/>
</selector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_fluent_checkbox_checked_24_filled" android:state_activated="true"/>
<item android:drawable="@drawable/ic_fluent_checkbox_checked_24_filled" android:state_checked="true"/>
<item android:drawable="@drawable/ic_fluent_checkbox_checked_24_filled" android:state_selected="true"/>
<item android:drawable="@drawable/ic_fluent_checkbox_unchecked_24_filled"/>
</selector>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_fluent_checkbox_checked_24_regular" android:state_activated="true"/>
<item android:drawable="@drawable/ic_fluent_checkbox_checked_24_regular" android:state_checked="true"/>
<item android:drawable="@drawable/ic_fluent_checkbox_checked_24_regular" android:state_selected="true"/>
<item android:drawable="@drawable/ic_fluent_checkbox_unchecked_24_regular"/>
</selector>

View File

@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:aapt="http://schemas.android.com/aapt"
android:width="257dp" android:width="134dp"
android:height="67dp" android:height="34dp"
android:viewportWidth="313" android:viewportWidth="313"
android:viewportHeight="81"> android:viewportHeight="81">
<path <path
@@ -20,8 +20,8 @@
</path> </path>
<path <path
android:pathData="M14.81,23.2C14.81,20.72 16.77,18.72 19.2,18.72C21.62,18.72 23.58,20.73 23.58,23.2C23.58,25.67 21.62,27.68 19.2,27.68C16.77,27.68 14.81,25.67 14.81,23.2Z" android:pathData="M14.81,23.2C14.81,20.72 16.77,18.72 19.2,18.72C21.62,18.72 23.58,20.73 23.58,23.2C23.58,25.67 21.62,27.68 19.2,27.68C16.77,27.68 14.81,25.67 14.81,23.2Z"
android:fillColor="#ffffff"/> android:fillColor="#000"/>
<path <path
android:pathData="M80.02,27.06V47.66H72.03V27.67C72.03,23.45 70.3,21.32 66.83,21.32C63,21.32 61.07,23.87 61.07,28.87V39.82H53.14V28.87C53.14,23.84 51.24,21.32 47.38,21.32C43.92,21.32 42.18,23.45 42.18,27.67V47.65H34.21V27.06C34.21,22.86 35.25,19.51 37.35,17.03C39.53,14.54 42.37,13.29 45.89,13.29C49.97,13.29 53.07,14.9 55.11,18.11L57.11,21.52L59.1,18.11C61.14,14.91 64.23,13.29 68.32,13.29C71.84,13.29 74.69,14.55 76.86,17.03C78.96,19.51 80.01,22.83 80.01,27.06H80.02ZM107.49,37.3C109.15,35.51 109.93,33.29 109.93,30.59C109.93,27.89 109.14,25.65 107.49,23.94C105.91,22.15 103.89,21.3 101.45,21.3C99.02,21.3 97.01,22.15 95.41,23.94C93.83,25.65 93.04,27.89 93.04,30.59C93.04,33.29 93.83,35.53 95.41,37.3C97,39 99.02,39.87 101.45,39.87C103.89,39.87 105.9,39.02 107.49,37.3ZM109.93,14.12H117.8V47.06H109.93V43.18C107.55,46.41 104.26,48 99.99,48C95.71,48 92.42,46.36 89.5,43C86.64,39.64 85.18,35.48 85.18,30.61C85.18,25.74 86.65,21.65 89.5,18.29C92.43,14.93 95.92,13.23 99.99,13.23C104.06,13.23 107.55,14.81 109.93,18.02V14.14V14.12ZM144.26,29.97C146.58,31.76 147.73,34.25 147.67,37.41C147.67,40.77 146.52,43.41 144.14,45.24C141.76,47.03 138.89,47.94 135.41,47.94C129.13,47.94 124.87,45.3 122.61,40.11L129.43,35.96C130.34,38.78 132.35,40.25 135.41,40.25C138.22,40.25 139.62,39.33 139.62,37.42C139.62,36.03 137.79,34.78 134.07,33.8C132.66,33.41 131.5,33.01 130.6,32.68C129.31,32.16 128.22,31.56 127.31,30.83C125.05,29.04 123.9,26.68 123.9,23.65C123.9,20.42 124.99,17.85 127.19,16C129.45,14.09 132.19,13.18 135.48,13.18C140.73,13.18 144.56,15.48 147.07,20.16L140.37,24.1C139.4,21.86 137.74,20.74 135.48,20.74C133.11,20.74 131.95,21.65 131.95,23.44C131.95,24.83 133.78,26.08 137.5,27.06C140.37,27.72 142.63,28.7 144.26,29.97H144.27H144.26ZM169.26,22.27H162.37V35.98C162.37,37.63 162.98,38.63 164.15,39.08C165,39.4 166.71,39.47 169.27,39.34V47.05C163.98,47.71 160.14,47.17 157.88,45.41C155.62,43.7 154.53,40.53 154.53,36V22.27H149.23V14.1H154.53V7.46L162.39,4.89V14.12H169.29V22.29H169.27L169.26,22.27ZM194.34,37.1C195.92,35.4 196.71,33.22 196.71,30.58C196.71,27.94 195.92,25.78 194.34,24.05C192.74,22.35 190.79,21.48 188.42,21.48C186.04,21.48 184.09,22.33 182.49,24.05C180.97,25.84 180.18,28 180.18,30.58C180.18,33.16 180.97,35.31 182.49,37.1C184.08,38.81 186.04,39.67 188.42,39.67C190.79,39.67 192.74,38.82 194.34,37.1ZM176.96,42.96C173.85,39.6 172.32,35.52 172.32,30.58C172.32,25.63 173.85,21.62 176.96,18.26C180.07,14.9 183.91,13.19 188.42,13.19C192.92,13.19 196.77,14.9 199.87,18.26C202.97,21.62 204.57,25.77 204.57,30.58C204.57,35.39 202.97,39.6 199.87,42.96C196.76,46.32 192.98,47.96 188.42,47.96C183.85,47.96 180.06,46.32 176.96,42.96ZM230.86,37.29C232.45,35.5 233.24,33.28 233.24,30.58C233.24,27.87 232.45,25.63 230.86,23.93C229.28,22.14 227.26,21.29 224.82,21.29C222.39,21.29 220.37,22.14 218.73,23.93C217.14,25.63 216.35,27.87 216.35,30.58C216.35,33.28 217.14,35.52 218.73,37.29C220.38,38.99 222.45,39.86 224.82,39.86C227.2,39.86 229.27,39 230.86,37.29ZM233.24,0.92H241.11V47.05H233.24V43.17C230.93,46.39 227.63,47.99 223.36,47.99C219.09,47.99 215.75,46.35 212.8,42.98C209.93,39.62 208.48,35.47 208.48,30.6C208.48,25.73 209.95,21.64 212.8,18.28C215.72,14.92 219.26,13.22 223.36,13.22C227.45,13.22 230.93,14.8 233.24,18.01V0.93V0.92ZM268.74,37.07C270.32,35.36 271.12,33.18 271.12,30.54C271.12,27.9 270.32,25.74 268.74,24.01C267.15,22.31 265.21,21.45 262.82,21.45C260.43,21.45 258.5,22.3 256.9,24.01C255.37,25.8 254.58,27.96 254.58,30.54C254.58,33.12 255.37,35.28 256.9,37.07C258.48,38.77 260.44,39.64 262.82,39.64C265.2,39.64 267.14,38.78 268.74,37.07ZM251.36,42.92C248.26,39.56 246.73,35.48 246.73,30.54C246.73,25.6 248.25,21.58 251.36,18.22C254.47,14.86 258.32,13.15 262.82,13.15C267.32,13.15 271.18,14.86 274.27,18.22C277.38,21.58 278.97,25.73 278.97,30.54C278.97,35.35 277.38,39.56 274.27,42.92C271.16,46.28 267.38,47.93 262.82,47.93C258.26,47.93 254.46,46.28 251.36,42.92ZM313,26.78V47.01H305.14V27.84C305.14,25.66 304.59,24.01 303.48,22.77C302.45,21.65 300.98,21.07 299.09,21.07C294.65,21.07 292.39,23.77 292.39,29.24V47.03H284.53V14.1H292.39V17.81C294.28,14.71 297.28,13.19 301.47,13.19C304.82,13.19 307.57,14.37 309.71,16.81C311.91,19.24 313,22.54 313,26.82" android:pathData="M80.02,27.06V47.66H72.03V27.67C72.03,23.45 70.3,21.32 66.83,21.32C63,21.32 61.07,23.87 61.07,28.87V39.82H53.14V28.87C53.14,23.84 51.24,21.32 47.38,21.32C43.92,21.32 42.18,23.45 42.18,27.67V47.65H34.21V27.06C34.21,22.86 35.25,19.51 37.35,17.03C39.53,14.54 42.37,13.29 45.89,13.29C49.97,13.29 53.07,14.9 55.11,18.11L57.11,21.52L59.1,18.11C61.14,14.91 64.23,13.29 68.32,13.29C71.84,13.29 74.69,14.55 76.86,17.03C78.96,19.51 80.01,22.83 80.01,27.06H80.02ZM107.49,37.3C109.15,35.51 109.93,33.29 109.93,30.59C109.93,27.89 109.14,25.65 107.49,23.94C105.91,22.15 103.89,21.3 101.45,21.3C99.02,21.3 97.01,22.15 95.41,23.94C93.83,25.65 93.04,27.89 93.04,30.59C93.04,33.29 93.83,35.53 95.41,37.3C97,39 99.02,39.87 101.45,39.87C103.89,39.87 105.9,39.02 107.49,37.3ZM109.93,14.12H117.8V47.06H109.93V43.18C107.55,46.41 104.26,48 99.99,48C95.71,48 92.42,46.36 89.5,43C86.64,39.64 85.18,35.48 85.18,30.61C85.18,25.74 86.65,21.65 89.5,18.29C92.43,14.93 95.92,13.23 99.99,13.23C104.06,13.23 107.55,14.81 109.93,18.02V14.14V14.12ZM144.26,29.97C146.58,31.76 147.73,34.25 147.67,37.41C147.67,40.77 146.52,43.41 144.14,45.24C141.76,47.03 138.89,47.94 135.41,47.94C129.13,47.94 124.87,45.3 122.61,40.11L129.43,35.96C130.34,38.78 132.35,40.25 135.41,40.25C138.22,40.25 139.62,39.33 139.62,37.42C139.62,36.03 137.79,34.78 134.07,33.8C132.66,33.41 131.5,33.01 130.6,32.68C129.31,32.16 128.22,31.56 127.31,30.83C125.05,29.04 123.9,26.68 123.9,23.65C123.9,20.42 124.99,17.85 127.19,16C129.45,14.09 132.19,13.18 135.48,13.18C140.73,13.18 144.56,15.48 147.07,20.16L140.37,24.1C139.4,21.86 137.74,20.74 135.48,20.74C133.11,20.74 131.95,21.65 131.95,23.44C131.95,24.83 133.78,26.08 137.5,27.06C140.37,27.72 142.63,28.7 144.26,29.97H144.27H144.26ZM169.26,22.27H162.37V35.98C162.37,37.63 162.98,38.63 164.15,39.08C165,39.4 166.71,39.47 169.27,39.34V47.05C163.98,47.71 160.14,47.17 157.88,45.41C155.62,43.7 154.53,40.53 154.53,36V22.27H149.23V14.1H154.53V7.46L162.39,4.89V14.12H169.29V22.29H169.27L169.26,22.27ZM194.34,37.1C195.92,35.4 196.71,33.22 196.71,30.58C196.71,27.94 195.92,25.78 194.34,24.05C192.74,22.35 190.79,21.48 188.42,21.48C186.04,21.48 184.09,22.33 182.49,24.05C180.97,25.84 180.18,28 180.18,30.58C180.18,33.16 180.97,35.31 182.49,37.1C184.08,38.81 186.04,39.67 188.42,39.67C190.79,39.67 192.74,38.82 194.34,37.1ZM176.96,42.96C173.85,39.6 172.32,35.52 172.32,30.58C172.32,25.63 173.85,21.62 176.96,18.26C180.07,14.9 183.91,13.19 188.42,13.19C192.92,13.19 196.77,14.9 199.87,18.26C202.97,21.62 204.57,25.77 204.57,30.58C204.57,35.39 202.97,39.6 199.87,42.96C196.76,46.32 192.98,47.96 188.42,47.96C183.85,47.96 180.06,46.32 176.96,42.96ZM230.86,37.29C232.45,35.5 233.24,33.28 233.24,30.58C233.24,27.87 232.45,25.63 230.86,23.93C229.28,22.14 227.26,21.29 224.82,21.29C222.39,21.29 220.37,22.14 218.73,23.93C217.14,25.63 216.35,27.87 216.35,30.58C216.35,33.28 217.14,35.52 218.73,37.29C220.38,38.99 222.45,39.86 224.82,39.86C227.2,39.86 229.27,39 230.86,37.29ZM233.24,0.92H241.11V47.05H233.24V43.17C230.93,46.39 227.63,47.99 223.36,47.99C219.09,47.99 215.75,46.35 212.8,42.98C209.93,39.62 208.48,35.47 208.48,30.6C208.48,25.73 209.95,21.64 212.8,18.28C215.72,14.92 219.26,13.22 223.36,13.22C227.45,13.22 230.93,14.8 233.24,18.01V0.93V0.92ZM268.74,37.07C270.32,35.36 271.12,33.18 271.12,30.54C271.12,27.9 270.32,25.74 268.74,24.01C267.15,22.31 265.21,21.45 262.82,21.45C260.43,21.45 258.5,22.3 256.9,24.01C255.37,25.8 254.58,27.96 254.58,30.54C254.58,33.12 255.37,35.28 256.9,37.07C258.48,38.77 260.44,39.64 262.82,39.64C265.2,39.64 267.14,38.78 268.74,37.07ZM251.36,42.92C248.26,39.56 246.73,35.48 246.73,30.54C246.73,25.6 248.25,21.58 251.36,18.22C254.47,14.86 258.32,13.15 262.82,13.15C267.32,13.15 271.18,14.86 274.27,18.22C277.38,21.58 278.97,25.73 278.97,30.54C278.97,35.35 277.38,39.56 274.27,42.92C271.16,46.28 267.38,47.93 262.82,47.93C258.26,47.93 254.46,46.28 251.36,42.92ZM313,26.78V47.01H305.14V27.84C305.14,25.66 304.59,24.01 303.48,22.77C302.45,21.65 300.98,21.07 299.09,21.07C294.65,21.07 292.39,23.77 292.39,29.24V47.03H284.53V14.1H292.39V17.81C294.28,14.71 297.28,13.19 301.47,13.19C304.82,13.19 307.57,14.37 309.71,16.81C311.91,19.24 313,22.54 313,26.82"
android:fillColor="#ffffff"/> android:fillColor="#000"/>
</vector> </vector>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#fff"/>
</shape>

View File

@@ -15,6 +15,7 @@
android:outlineProvider="background" android:outlineProvider="background"
android:elevation="2dp"> android:elevation="2dp">
<ImageView <ImageView
android:id="@+id/icon"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_margin="16dp" android:layout_margin="16dp"

View File

@@ -26,7 +26,6 @@
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:duplicateParentState="true"
android:tint="?colorDarkIcon" android:tint="?colorDarkIcon"
android:src="@drawable/ic_poll_option_button"/> android:src="@drawable/ic_poll_option_button"/>

View File

@@ -7,6 +7,7 @@
android:paddingBottom="12dp"> android:paddingBottom="12dp">
<LinearLayout <LinearLayout
android:id="@+id/text_wrap"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@@ -47,10 +48,57 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingHorizontal="16dp" android:paddingHorizontal="16dp"
android:textSize="16sp" android:textSize="16sp"
android:textAppearance="@style/m3_body_large" android:textAppearance="@style/m3_body_large"/>
tools:text="setting up my mstdn"/>
</LinearLayout>
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout
android:id="@+id/translate_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical">
<FrameLayout
android:id="@+id/action_btn_wrap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:clipToPadding="false">
<org.joinmastodon.android.ui.views.ProgressBarButton
android:id="@+id/translate_btn"
style="?secondaryButtonStyle"
android:background="?android:selectableItemBackground"
android:textColor="?android:textColorSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="8dp"
tools:text="@string/translate_post"/>
<ProgressBar
android:id="@+id/translate_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
style="?android:progressBarStyleSmall"
android:elevation="10dp"
android:outlineProvider="none"
android:indeterminateTint="?android:textColorPrimary"
android:visibility="gone"/>
</FrameLayout>
<TextView
android:id="@+id/translate_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:textColor="?android:textColorSecondary"
android:textAlignment="textEnd"
tools:text="Translated using TranslateEngine" />
</org.joinmastodon.android.ui.views.AutoOrientationLinearLayout>
</LinearLayout>
<LinearLayout <LinearLayout
android:visibility="gone" android:visibility="gone"

View File

@@ -132,6 +132,7 @@
android:outlineProvider="background" android:outlineProvider="background"
android:elevation="2dp"> android:elevation="2dp">
<ImageView <ImageView
android:id="@+id/add_poll_option_icon"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_margin="16dp" android:layout_margin="16dp"
@@ -148,6 +149,39 @@
android:textAppearance="@style/m3_label_large" android:textAppearance="@style/m3_label_large"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
tools:text="Duration: 7 days"/> tools:text="Duration: 7 days"/>
<LinearLayout
android:id="@+id/poll_allow_multiple"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
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">
<CheckBox
android:id="@+id/poll_allow_multiple_checkbox"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_marginEnd="24dp"
android:duplicateParentState="true"
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/sk_poll_allow_multiple" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<org.joinmastodon.android.ui.views.ComposeMediaLayout <org.joinmastodon.android.ui.views.ComposeMediaLayout
@@ -162,6 +196,7 @@
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layoutDirection="locale" android:layoutDirection="locale"

View File

@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.SizeListenerFrameLayout <org.joinmastodon.android.ui.views.SizeListenerFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:clipToPadding="false" android:clipToPadding="false">
android:clipChildren="false">
<View <View
android:id="@+id/blue_fill" android:id="@+id/blue_fill"
@@ -18,51 +17,60 @@
<FrameLayout <FrameLayout
android:id="@+id/art_container" android:id="@+id/art_container"
android:layout_width="450dp" android:layout_width="360dp"
android:layout_height="631dp" android:layout_height="640dp"
android:layout_marginTop="40dp" android:layout_gravity="center"
android:layout_gravity="center"> tools:ignore="rtlHardcoded">
<ImageView <ImageView
android:id="@+id/art_clouds" android:id="@+id/art_clouds"
android:layout_width="450dp" android:layout_width="414dp"
android:layout_height="589dp" android:layout_height="541dp"
android:layout_gravity="bottom|center_horizontal" android:layout_marginTop="91dp"
android:layout_gravity="top|left"
android:alpha="0.3"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer0"/> android:src="@drawable/splash_art_layer0"/>
<ImageView
android:id="@+id/art_plane_elephant"
android:layout_width="245.64dp"
android:layout_height="72.65dp"
android:layout_marginLeft="-101.55dp"
android:layout_marginTop="238.12dp"
android:layout_gravity="left|top"
android:alpha="0.3"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer4"/>
<ImageView <ImageView
android:id="@+id/art_right_hill" android:id="@+id/art_right_hill"
android:layout_width="218dp" android:layout_width="150.84dp"
android:layout_height="255dp" android:layout_height="176.44dp"
android:layout_gravity="bottom|right" android:layout_gravity="top|left"
android:layout_marginBottom="156dp" android:layout_marginLeft="322dp"
android:layout_marginRight="11dp" android:layout_marginTop="310dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer1"/> android:src="@drawable/splash_art_layer1"/>
<ImageView <ImageView
android:id="@+id/art_left_hill" android:id="@+id/art_left_hill"
android:layout_width="285dp" android:layout_width="197.2dp"
android:layout_height="222dp" android:layout_height="153.61dp"
android:layout_gravity="bottom|left" android:layout_gravity="top|left"
android:layout_marginLeft="-6dp" android:layout_marginTop="294dp"
android:layout_marginBottom="243dp" android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer2"/> android:src="@drawable/splash_art_layer2"/>
<ImageView <ImageView
android:id="@+id/art_center_hill" android:id="@+id/art_center_hill"
android:layout_width="457dp" android:layout_width="400dp"
android:layout_height="397dp" android:layout_height="346dp"
android:layout_gravity="bottom|center_horizontal" android:layout_gravity="top|left"
android:layout_marginBottom="51dp" android:layout_marginTop="294dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer3"/> android:src="@drawable/splash_art_layer3"/>
<ImageView
android:id="@+id/art_plane_elephant"
android:layout_width="355dp"
android:layout_height="105dp"
android:layout_gravity="left|top"
android:src="@drawable/splash_art_layer4"/>
</FrameLayout> </FrameLayout>
<View <View
@@ -73,36 +81,65 @@
android:transformPivotY="1px" android:transformPivotY="1px"
android:background="#478E6A"/> android:background="#478E6A"/>
<org.joinmastodon.android.ui.views.SplashLogoView
android:layout_width="261dp"
android:layout_height="71dp"
android:layout_gravity="center_horizontal|top"
android:layout_marginTop="24dp"
android:scaleType="center"
android:importantForAccessibility="no"
android:src="@drawable/splash_logo"/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_gravity="bottom"
android:padding="16dp"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical"> android:orientation="vertical">
<Button
android:id="@+id/btn_get_started" <androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/pager_dots"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="13dp" android:layout_gravity="center_horizontal"
style="@style/Widget.Mastodon.Button.Large.Primary_LightOnDark" android:layout_marginBottom="16dp"
android:text="@string/get_started"/> android:orientation="horizontal">
<View
android:layout_width="8dp"
android:layout_height="8dp"
android:background="@drawable/white_circle"/>
<View
android:layout_width="8dp"
android:layout_height="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:alpha="0.3"
android:background="@drawable/white_circle"/>
<View
android:layout_width="8dp"
android:layout_height="8dp"
android:alpha="0.3"
android:background="@drawable/white_circle"/>
</LinearLayout>
<Button <Button
android:id="@+id/btn_log_in" android:id="@+id/btn_log_in"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/Widget.Mastodon.Button.Large.Primary_DarkOnLight" android:layout_marginLeft="16dp"
android:background="@drawable/bg_button_green" android:layout_marginRight="16dp"
android:text="@string/log_in"/> style="@style/Widget.Mastodon.M3.Button.Text"
android:textColor="#fff"
android:text="@string/already_have_account"/>
<Button
android:id="@+id/btn_get_started"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/get_started"/>
</LinearLayout> </LinearLayout>
</org.joinmastodon.android.ui.views.SizeListenerFrameLayout> </org.joinmastodon.android.ui.views.SizeListenerFrameLayout>

View File

@@ -47,4 +47,5 @@
<string name="sk_color_theme_yellow">Gelb</string> <string name="sk_color_theme_yellow">Gelb</string>
<string name="sk_notification_type_status">Beiträge</string> <string name="sk_notification_type_status">Beiträge</string>
<string name="sk_color_theme_blue">Blau</string> <string name="sk_color_theme_blue">Blau</string>
<string name="sk_poll_allow_multiple">Mehrfachantworten erlauben</string>
</resources> </resources>

View File

@@ -2,7 +2,8 @@
<resources> <resources>
<string name="app_name" translatable="false">Mastodon</string> <string name="app_name" translatable="false">Mastodon</string>
<string name="get_started">Get started</string> <string name="get_started">Create account</string>
<string name="already_have_account">I already have an account</string>
<string name="log_in">Log in</string> <string name="log_in">Log in</string>
<string name="next">Next</string> <string name="next">Next</string>
<string name="loading_instance">Retrieving server info…</string> <string name="loading_instance">Retrieving server info…</string>
@@ -397,4 +398,11 @@
<string name="login_title">Welcome Back</string> <string name="login_title">Welcome Back</string>
<string name="login_subtitle">Log in with the server where you created your account.</string> <string name="login_subtitle">Log in with the server where you created your account.</string>
<string name="server_url">Server URL</string> <string name="server_url">Server URL</string>
<!-- {logo} is a placeholder that is replaced with the Mastodon logo image at runtime. Please copy it into your translation as is. -->
<string name="welcome_page1_title">What is {logo}?</string>
<string name="welcome_page1_text">Imagine you have an email address that ends with @example.com.\n\nYou can still send and receive emails from anyone, even if their email ends in @gmail.com or @icloud.com or @example.com.</string>
<string name="welcome_page2_title">Mastodon is like that.</string>
<string name="welcome_page2_text">Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online.</string>
<string name="welcome_page3_title">How do I pick a server?</string>
<string name="welcome_page3_text">Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots.\n\nYou cant go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), youll never miss a beat anywhere.</string>
</resources> </resources>

View File

@@ -47,4 +47,12 @@
<string name="sk_color_theme_blue">Blue</string> <string name="sk_color_theme_blue">Blue</string>
<string name="sk_color_theme_brown">Brown</string> <string name="sk_color_theme_brown">Brown</string>
<string name="sk_color_theme_yellow">Yellow</string> <string name="sk_color_theme_yellow">Yellow</string>
<string name="sk_poll_allow_multiple">Allow multiple choices</string>
<string name="sk_translate_post">Translate</string>
<string name="sk_translate_show_original">Show original</string>
<string name="sk_translated_using">Translated using %s</string>
<string name="sk_post_language">Language: %s</string>
<string name="sk_all_languages">All languages</string>
<string name="sk_clear_recent_languages">Clear recent languages</string>
<string name="sk_confirm_clear_recent_languages">Are you sure you want to clear your recently used languages?</string>
</resources> </resources>

View File

@@ -753,6 +753,13 @@
<item name="android:paddingRight">24dp</item> <item name="android:paddingRight">24dp</item>
</style> </style>
<style name="Widget.Mastodon.M3.Button.Text">
<item name="android:background">@drawable/bg_button_m3_text</item>
<item name="android:textColor">@color/button_text_m3_text</item>
<item name="android:paddingLeft">24dp</item>
<item name="android:paddingRight">24dp</item>
</style>
<style name="alert_title"> <style name="alert_title">
<item name="android:textColor">?android:textColorPrimary</item> <item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">24dp</item> <item name="android:textSize">24dp</item>

View File

@@ -1,4 +1,5 @@
- Eigene Farbschemata von @LucasGGamerM - Eigene Farbschemata von @LucasGGamerM
- Neuer "megalodon" Logo-Schriftzug von @LucasGGamerM
- Bessere Emoji-Suche beim Verfassen - Bessere Emoji-Suche beim Verfassen
- Verbesserungen bei Abstimmungen (eigene Stimme wird angezeigt, Abstimmen-Button wird immer angezeigt, lange Antworten werden nicht abgeschnitten) - Verbesserungen bei Abstimmungen (eigene Stimme wird angezeigt, Abstimmen-Button wird immer angezeigt, lange Antworten werden nicht abgeschnitten)
- Push-Notification-Einstellung für Beitrags-Benachrichtigungen - Push-Notification-Einstellung für Beitrags-Benachrichtigungen

View File

@@ -1,4 +1,4 @@
Megalodon ist eine modifizierte Version der <a href="https://github.com/mastodon/mastodon-android">offiziellen Mastodon-Android-App</a> mit vielen Features, die in der offiziellen App fehlen, z.B. die föderierte Timeline, ungelistete Beiträge posten, Lesezeichen und die Möglichkeit, Bildbeschreibungen anzuzeigen. Megalodon ist eine modifizierte Version der <a href="https://github.com/mastodon/mastodon-android">offiziellen Mastodon-Android-App</a> mit vielen Features, die in der offiziellen App fehlen, z.B. die föderierte Timeline, ungelistete Beiträge posten und die Möglichkeit, Bildbeschreibungen anzuzeigen.
<b>Die wichtigsten Features</b> <b>Die wichtigsten Features</b>
@@ -6,12 +6,6 @@ Megalodon ist eine modifizierte Version der <a href="https://github.com/mastodon
- <b>Föderierte Timeline</b>: Alle öffentlichen Beiträge aller anderen Fediverse-Nachbarschaften, mit denen deine Heim-Instanz verbunden ist. - <b>Föderierte Timeline</b>: Alle öffentlichen Beiträge aller anderen Fediverse-Nachbarschaften, mit denen deine Heim-Instanz verbunden ist.
- <b>Bildbeschreibungen anzeigen</b>: Unkompliziert prüfen, ob Bilder und Videos Alternativ-Texte beinhalten. - <b>Bildbeschreibungen anzeigen</b>: Unkompliziert prüfen, ob Bilder und Videos Alternativ-Texte beinhalten.
- <b>Beiträge anpinnen</b>: Pinne deine wichtigsten Beiträge an dein Profil an und sieh im “Angepinnt”-Tab nach, was andere User_innen angepinnt haben. - <b>Beiträge anpinnen</b>: Pinne deine wichtigsten Beiträge an dein Profil an und sieh im “Angepinnt”-Tab nach, was andere User_innen angepinnt haben.
- <b>Lesezeichen</b>: Schnell und einfach Beiträge speichern und später in der Lesezeichen-Liste wieder finden.
- <b>Hashtags folgen</b>: Bringt neue Beiträge bestimmter Hashtags direkt in deine Home-Timeline. - <b>Hashtags folgen</b>: Bringt neue Beiträge bestimmter Hashtags direkt in deine Home-Timeline.
- <b>Folgeanfragen beantworten</b>: Folgeanfragen lassen sich nun direkt über die Benachrichtigungen-Liste oder über die Folgeanfragen-Liste akzeptieren oder ablehnen. - <b>Folgeanfragen beantworten</b>: Folgeanfragen lassen sich nun direkt über die Benachrichtigungen-Liste oder über die Folgeanfragen-Liste akzeptieren oder ablehnen.
- <b>Beiträge löschen und neu erstellen</b>: Das beliebte Feature, das das Bearbeiten von Beiträgen ohne tatsächliche Bearbeit-Funktion möglich gemacht hat. - <b>Beiträge löschen und neu erstellen</b>: Das beliebte Feature, das das Bearbeiten von Beiträgen ohne tatsächliche Bearbeit-Funktion möglich gemacht hat.
<b>Aus der offiziellen App vorab verfügbar</b>
- Beiträge bearbeiten
- Integrierter Updater für GitHub-Releases

View File

@@ -1,4 +1,5 @@
- Custom color themes by @LucasGGamerM - Custom color themes by @LucasGGamerM
- New "megalodon" text logo submitted by @LucasGGamerM
- Better emoji search while composing - Better emoji search while composing
- Tweaked voting (display own vote, always display vote button, don't cut off long answers) - Tweaked voting (display own vote, always display vote button, don't cut off long answers)
- Add push notification setting for post notifications - Add push notification setting for post notifications

View File

@@ -0,0 +1,5 @@
- Add language selector
- Add translate function
- Improve semantics for voting on polls (radio buttons and checkboxes)
- Add option to allow voting for multiple options on polls
- Bugfixes

View File

@@ -1,4 +1,4 @@
Megalodon is a modified version of the <a href="https://github.com/mastodon/mastodon-android">official Mastodon Android app</a> adding important features that are missing in the official app, such as the federated timeline, unlisted posting, bookmarks and an image description viewer. Megalodon is a modified version of the <a href="https://github.com/mastodon/mastodon-android">official Mastodon Android app</a> adding important features that are missing in the official app, such as the federated timeline, unlisted posting and an image description viewer.
<b>Key features</b> <b>Key features</b>
@@ -6,12 +6,6 @@ Megalodon is a modified version of the <a href="https://github.com/mastodon/mast
- <b>Federated timeline</b>: See all public posts from people on all other Fediverse neighborhoods your home instance is connected to. - <b>Federated timeline</b>: See all public posts from people on all other Fediverse neighborhoods your home instance is connected to.
- <b>Image description viewer</b>: Quickly check whether an image or video has an alt text attached to it. - <b>Image description viewer</b>: Quickly check whether an image or video has an alt text attached to it.
- <b>Pinning posts</b>: Pin your most important posts to your profile and see what others have pinned using the “Pinned“ tab. - <b>Pinning posts</b>: Pin your most important posts to your profile and see what others have pinned using the “Pinned“ tab.
- <b>Bookmarks</b>: Quickly save posts and find them later in the Bookmarks list.
- <b>Follow hashtags</b>: See new posts from specific hashtags directly in your home timeline by following them. - <b>Follow hashtags</b>: See new posts from specific hashtags directly in your home timeline by following them.
- <b>Answering follow requests</b>: Accept or decline follow requests from your notifications or the dedicated Follow requests list. - <b>Answering follow requests</b>: Accept or decline follow requests from your notifications or the dedicated Follow requests list.
- <b>Delete and re-draft</b>: The much-loved feature that made editing possible without an actual editing function. - <b>Delete and re-draft</b>: The much-loved feature that made editing possible without an actual editing function.
<b>Unreleased official features, available in advance</b>
- Editing posts
- Integrated updater for GitHub releases