Merge branch 'feature/language-selector' into fork

# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
#	mastodon/src/main/res/values/strings.xml
This commit is contained in:
LucasGGamerM
2022-12-14 19:03:15 -03:00
12 changed files with 465 additions and 75 deletions

View File

@@ -1,8 +1,18 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GlobalUserPreferences{
public static boolean playGifs;
public static boolean useCustomTabs;
@@ -18,10 +28,18 @@ public class GlobalUserPreferences{
public static ThemePreference theme;
public static ColorPreference color;
private final static Type recentLanguagesType = new TypeToken<Map<String, List<String>>>() {}.getType();
public static Map<String, List<String>> recentLanguages;
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
}
private static <T> T fromJson(String json, Type type, T orElse) {
try { return gson.fromJson(json, type); }
catch (JsonSyntaxException ignored) { return orElse; }
}
public static void load(){
SharedPreferences prefs=getPrefs();
playGifs=prefs.getBoolean("playGifs", true);
@@ -36,6 +54,7 @@ public class GlobalUserPreferences{
disableMarquee=prefs.getBoolean("disableMarquee", false);
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
color=ColorPreference.values()[prefs.getInt("color", 1)];
}
@@ -52,6 +71,7 @@ public class GlobalUserPreferences{
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
.putBoolean("disableMarquee", disableMarquee)
.putInt("theme", theme.ordinal())
.putString("recentLanguages", gson.toJson(recentLanguages))
.putInt("color", color.ordinal())
.apply();
}

View File

@@ -1,5 +1,9 @@
package org.joinmastodon.android.fragments;
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.defaultRecentLanguages;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -29,11 +33,13 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
@@ -55,6 +61,7 @@ import android.widget.Toast;
import com.twitter.twittertext.TwitterTextEmojiRegex;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
@@ -95,6 +102,7 @@ import org.joinmastodon.android.ui.views.ComposeEditText;
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
import org.joinmastodon.android.utils.MastodonLanguage;
import org.parceler.Parcel;
import org.parceler.Parcels;
@@ -105,6 +113,7 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -145,7 +154,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private String accountID;
private int charCount, charLimit, trimmedCharCount;
private Button publishButton;
private Button publishButton, languageButton;
private PopupMenu languagePopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
private ImageView sensitiveIcon;
private ComposeMediaLayout attachmentsView;
@@ -190,6 +200,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private boolean ignoreSelectionChanges=false;
private Runnable updateUploadEtaRunnable;
private String language;
private MastodonLanguage.LanguageResolver languageResolver;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -201,6 +214,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
instanceDomain=session.domain;
customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain);
instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain);
languageResolver=new MastodonLanguage.LanguageResolver(instance);
if(getArguments().containsKey("editStatus")){
editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus"));
redraftStatus=getArguments().getBoolean("redraftStatus");
@@ -403,6 +417,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
outState.putBoolean("sensitive", sensitive);
outState.putBoolean("hasSpoiler", hasSpoiler);
outState.putString("language", language);
if(!attachments.isEmpty()){
ArrayList<Parcelable> serializedAttachments=new ArrayList<>(attachments.size());
for(DraftMediaAttachment att:attachments){
@@ -542,6 +557,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
spoilerEdit.setText(replyTo.spoilerText);
spoilerBtn.setSelected(true);
}
if (replyTo.language != null && !replyTo.language.isEmpty()) updateLanguage(replyTo.language);
}
}else{
replyText.setVisibility(View.GONE);
@@ -553,6 +569,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
ignoreSelectionChanges=true;
mainEditText.setSelection(mainEditText.length());
ignoreSelectionChanges=false;
updateLanguage(editingStatus.language);
if(!editingStatus.mediaAttachments.isEmpty()){
attachmentsView.setVisibility(View.VISIBLE);
for(Attachment att:editingStatus.mediaAttachments){
@@ -615,6 +632,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
sendError.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.setPadding(V.dp(16), V.dp(4), V.dp(16), V.dp(8));
wrap.setClipToPadding(false);
@@ -624,6 +645,55 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
updatePublishButtonState();
}
private void updateLanguage(String lang) {
updateLanguage(languageResolver.from(lang));
}
private void updateLanguage(MastodonLanguage loc) {
language = loc.getLanguage();
languageButton.setText(loc.getLanguageName());
languageButton.setContentDescription(getActivity().getString(R.string.post_language, loc.getDefaultName()));
}
@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));
updateLanguage(languageResolver.getDefault());
languagePopup=new PopupMenu(getActivity(), languageButton);
languageButton.setOnTouchListener(languagePopup.getDragToOpenListener());
languageButton.setOnClickListener(v->languagePopup.show());
Menu languageMenu = languagePopup.getMenu();
for (String recentLanguage : Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages)) {
MastodonLanguage l = languageResolver.from(recentLanguage);
languageMenu.add(0, allLanguages.indexOf(l), Menu.NONE, getActivity().getString(R.string.language_name, l.getDefaultName(), l.getLanguageName()));
}
SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.available_languages);
for (int i = 0; i < allLanguages.size(); i++) {
MastodonLanguage l = allLanguages.get(i);
allLanguagesMenu.add(0, i, Menu.NONE, getActivity().getString(R.string.language_name, l.getDefaultName(), l.getLanguageName()));
}
languagePopup.setOnMenuItemClickListener(i->{
if (i.hasSubMenu()) return false;
updateLanguage(allLanguages.get(i.getItemId()));
return true;
});
return languageButton;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
return true;
@@ -697,6 +767,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.status=text;
req.visibility=statusVisibility;
req.sensitive=sensitive;
req.language=language;
if(!attachments.isEmpty()){
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
}
@@ -773,6 +844,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.setCallback(resCallback)
.exec(accountID);
}
if (replyTo == null) {
List<String> newRecentLanguages = new ArrayList<>(Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages));
newRecentLanguages.remove(language);
newRecentLanguages.add(0, language);
recentLanguages.put(accountID, newRecentLanguages.stream().limit(4).collect(Collectors.toList()));
GlobalUserPreferences.save();
}
}
private boolean hasDraft(){
@@ -1362,6 +1441,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
public void onSuccess(Preferences result){
// Only override the reply visibility if our preference is more private
if (result.postingDefaultVisibility.isLessVisibleThan(statusVisibility)) {
// Map unlisted from the API onto public, because we don't have unlisted in the UI
statusVisibility = switch (result.postingDefaultVisibility) {
case PUBLIC -> StatusPrivacy.PUBLIC;
case UNLISTED -> StatusPrivacy.UNLISTED;

View File

@@ -48,6 +48,7 @@ import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Consumer;
import androidx.annotation.DrawableRes;
@@ -159,6 +160,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
items.add(new TextItem(R.string.settings_contribute_fork, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon")));
items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache));
items.add(new TextItem(R.string.clear_recent_languages, ()->UiUtils.showConfirmationAlert(getActivity(), R.string.clear_recent_languages, R.string.confirm_clear_recent_languages, R.string.clear, ()->{
GlobalUserPreferences.recentLanguages.remove(accountID);
GlobalUserPreferences.save();
})));
items.add(new TextItem(R.string.log_out, this::confirmLogOut));
items.add(new FooterItem(getString(R.string.settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));

View File

@@ -1,11 +1,19 @@
package org.joinmastodon.android.fragments;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
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.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.MastodonApp;
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.views.SizeListenerFrameLayout;
import androidx.annotation.NonNull;
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.fragments.AppKitFragment;
import me.grishka.appkit.utils.V;
@@ -23,12 +35,13 @@ public class SplashFragment extends AppKitFragment{
private SizeListenerFrameLayout contentView;
private View artContainer, blueFill, greenFill;
private InterpolatingMotionEffect motionEffect;
private ViewPager2 pager;
private ViewGroup pagerDots;
private View artClouds, artPlaneElephant, artRightHill, artLeftHill, artCenterHill;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
}
@Nullable
@@ -37,15 +50,44 @@ public class SplashFragment extends AppKitFragment{
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_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);
blueFill=contentView.findViewById(R.id.blue_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(){
@Override
@@ -72,10 +114,10 @@ public class SplashFragment extends AppKitFragment{
}
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.setScaleY(scale);
blueFill.setScaleY(h/2f);
blueFill.setScaleY(artContainer.getBottom()-V.dp(90));
greenFill.setScaleY(h-artContainer.getBottom()+V.dp(90));
}
@@ -101,15 +143,91 @@ public class SplashFragment extends AppKitFragment{
return true;
}
@Override
protected void onShown(){
super.onShown();
motionEffect.activate();
private class PagerAdapter extends RecyclerView.Adapter<PagerViewHolder>{
@NonNull
@Override
public PagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
return new PagerViewHolder(viewType);
}
@Override
public void onBindViewHolder(@NonNull PagerViewHolder holder, int position){}
@Override
public int getItemCount(){
return 3;
}
@Override
public int getItemViewType(int position){
return position;
}
}
@Override
protected void onHidden(){
super.onHidden();
motionEffect.deactivate();
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();
}
}
}

File diff suppressed because one or more lines are too long

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

@@ -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

@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="257dp"
android:height="67dp"
android:width="134dp"
android:height="34dp"
android:viewportWidth="313"
android:viewportHeight="81">
<path
@@ -20,8 +20,8 @@
</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:fillColor="#ffffff"/>
android:fillColor="#000"/>
<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:fillColor="#ffffff"/>
android:fillColor="#000"/>
</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

@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.SizeListenerFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<org.joinmastodon.android.ui.views.SizeListenerFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:clipToPadding="false"
android:clipChildren="false">
android:clipToPadding="false">
<View
android:id="@+id/blue_fill"
@@ -18,51 +17,60 @@
<FrameLayout
android:id="@+id/art_container"
android:layout_width="450dp"
android:layout_height="631dp"
android:layout_marginTop="40dp"
android:layout_gravity="center">
android:layout_width="360dp"
android:layout_height="640dp"
android:layout_gravity="center"
tools:ignore="rtlHardcoded">
<ImageView
android:id="@+id/art_clouds"
android:layout_width="450dp"
android:layout_height="589dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_width="414dp"
android:layout_height="541dp"
android:layout_marginTop="91dp"
android:layout_gravity="top|left"
android:alpha="0.3"
android:importantForAccessibility="no"
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
android:id="@+id/art_right_hill"
android:layout_width="218dp"
android:layout_height="255dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="156dp"
android:layout_marginRight="11dp"
android:layout_width="150.84dp"
android:layout_height="176.44dp"
android:layout_gravity="top|left"
android:layout_marginLeft="322dp"
android:layout_marginTop="310dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer1"/>
<ImageView
android:id="@+id/art_left_hill"
android:layout_width="285dp"
android:layout_height="222dp"
android:layout_gravity="bottom|left"
android:layout_marginLeft="-6dp"
android:layout_marginBottom="243dp"
android:layout_width="197.2dp"
android:layout_height="153.61dp"
android:layout_gravity="top|left"
android:layout_marginTop="294dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer2"/>
<ImageView
android:id="@+id/art_center_hill"
android:layout_width="457dp"
android:layout_height="397dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="51dp"
android:layout_width="400dp"
android:layout_height="346dp"
android:layout_gravity="top|left"
android:layout_marginTop="294dp"
android:importantForAccessibility="no"
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>
<View
@@ -73,36 +81,65 @@
android:transformPivotY="1px"
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
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="16dp"
android:layout_height="match_parent"
android:clipToPadding="false"
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_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/pager_dots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="13dp"
style="@style/Widget.Mastodon.Button.Large.Primary_LightOnDark"
android:text="@string/get_started"/>
android:layout_gravity="center_horizontal"
android:layout_marginBottom="16dp"
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
android:id="@+id/btn_log_in"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.Mastodon.Button.Large.Primary_DarkOnLight"
android:background="@drawable/bg_button_green"
android:text="@string/log_in"/>
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
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>
</org.joinmastodon.android.ui.views.SizeListenerFrameLayout>

View File

@@ -866,6 +866,13 @@
<item name="android:paddingRight">24dp</item>
</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">
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">24dp</item>