From b2d49c31435a1d5e802aa605e842dc723c32db9c Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 15 Apr 2024 16:36:59 +0300 Subject: [PATCH 01/19] Initial implementation of donations --- mastodon/build.gradle | 2 +- .../android/api/CacheController.java | 10 +- .../android/api/DatabaseRunnable.java | 10 + .../catalog/GetDonationCampaigns.java | 28 ++ .../android/api/session/AccountSession.java | 9 +- .../api/session/AccountSessionManager.java | 97 ++++- .../DismissDonationCampaignBannerEvent.java | 9 + .../fragments/DonationWebViewFragment.java | 52 +++ .../fragments/HomeTimelineFragment.java | 106 ++++++ .../android/fragments/WebViewFragment.java | 76 ++++ .../settings/SettingsDebugFragment.java | 8 +- .../model/donations/DonationCampaign.java | 33 ++ .../android/ui/sheets/DonationSheet.java | 288 +++++++++++++++ .../android/ui/views/CurrencyAmountInput.java | 336 ++++++++++++++++++ .../main/res/drawable-xxxhdpi/scribble.webp | Bin 0 -> 62438 bytes .../main/res/drawable/bg_donation_banner.xml | 13 + .../src/main/res/drawable/bg_filter_chip.xml | 10 + .../main/res/drawable/fg_currency_input.xml | 15 + .../main/res/drawable/ic_donation_monthly.xml | 5 + .../main/res/drawable/ic_favorite_18px.xml | 9 + .../drawable/ic_volunteer_activism_20px.xml | 9 + .../src/main/res/layout/donation_banner.xml | 32 ++ .../src/main/res/layout/fragment_timeline.xml | 7 + .../src/main/res/layout/sheet_donation.xml | 114 ++++++ .../src/main/res/values/colors_masterial.xml | 336 ++++++++++++++++++ mastodon/src/main/res/values/strings.xml | 5 + 26 files changed, 1606 insertions(+), 13 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/DatabaseRunnable.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/events/DismissDonationCampaignBannerEvent.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/model/donations/DonationCampaign.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java create mode 100644 mastodon/src/main/res/drawable-xxxhdpi/scribble.webp create mode 100644 mastodon/src/main/res/drawable/bg_donation_banner.xml create mode 100644 mastodon/src/main/res/drawable/fg_currency_input.xml create mode 100644 mastodon/src/main/res/drawable/ic_donation_monthly.xml create mode 100644 mastodon/src/main/res/drawable/ic_favorite_18px.xml create mode 100644 mastodon/src/main/res/drawable/ic_volunteer_activism_20px.xml create mode 100644 mastodon/src/main/res/layout/donation_banner.xml create mode 100644 mastodon/src/main/res/layout/sheet_donation.xml create mode 100644 mastodon/src/main/res/values/colors_masterial.xml diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 5077aae01..c7148d802 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -13,7 +13,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 33 - versionCode 93 + versionCode 94 versionName "2.5.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java b/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java index 6e226bb65..3a027e7e2 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java @@ -24,7 +24,6 @@ import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.PaginatedResponse; import org.joinmastodon.android.model.SearchResult; import org.joinmastodon.android.model.Status; -import org.joinmastodon.android.ui.utils.UiUtils; import java.io.File; import java.io.FileInputStream; @@ -45,8 +44,8 @@ import me.grishka.appkit.utils.WorkerThread; public class CacheController{ private static final String TAG="CacheController"; private static final int DB_VERSION=3; - private static final WorkerThread databaseThread=new WorkerThread("databaseThread"); - private static final Handler uiHandler=new Handler(Looper.getMainLooper()); + public static final WorkerThread databaseThread=new WorkerThread("databaseThread"); + public static final Handler uiHandler=new Handler(Looper.getMainLooper()); private final String accountID; private DatabaseHelper db; @@ -467,9 +466,4 @@ public class CacheController{ db.execSQL("ALTER TABLE `notifications_mentions` ADD `time` INTEGER NOT NULL DEFAULT 0"); } } - - @FunctionalInterface - private interface DatabaseRunnable{ - void run(SQLiteDatabase db) throws IOException; - } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/DatabaseRunnable.java b/mastodon/src/main/java/org/joinmastodon/android/api/DatabaseRunnable.java new file mode 100644 index 000000000..bf8b711c9 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/DatabaseRunnable.java @@ -0,0 +1,10 @@ +package org.joinmastodon.android.api; + +import android.database.sqlite.SQLiteDatabase; + +import java.io.IOException; + +@FunctionalInterface +public interface DatabaseRunnable{ + void run(SQLiteDatabase db) throws IOException; +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java new file mode 100644 index 000000000..e6f018efa --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java @@ -0,0 +1,28 @@ +package org.joinmastodon.android.api.requests.catalog; + +import android.net.Uri; + +import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.model.donations.DonationCampaign; + +public class GetDonationCampaigns extends MastodonAPIRequest{ + private final String locale, seed; + + public GetDonationCampaigns(String locale, String seed){ + super(HttpMethod.GET, null, DonationCampaign.class); + this.locale=locale; + this.seed=seed; + } + + @Override + public Uri getURL(){ + Uri.Builder builder=new Uri.Builder() + .scheme("https") + .authority("api.joinmastodon.org") + .path("/donations/campaigns") + .appendQueryParameter("platform", "android") + .appendQueryParameter("locale", locale) + .appendQueryParameter("seed", seed); + return builder.build(); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java index 43190c73d..55cdac05f 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java @@ -33,7 +33,6 @@ import org.joinmastodon.android.model.TimelineMarkers; import org.joinmastodon.android.model.Token; import org.joinmastodon.android.utils.ObjectIdComparator; -import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -276,4 +275,12 @@ public class AccountSession{ public void setNotificationsMentionsOnly(boolean mentionsOnly){ getRawLocalPreferences().edit().putBoolean("notificationsMentionsOnly", mentionsOnly).apply(); } + + public boolean isEligibleForDonations(){ + return "mastodon.social".equalsIgnoreCase(domain) || "mastodon.online".equalsIgnoreCase(domain); + } + + public int getDonationSeed(){ + return Math.abs(getFullUsername().hashCode())%100; + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java index 07e5059d4..621c5a197 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java @@ -3,11 +3,16 @@ package org.joinmastodon.android.api.session; import android.app.Activity; import android.app.NotificationManager; import android.content.ComponentName; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteOpenHelper; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; @@ -18,11 +23,13 @@ import org.joinmastodon.android.E; import org.joinmastodon.android.MainActivity; import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.R; +import org.joinmastodon.android.api.CacheController; +import org.joinmastodon.android.api.DatabaseRunnable; import org.joinmastodon.android.api.MastodonAPIController; import org.joinmastodon.android.api.PushSubscriptionManager; +import org.joinmastodon.android.api.requests.accounts.GetOwnAccount; import org.joinmastodon.android.api.requests.filters.GetLegacyFilters; import org.joinmastodon.android.api.requests.instance.GetCustomEmojis; -import org.joinmastodon.android.api.requests.accounts.GetOwnAccount; import org.joinmastodon.android.api.requests.instance.GetInstance; import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp; import org.joinmastodon.android.events.EmojiUpdatedEvent; @@ -30,9 +37,10 @@ import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Application; import org.joinmastodon.android.model.Emoji; import org.joinmastodon.android.model.EmojiCategory; -import org.joinmastodon.android.model.LegacyFilter; import org.joinmastodon.android.model.Instance; +import org.joinmastodon.android.model.LegacyFilter; import org.joinmastodon.android.model.Token; +import org.joinmastodon.android.ui.utils.UiUtils; import java.io.File; import java.io.FileInputStream; @@ -60,6 +68,7 @@ public class AccountSessionManager{ private static final String TAG="AccountSessionManager"; public static final String SCOPE="read write follow push"; public static final String REDIRECT_URI="mastodon-android-auth://callback"; + private static final int DB_VERSION=1; private static final AccountSessionManager instance=new AccountSessionManager(); @@ -73,6 +82,8 @@ public class AccountSessionManager{ private String lastActiveAccountID; private SharedPreferences prefs; private boolean loadedInstances; + private DatabaseHelper db; + private final Runnable databaseCloseRunnable=this::closeDatabase; public static AccountSessionManager getInstance(){ return instance; @@ -442,6 +453,68 @@ public class AccountSessionManager{ } } + private void closeDelayed(){ + CacheController.databaseThread.postRunnable(databaseCloseRunnable, 10_000); + } + + public void closeDatabase(){ + if(db!=null){ + if(BuildConfig.DEBUG) + Log.d(TAG, "closeDatabase"); + db.close(); + db=null; + } + } + + private void cancelDelayedClose(){ + if(db!=null){ + CacheController.databaseThread.handler.removeCallbacks(databaseCloseRunnable); + } + } + + private SQLiteDatabase getOrOpenDatabase(){ + if(db==null) + db=new DatabaseHelper(); + return db.getWritableDatabase(); + } + + private void runOnDbThread(DatabaseRunnable r){ + cancelDelayedClose(); + CacheController.databaseThread.postRunnable(()->{ + try{ + SQLiteDatabase db=getOrOpenDatabase(); + r.run(db); + }catch(SQLiteException|IOException x){ + Log.w(TAG, x); + }finally{ + closeDelayed(); + } + }, 0); + } + + public void runIfDonationCampaignNotDismissed(String id, Runnable action){ + runOnDbThread(db->{ + try(Cursor cursor=db.query("dismissed_donation_campaigns", null, "id=?", new String[]{id}, null, null, null)){ + if(!cursor.moveToFirst()){ + UiUtils.runOnUiThread(action); + } + } + }); + } + + public void markDonationCampaignAsDismissed(String id){ + runOnDbThread(db->{ + ContentValues values=new ContentValues(); + values.put("id", id); + values.put("dismissed_at", System.currentTimeMillis()); + db.insert("dismissed_donation_campaigns", null, values); + }); + } + + public void clearDismissedDonationCampaigns(){ + runOnDbThread(db->db.delete("dismissed_donation_campaigns", null, null)); + } + private static class SessionsStorageWrapper{ public List accounts; } @@ -451,4 +524,24 @@ public class AccountSessionManager{ public List emojis; public long lastUpdated; } + + private static class DatabaseHelper extends SQLiteOpenHelper{ + public DatabaseHelper(){ + super(MastodonApp.context, "accounts.db", null, DB_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db){ + db.execSQL(""" + CREATE TABLE `dismissed_donation_campaigns` ( + `id` text PRIMARY KEY, + `dismissed_at` bigint + )"""); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){ + + } + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/DismissDonationCampaignBannerEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/DismissDonationCampaignBannerEvent.java new file mode 100644 index 000000000..101369e17 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/events/DismissDonationCampaignBannerEvent.java @@ -0,0 +1,9 @@ +package org.joinmastodon.android.events; + +public class DismissDonationCampaignBannerEvent{ + public final String campaignID; + + public DismissDonationCampaignBannerEvent(String campaignID){ + this.campaignID=campaignID; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java new file mode 100644 index 000000000..6ca545c47 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java @@ -0,0 +1,52 @@ +package org.joinmastodon.android.fragments; + +import android.os.Bundle; +import android.view.View; +import android.webkit.WebResourceRequest; + +import org.joinmastodon.android.E; +import org.joinmastodon.android.R; +import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.events.DismissDonationCampaignBannerEvent; +import org.joinmastodon.android.ui.M3AlertDialogBuilder; + +import java.util.Objects; + +import me.grishka.appkit.Nav; + +public class DonationWebViewFragment extends WebViewFragment{ + public static final String SUCCESS_URL="https://sponsor.joinmastodon.org/donation/success"; + public static final String FAILURE_URL="https://sponsor.joinmastodon.org/donation/failure"; + + @Override + public void onViewCreated(View view, Bundle savedInstanceState){ + super.onViewCreated(view, savedInstanceState); + webView.loadUrl(Objects.requireNonNull(getArguments().getString("url"))); + } + + @Override + protected boolean shouldOverrideUrlLoading(WebResourceRequest req){ + String url=req.getUrl().buildUpon().clearQuery().fragment(null).build().toString(); + if(url.equalsIgnoreCase(SUCCESS_URL)){ + new M3AlertDialogBuilder(getActivity()) + .setTitle("Success") + .setMessage("Some sort of UI that would tell the user that their payment was successful") + .setPositiveButton(R.string.ok, null) + .setOnDismissListener(dlg->Nav.finish(this)) + .show(); + String campaignID=getArguments().getString("campaignID"); + AccountSessionManager.getInstance().markDonationCampaignAsDismissed(campaignID); + E.post(new DismissDonationCampaignBannerEvent(campaignID)); + return true; + }else if(url.equalsIgnoreCase(FAILURE_URL)){ + new M3AlertDialogBuilder(getActivity()) + .setTitle("Failure") + .setMessage("Some sort of UI that would tell the user that their payment didn't go through") + .setPositiveButton(R.string.ok, null) + .setOnDismissListener(dlg->Nav.finish(this)) + .show(); + return true; + } + return false; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 174aa2335..1d60f042a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -7,13 +7,19 @@ import android.animation.ObjectAnimator; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; +import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.text.style.TypefaceSpan; +import android.text.style.UnderlineSpan; import android.view.Gravity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.ViewStub; +import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; import android.widget.Button; @@ -29,11 +35,13 @@ import com.squareup.otto.Subscribe; import org.joinmastodon.android.E; import org.joinmastodon.android.R; import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns; import org.joinmastodon.android.api.requests.markers.SaveMarkers; import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline; import org.joinmastodon.android.api.requests.timelines.GetListTimeline; import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline; import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.events.DismissDonationCampaignBannerEvent; import org.joinmastodon.android.events.SelfUpdateStateChangedEvent; import org.joinmastodon.android.fragments.settings.SettingsMainFragment; import org.joinmastodon.android.model.CacheablePaginatedResponse; @@ -41,8 +49,10 @@ import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FollowList; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.TimelineMarkers; +import org.joinmastodon.android.model.donations.DonationCampaign; import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.StatusDisplayItem; +import org.joinmastodon.android.ui.sheets.DonationSheet; import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper; import org.joinmastodon.android.ui.viewcontrollers.HomeTimelineMenuController; import org.joinmastodon.android.ui.viewcontrollers.ToolbarDropdownMenuController; @@ -53,6 +63,7 @@ import org.parceler.Parcels; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import androidx.annotation.NonNull; @@ -81,9 +92,12 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD private FollowList currentList; private MergeRecyclerAdapter mergeAdapter; private DiscoverInfoBannerHelper localTimelineBannerHelper; + private View donationBanner; + private boolean donationBannerDismissing; private String maxID; private String lastSavedMarkerID; + private DonationCampaign currentDonationCampaign; public HomeTimelineFragment(){ setListLayoutId(R.layout.fragment_timeline); @@ -93,6 +107,23 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); localTimelineBannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.LOCAL_TIMELINE, accountID); + + // TODO how often do we do this request? Maybe cache something somewhere? + if(AccountSessionManager.get(accountID).isEligibleForDonations()){ + new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed())) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(DonationCampaign result){ + if(result==null) + return; + AccountSessionManager.getInstance().runIfDonationCampaignNotDismissed(result.id, ()->showDonationBanner(result)); + } + + @Override + public void onError(ErrorResponse error){} + }) + .execNoAuth(""); + } } @Override @@ -599,6 +630,12 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD updateUpdateState(ev.state); } + public void onDismissDonationCampaignBanner(DismissDonationCampaignBannerEvent ev){ + if(currentDonationCampaign!=null && ev.campaignID.equals(currentDonationCampaign.id)){ + dismissDonationBanner(); + } + } + @Override protected boolean shouldRemoveAccountPostsWhenUnfollowing(){ return true; @@ -661,6 +698,75 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD }; } + private void showDonationBanner(DonationCampaign campaign){ + if(getActivity()==null) + return; + currentDonationCampaign=campaign; + if(donationBanner==null){ + ViewStub stub=contentView.findViewById(R.id.donation_banner); + donationBanner=stub.inflate(); + donationBanner.findViewById(R.id.banner_dismiss).setOnClickListener(v->{ + AccountSessionManager.getInstance().markDonationCampaignAsDismissed(currentDonationCampaign.id); + dismissDonationBanner(); + }); + donationBanner.setOnClickListener(v->openDonationSheet()); + }else{ + donationBanner.setVisibility(View.VISIBLE); + } + TextView text=donationBanner.findViewById(R.id.banner_text); + SpannableStringBuilder ssb=new SpannableStringBuilder(campaign.bannerMessage); + ssb.append(' '); + int start=ssb.length(); + ssb.append(campaign.bannerButtonText); + ssb.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.masterialDark_colorGoldenrodContainer, getActivity().getTheme())), start, ssb.length(), 0); + ssb.setSpan(new UnderlineSpan(), start, ssb.length(), 0); + ssb.setSpan(new TypefaceSpan("sans-serif-medium"), start, ssb.length(), 0); + text.setText(ssb); + donationBanner.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){ + @Override + public boolean onPreDraw(){ + donationBanner.getViewTreeObserver().removeOnPreDrawListener(this); + + AnimatorSet set=new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(donationBanner, View.TRANSLATION_Y, donationBanner.getHeight(), 0), + ObjectAnimator.ofFloat(fab, View.TRANSLATION_Y, -donationBanner.getHeight()) + ); + set.setDuration(250); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.start(); + + return true; + } + }); + } + + private void dismissDonationBanner(){ + if(donationBanner==null || donationBannerDismissing) + return; + AnimatorSet set=new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofFloat(donationBanner, View.TRANSLATION_Y, donationBanner.getHeight()), + ObjectAnimator.ofFloat(fab, View.TRANSLATION_Y, 0) + ); + set.setDuration(250); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.addListener(new AnimatorListenerAdapter(){ + @Override + public void onAnimationEnd(Animator animation){ + donationBanner.setVisibility(View.GONE); + donationBannerDismissing=false; + } + }); + donationBannerDismissing=true; + set.start(); + currentDonationCampaign=null; + } + + private void openDonationSheet(){ + new DonationSheet(getActivity(), currentDonationCampaign, accountID).show(); + } + private enum ListMode{ FOLLOWING, LOCAL, diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java new file mode 100644 index 000000000..6146abc7c --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java @@ -0,0 +1,76 @@ +package org.joinmastodon.android.fragments; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import org.joinmastodon.android.api.MastodonErrorResponse; + +import me.grishka.appkit.Nav; +import me.grishka.appkit.fragments.LoaderFragment; +import me.grishka.appkit.fragments.OnBackPressedListener; + +public abstract class WebViewFragment extends LoaderFragment implements OnBackPressedListener{ + protected WebView webView; + + @Override + public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ + webView=new WebView(getActivity()); + webView.setWebChromeClient(new WebChromeClient(){ + @Override + public void onReceivedTitle(WebView view, String title){ + setTitle(title); + } + }); + webView.setWebViewClient(new WebViewClient(){ + @Override + public void onPageFinished(WebView view, String url){ + dataLoaded(); + } + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){ + onError(new MastodonErrorResponse(error.getDescription().toString(), -1, null)); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request){ + return WebViewFragment.this.shouldOverrideUrlLoading(request); + } + }); + webView.getSettings().setJavaScriptEnabled(true); + return webView; + } + + @Override + protected void doLoadData(){ + + } + + @Override + public void onRefresh(){ + webView.reload(); + } + + @Override + public boolean onBackPressed(){ + if(webView.canGoBack()){ + webView.goBack(); + return true; + } + return false; + } + + @Override + public void onToolbarNavigationClick(){ + Nav.finish(this); + } + + protected abstract boolean shouldOverrideUrlLoading(WebResourceRequest req); +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java index 755238e83..35b9554d4 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java @@ -28,7 +28,8 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ selfUpdateItem=new ListItem<>("Force self-update", null, this::onForceSelfUpdateClick), resetUpdateItem=new ListItem<>("Reset self-updater", null, this::onResetUpdaterClick), new ListItem<>("Reset search info banners", null, this::onResetDiscoverBannersClick), - new ListItem<>("Reset pre-reply sheets", null, this::onResetPreReplySheetsClick) + new ListItem<>("Reset pre-reply sheets", null, this::onResetPreReplySheetsClick), + new ListItem<>("Clear dismissed donation campaigns", null, this::onClearDismissedCampaignsClick) )); if(!GithubSelfUpdater.needSelfUpdating()){ resetUpdateItem.isEnabled=selfUpdateItem.isEnabled=false; @@ -70,6 +71,11 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ Toast.makeText(getActivity(), "Pre-reply sheets were reset", Toast.LENGTH_SHORT).show(); } + private void onClearDismissedCampaignsClick(ListItem item){ + AccountSessionManager.getInstance().clearDismissedDonationCampaigns(); + Toast.makeText(getActivity(), "Dismissed campaigns cleared. Restart app to see your current campaign, if any", Toast.LENGTH_LONG).show(); + } + private void restartUI(){ Bundle args=new Bundle(); args.putString("account", accountID); diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/donations/DonationCampaign.java b/mastodon/src/main/java/org/joinmastodon/android/model/donations/DonationCampaign.java new file mode 100644 index 000000000..819011d02 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/model/donations/DonationCampaign.java @@ -0,0 +1,33 @@ +package org.joinmastodon.android.model.donations; + +import org.joinmastodon.android.api.AllFieldsAreRequired; +import org.joinmastodon.android.api.ObjectValidationException; +import org.joinmastodon.android.api.RequiredField; +import org.joinmastodon.android.model.BaseModel; + +import java.util.Map; + +@AllFieldsAreRequired +public class DonationCampaign extends BaseModel{ + public String id; + public String bannerMessage; + public String bannerButtonText; + public String donationMessage; + public String donationButtonText; + public Amounts amounts; + public String defaultCurrency; + public String donationUrl; + + @Override + public void postprocess() throws ObjectValidationException{ + super.postprocess(); + amounts.postprocess(); + } + + public static class Amounts extends BaseModel{ + public Map oneTime; + @RequiredField + public Map monthly; + public Map yearly; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java new file mode 100644 index 000000000..4fa4ab52d --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java @@ -0,0 +1,288 @@ +package org.joinmastodon.android.ui.sheets; + +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ToggleButton; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.fragments.DonationWebViewFragment; +import org.joinmastodon.android.model.donations.DonationCampaign; +import org.joinmastodon.android.ui.M3AlertDialogBuilder; +import org.joinmastodon.android.ui.OutlineProviders; +import org.joinmastodon.android.ui.utils.UiUtils; +import org.joinmastodon.android.ui.views.CurrencyAmountInput; + +import java.text.NumberFormat; +import java.util.Currency; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +import androidx.annotation.NonNull; +import me.grishka.appkit.Nav; +import me.grishka.appkit.utils.V; +import me.grishka.appkit.views.BottomSheet; + +public class DonationSheet extends BottomSheet{ + private final DonationCampaign campaign; + private final String accountID; + private DonationFrequency frequency=DonationFrequency.MONTHLY; + + private View onceTab, monthlyTab, yearlyTab; + private int currentTab; + private CurrencyAmountInput amountField; + private ToggleButton[] suggestedAmountButtons=new ToggleButton[6]; + private View button; + private TextView buttonText; + private Activity activity; + + public DonationSheet(@NonNull Activity activity, DonationCampaign campaign, String accountID){ + super(activity); + this.campaign=campaign; + this.accountID=accountID; + this.activity=activity; + Context context=activity; + + View content=context.getSystemService(LayoutInflater.class).inflate(R.layout.sheet_donation, null); + setContentView(content); + setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.colorM3Surface), + UiUtils.getThemeColor(context, R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme()); + + TextView text=findViewById(R.id.text); + text.setText(campaign.donationMessage); + + onceTab=findViewById(R.id.once); + monthlyTab=findViewById(R.id.monthly); + yearlyTab=findViewById(R.id.yearly); + onceTab.setOnClickListener(this::onTabClick); + monthlyTab.setOnClickListener(this::onTabClick); + yearlyTab.setOnClickListener(this::onTabClick); + + if(campaign.amounts.yearly==null) + yearlyTab.setVisibility(View.GONE); + if(campaign.amounts.oneTime==null) + onceTab.setVisibility(View.GONE); + if(campaign.amounts.monthly==null){ + monthlyTab.setVisibility(View.GONE); + if(campaign.amounts.oneTime!=null){ + onceTab.setSelected(true); + currentTab=R.id.once; + frequency=DonationFrequency.ONCE; + }else if(campaign.amounts.yearly!=null){ + yearlyTab.setSelected(true); + currentTab=R.id.yearly; + frequency=DonationFrequency.YEARLY; + }else{ + Toast.makeText(context, "Amounts object is empty", Toast.LENGTH_SHORT).show(); + dismiss(); + return; + } + }else{ + monthlyTab.setSelected(true); + currentTab=R.id.monthly; + } + + + View tabBarItself=findViewById(R.id.tabbar_inner); + tabBarItself.setOutlineProvider(OutlineProviders.roundedRect(20)); + tabBarItself.setClipToOutline(true); + + amountField=findViewById(R.id.amount); + List availableCurrencies=campaign.amounts.monthly.keySet().stream().sorted().collect(Collectors.toList()); + amountField.setCurrencies(availableCurrencies); + try{ + amountField.setSelectedCurrency(campaign.defaultCurrency); + }catch(IllegalArgumentException x){ + new M3AlertDialogBuilder(context) + .setTitle(R.string.error) + .setMessage("Default currency "+campaign.defaultCurrency+" not in list of available currencies "+availableCurrencies) + .show(); + dismiss(); + return; + } + amountField.setChangeListener(new CurrencyAmountInput.ChangeListener(){ + @Override + public void onCurrencyChanged(String code){ + updateSuggestedAmounts(code); + button.setEnabled(amountField.getAmount()>=getMinimumChargeAmount(code)); + updateSuggestedButtonsState(); + } + + @Override + public void onAmountChanged(long amount){ + button.setEnabled(amount>=getMinimumChargeAmount(amountField.getCurrency())); + updateSuggestedButtonsState(); + } + }); + button=findViewById(R.id.button); + buttonText=findViewById(R.id.button_text); + + LinearLayout suggestedAmounts=findViewById(R.id.suggested_amounts); + for(int i=0;iopenWebView()); + } + + @Override + protected void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + Window window=getWindow(); + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + + private void onTabClick(View v){ + if(v.getId()==currentTab) + return; + findViewById(currentTab).setSelected(false); + v.setSelected(true); + currentTab=v.getId(); + if(currentTab==R.id.once) + frequency=DonationFrequency.ONCE; + else if(currentTab==R.id.monthly) + frequency=DonationFrequency.MONTHLY; + else if(currentTab==R.id.yearly) + frequency=DonationFrequency.YEARLY; + updateSuggestedAmounts(amountField.getCurrency()); + } + + private long[] getCurrentSuggestedAmounts(String currency){ + long[] amounts=(switch(frequency){ + case ONCE -> campaign.amounts.oneTime; + case MONTHLY -> campaign.amounts.monthly; + case YEARLY -> campaign.amounts.yearly; + }).get(currency); + if(amounts==null){ + amounts=new long[0]; + } + return amounts; + } + + private void updateSuggestedAmounts(String currency){ + NumberFormat format=NumberFormat.getCurrencyInstance(); + try{ + format.setCurrency(Currency.getInstance(currency)); + }catch(IllegalArgumentException ignore){} + int defaultFractionDigits=format.getMinimumFractionDigits(); + long[] amounts=getCurrentSuggestedAmounts(currency); + for(int i=0;i=amounts.length){ + btn.setVisibility(View.GONE); + continue; + } + btn.setVisibility(View.VISIBLE); + long amount=amounts[i]; + format.setMinimumFractionDigits(amount%100==0 ? 0 : defaultFractionDigits); + btn.setText(format.format(amount/100.0)); + } + updateSuggestedButtonsState(); + } + + private void onSuggestedAmountClick(View v){ + int index=(int) v.getTag(); + long[] amounts=getCurrentSuggestedAmounts(amountField.getCurrency()); + amountField.setAmount(amounts[index]); + } + + private void updateSuggestedButtonsState(){ + long amount=amountField.getAmount(); + long[] amounts=getCurrentSuggestedAmounts(amountField.getCurrency()); + for(int i=0;i "one_time"; + case MONTHLY -> "monthly"; + case YEARLY -> "yearly"; + }) + .appendQueryParameter("success_callback_url", DonationWebViewFragment.SUCCESS_URL) + .appendQueryParameter("failure_callback_url", DonationWebViewFragment.FAILURE_URL); + Bundle args=new Bundle(); + args.putString("url", builder.build().toString()); + args.putString("account", accountID); + args.putString("campaignID", campaign.id); + Nav.go(activity, DonationWebViewFragment.class, args); + dismiss(); + } + + private static long getMinimumChargeAmount(String currency){ + // https://docs.stripe.com/currencies#minimum-and-maximum-charge-amounts + // values are in cents + return switch(currency){ + case "USD" -> 50; + case "AED" -> 2_00; + case "AUD" -> 50; + case "BGN" -> 1_00; + case "BRL" -> 50; + case "CAD" -> 50; + case "CHF" -> 50; + case "CZK" -> 15_00; + case "DKK" -> 2_50; + case "EUR" -> 50; + case "GBP" -> 30; + case "HKD" -> 4_00; + case "HUF" -> 175_00; + case "INR" -> 50; + case "JPY" -> 50_00; + case "MXN" -> 10_00; + case "MYR" -> 2_00; + case "NOK" -> 3_00; + case "NZD" -> 50; + case "PLN" -> 2_00; + case "RON" -> 2_00; + case "SEK" -> 3_00; + case "SGD" -> 50; + case "THB" -> 10_00; + + default -> 50; + }; + } + + private enum DonationFrequency{ + ONCE, + MONTHLY, + YEARLY + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java new file mode 100644 index 000000000..bbd98310b --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java @@ -0,0 +1,336 @@ +package org.joinmastodon.android.ui.views; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextWatcher; +import android.text.method.DigitsKeyListener; +import android.text.style.ReplacementSpan; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.ui.M3AlertDialogBuilder; +import org.joinmastodon.android.ui.OutlineProviders; +import org.joinmastodon.android.ui.utils.UiUtils; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Currency; +import java.util.List; +import java.util.stream.Collectors; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import me.grishka.appkit.utils.CustomViewHelper; + +public class CurrencyAmountInput extends LinearLayout implements CustomViewHelper{ + private ActualEditText edit; + private Button currencyBtn; + private List currencies; + private CurrencyInfo currentCurrency; + private boolean spanAdded; + private CurrencySymbolSpan symbolSpan; + private boolean symbolBeforeAmount; + private ChangeListener changeListener; + private long lastAmount=0; + private NumberFormat numberFormat=NumberFormat.getNumberInstance(); + private boolean allowSymbolToBeDeleted; + + public CurrencyAmountInput(Context context){ + this(context, null); + } + + public CurrencyAmountInput(Context context, AttributeSet attrs){ + this(context, attrs, 0); + } + + public CurrencyAmountInput(Context context, AttributeSet attrs, int defStyle){ + super(context, attrs, defStyle); + setForeground(getResources().getDrawable(R.drawable.fg_currency_input, context.getTheme())); + setAddStatesFromChildren(true); + + if(!isInEditMode()) + setOutlineProvider(OutlineProviders.roundedRect(8)); + setClipToOutline(true); + + currencyBtn=new Button(context); + currencyBtn.setTextAppearance(R.style.m3_label_large); + currencyBtn.setSingleLine(); + currencyBtn.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurfaceVariant)); + int pad=dp(12); + currencyBtn.setPadding(pad, 0, pad, 0); + currencyBtn.setBackgroundColor(UiUtils.getThemeColor(context, R.attr.colorM3SurfaceVariant)); + currencyBtn.setMinimumWidth(0); + currencyBtn.setMinWidth(0); + currencyBtn.setOnClickListener(v->showCurrencySelector()); + addView(currencyBtn, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + edit=new ActualEditText(context); + edit.setBackgroundColor(UiUtils.getThemeColor(context, R.attr.colorM3Surface)); + pad=dp(16); + edit.setPadding(pad, 0, pad, 0); + edit.setSingleLine(); + edit.setTextAppearance(R.style.m3_title_large); + edit.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurface)); + edit.setGravity(Gravity.END |Gravity.CENTER_VERTICAL); + edit.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); + InputFilter[] filters=edit.getText().getFilters(); + for(int i=0;i0; + + edit.addTextChangedListener(new TextWatcher(){ + private boolean ignore; + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after){ + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count){ + + } + + @Override + public void afterTextChanged(Editable e){ + if(ignore) + return; + ignore=true; + if(e.length()>0 && !spanAdded){ + SpannableString ss=new SpannableString(" "); + ss.setSpan(symbolSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + if(symbolBeforeAmount) + e.insert(0, ss); + else + e.append(ss); + spanAdded=true; + }else if(spanAdded && e.length()<=1){ + spanAdded=false; + if(e.length()>0){ + allowSymbolToBeDeleted=true; + e.clear(); + allowSymbolToBeDeleted=false; + } + } + ignore=false; + + updateAmount(); + } + }); + } + + public void setCurrencies(List currencies){ + this.currencies=currencies.stream().map(CurrencyInfo::new).collect(Collectors.toList()); + } + + public void setSelectedCurrency(String code){ + CurrencyInfo info=null; + for(CurrencyInfo c:currencies){ + if(c.code.equals(code)){ + info=c; + break; + } + } + if(info==null) + throw new IllegalArgumentException(); + setCurrency(info); + } + + private void setCurrency(CurrencyInfo info){ + currencyBtn.setText(info.code); + currentCurrency=info; + edit.invalidate(); + if(changeListener!=null) + changeListener.onCurrencyChanged(info.code); + } + + private void showCurrencySelector(){ + ArrayAdapter adapter=new ArrayAdapter<>(getContext(), R.layout.item_alert_single_choice_2lines_but_different, R.id.text, currencies){ + @Override + public boolean hasStableIds(){ + return true; + } + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent){ + View view=super.getView(position, convertView, parent); + TextView subtitle=view.findViewById(R.id.subtitle); + CurrencyInfo item=getItem(position); + if(item.jCurrency==null || item.jCurrency.getDisplayName().equals(item.code)){ + subtitle.setVisibility(View.GONE); + }else{ + subtitle.setVisibility(View.VISIBLE); + subtitle.setText(item.jCurrency.getDisplayName()); + } + return view; + } + }; + new M3AlertDialogBuilder(getContext()) + .setTitle(R.string.currency) + .setSingleChoiceItems(adapter, currencies.indexOf(currentCurrency), (dlg, item)->{ + setCurrency(currencies.get(item)); + dlg.dismiss(); + }) + .show(); + } + + public void setChangeListener(ChangeListener changeListener){ + this.changeListener=changeListener; + } + + private void updateAmount(){ + long newAmount; + try{ + Number n=numberFormat.parse(edit.getText().toString().trim()); + if(n instanceof Long l){ + newAmount=l*100L; + }else if(n instanceof Double d){ + newAmount=(long)(d*100); + }else{ + newAmount=0; + } + }catch(ParseException x){ + newAmount=0; + } + if(newAmount!=lastAmount){ + lastAmount=newAmount; + if(changeListener!=null) + changeListener.onAmountChanged(lastAmount); + } + } + + public long getAmount(){ + return lastAmount; + } + + public String getCurrency(){ + return currentCurrency.code; + } + + @SuppressLint("DefaultLocale") + public void setAmount(long amount){ + String value; + if(amount%100==0) + value=String.valueOf(amount/100); + else + value=String.format("%.2f", amount/100.0); + int start=spanAdded ? 1 : 0; + edit.getText().replace(start, edit.length(), value); + } + + private class ActualEditText extends EditText{ + public ActualEditText(Context context){ + super(context); + setClipToPadding(false); + } + + @Override + protected void onSelectionChanged(int selStart, int selEnd){ + super.onSelectionChanged(selStart, selEnd); + // Adjust the selection to prevent the symbol span being selected + if(spanAdded){ + int newSelStart=symbolBeforeAmount ? Math.max(selStart, 1) : Math.min(selStart, length()-1); + int newSelEnd=symbolBeforeAmount ? Math.max(selEnd, 1) : Math.min(selEnd, length()-1); + if(newSelStart!=selStart || newSelEnd!=selEnd){ + setSelection(newSelStart, newSelEnd); + } + } + } + } + + private static class CurrencyInfo{ + public String code; + public String symbol; + public Currency jCurrency; + + public CurrencyInfo(String code){ + this.code=code; + try{ + jCurrency=Currency.getInstance(code); + symbol=jCurrency.getSymbol(); + }catch(IllegalArgumentException x){ + symbol=code; + } + } + + @NonNull + @Override + public String toString(){ + return code; + } + } + + private class CurrencySymbolSpan extends ReplacementSpan{ + private Paint paint; + public CurrencySymbolSpan(Paint paint){ + this.paint=new Paint(paint); + this.paint.setTextSize(paint.getTextSize()*0.66f); + this.paint.setAlpha(77); + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm){ + return Math.round(this.paint.measureText(currentCurrency.symbol))+dp(2); + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint){ + if(!symbolBeforeAmount) + x+=dp(2); + canvas.drawText(currentCurrency.symbol, x, top+dp(1.5f)-this.paint.ascent(), this.paint); + } + } + + private class FormattingFriendlyDigitsKeyListener extends DigitsKeyListener{ + public FormattingFriendlyDigitsKeyListener(){ + super(false, true); + } + + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend){ + // Allow the currency symbol to be inserted (always done as a separate insertion operation) + if(source instanceof Spannable s && s.getSpans(start, end, CurrencySymbolSpan.class).length>0){ + return source; + } + // Don't allow the currency symbol to be deleted + if(!allowSymbolToBeDeleted && end-start0){ + return dest.subSequence(dstart, dend); + } + return super.filter(source, start, end, dest, dstart, dend); + } + } + + public interface ChangeListener{ + void onCurrencyChanged(String code); + void onAmountChanged(long amount); + } +} diff --git a/mastodon/src/main/res/drawable-xxxhdpi/scribble.webp b/mastodon/src/main/res/drawable-xxxhdpi/scribble.webp new file mode 100644 index 0000000000000000000000000000000000000000..abfe4d2747d03da29723e914c9cdd8f868dd13fa GIT binary patch literal 62438 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 literal 0 HcmV?d00001 diff --git a/mastodon/src/main/res/drawable/bg_donation_banner.xml b/mastodon/src/main/res/drawable/bg_donation_banner.xml new file mode 100644 index 000000000..de2ddedd8 --- /dev/null +++ b/mastodon/src/main/res/drawable/bg_donation_banner.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/bg_filter_chip.xml b/mastodon/src/main/res/drawable/bg_filter_chip.xml index d11366254..3072547e7 100644 --- a/mastodon/src/main/res/drawable/bg_filter_chip.xml +++ b/mastodon/src/main/res/drawable/bg_filter_chip.xml @@ -1,5 +1,15 @@ + + + + + + + + + + diff --git a/mastodon/src/main/res/drawable/fg_currency_input.xml b/mastodon/src/main/res/drawable/fg_currency_input.xml new file mode 100644 index 000000000..13f79a328 --- /dev/null +++ b/mastodon/src/main/res/drawable/fg_currency_input.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_donation_monthly.xml b/mastodon/src/main/res/drawable/ic_donation_monthly.xml new file mode 100644 index 000000000..2e796f13f --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_donation_monthly.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_favorite_18px.xml b/mastodon/src/main/res/drawable/ic_favorite_18px.xml new file mode 100644 index 000000000..c4066a427 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_favorite_18px.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_volunteer_activism_20px.xml b/mastodon/src/main/res/drawable/ic_volunteer_activism_20px.xml new file mode 100644 index 000000000..5f252b533 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_volunteer_activism_20px.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/layout/donation_banner.xml b/mastodon/src/main/res/layout/donation_banner.xml new file mode 100644 index 000000000..c25e4be12 --- /dev/null +++ b/mastodon/src/main/res/layout/donation_banner.xml @@ -0,0 +1,32 @@ + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/layout/fragment_timeline.xml b/mastodon/src/main/res/layout/fragment_timeline.xml index defa53bcf..e39c20575 100644 --- a/mastodon/src/main/res/layout/fragment_timeline.xml +++ b/mastodon/src/main/res/layout/fragment_timeline.xml @@ -58,5 +58,12 @@ android:text="@string/see_new_posts"/> + + \ No newline at end of file diff --git a/mastodon/src/main/res/layout/sheet_donation.xml b/mastodon/src/main/res/layout/sheet_donation.xml new file mode 100644 index 000000000..05cb1085a --- /dev/null +++ b/mastodon/src/main/res/layout/sheet_donation.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/colors_masterial.xml b/mastodon/src/main/res/values/colors_masterial.xml new file mode 100644 index 000000000..4221dff37 --- /dev/null +++ b/mastodon/src/main/res/values/colors_masterial.xml @@ -0,0 +1,336 @@ + + + + #5E5791 + #FFFFFF + #E5DEFF + #1A1249 + #5F5C71 + #FFFFFF + #E5DFF9 + #1C192C + #7B5265 + #FFFFFF + #FFD8E7 + #301121 + #BA1A1A + #FFFFFF + #FFDAD6 + #410002 + #FCF8FF + #1C1B20 + #FCF8FF + #1C1B20 + #E5E0EC + #47464F + #78767F + #C9C5D0 + #000000 + #313036 + #F4EFF7 + #C7BFFF + #E5DEFF + #1A1249 + #C7BFFF + #463F77 + #E5DFF9 + #1C192C + #C8C3DC + #474459 + #FFD8E7 + #301121 + #ECB8CE + #613B4D + #DDD8E0 + #FCF8FF + #FFFFFF + #F7F2FA + #F1ECF4 + #EBE6EF + #E5E1E9 + #423B73 + #FFFFFF + #746DA9 + #FFFFFF + #434055 + #FFFFFF + #767288 + #FFFFFF + #5D3749 + #FFFFFF + #94687B + #FFFFFF + #8C0009 + #FFFFFF + #DA342E + #FFFFFF + #FCF8FF + #1C1B20 + #FCF8FF + #1C1B20 + #E5E0EC + #44424B + #605E67 + #7C7983 + #000000 + #313036 + #F4EFF7 + #C7BFFF + #746DA9 + #FFFFFF + #5C558E + #FFFFFF + #767288 + #FFFFFF + #5D596F + #FFFFFF + #94687B + #FFFFFF + #795063 + #FFFFFF + #DDD8E0 + #FCF8FF + #FFFFFF + #F7F2FA + #F1ECF4 + #EBE6EF + #E5E1E9 + #211950 + #FFFFFF + #423B73 + #FFFFFF + #222033 + #FFFFFF + #434055 + #FFFFFF + #381728 + #FFFFFF + #5D3749 + #FFFFFF + #4E0002 + #FFFFFF + #8C0009 + #FFFFFF + #FCF8FF + #1C1B20 + #FCF8FF + #000000 + #E5E0EC + #24232B + #44424B + #44424B + #000000 + #313036 + #FFFFFF + #EFE9FF + #423B73 + #FFFFFF + #2C255B + #FFFFFF + #434055 + #FFFFFF + #2D2A3E + #FFFFFF + #5D3749 + #FFFFFF + #442233 + #FFFFFF + #DDD8E0 + #FCF8FF + #FFFFFF + #F7F2FA + #F1ECF4 + #EBE6EF + #E5E1E9 + #7A590C + #FFFFFF + #FFDEA6 + #271900 + #4F6628 + #FFFFFF + #D1ECA0 + #121F00 + #583E00 + #FFFFFF + #936F23 + #FFFFFF + #34490F + #FFFFFF + #657C3C + #FFFFFF + #2F1F00 + #FFFFFF + #583E00 + #FFFFFF + #182600 + #FFFFFF + #34490F + #FFFFFF + + + #C7BFFF + #2F285F + #463F77 + #E5DEFF + #C8C3DC + #312E41 + #474459 + #E5DFF9 + #ECB8CE + #482536 + #613B4D + #FFD8E7 + #FFB4AB + #690005 + #93000A + #FFDAD6 + #141318 + #E5E1E9 + #141318 + #E5E1E9 + #47464F + #C9C5D0 + #928F99 + #47464F + #000000 + #E5E1E9 + #313036 + #5E5791 + #E5DEFF + #1A1249 + #C7BFFF + #463F77 + #E5DFF9 + #1C192C + #C8C3DC + #474459 + #FFD8E7 + #301121 + #ECB8CE + #613B4D + #141318 + #3A383E + #0E0E13 + #1C1B20 + #201F25 + #2A292F + #35343A + #CCC4FF + #150B44 + #9189C7 + #000000 + #CDC8E1 + #161426 + #928EA5 + #000000 + #F1BCD2 + #2A0B1C + #B28498 + #000000 + #FFBAB1 + #370001 + #FF5449 + #000000 + #141318 + #E5E1E9 + #141318 + #FEF9FF + #47464F + #CDC9D4 + #A5A1AC + #85828C + #000000 + #E5E1E9 + #2A292F + #474179 + #E5DEFF + #0F053F + #C7BFFF + #352E65 + #E5DFF9 + #110F21 + #C8C3DC + #363447 + #FFD8E7 + #230716 + #ECB8CE + #4F2B3C + #141318 + #3A383E + #0E0E13 + #1C1B20 + #201F25 + #2A292F + #35343A + #FEF9FF + #000000 + #CCC4FF + #000000 + #FEF9FF + #000000 + #CDC8E1 + #000000 + #FFF9F9 + #000000 + #F1BCD2 + #000000 + #FFF9F9 + #000000 + #FFBAB1 + #000000 + #141318 + #E5E1E9 + #141318 + #FFFFFF + #47464F + #FEF9FF + #CDC9D4 + #CDC9D4 + #000000 + #E5E1E9 + #000000 + #292258 + #E9E3FF + #000000 + #CCC4FF + #150B44 + #E9E3FD + #000000 + #CDC8E1 + #161426 + #FFDEEA + #000000 + #F1BCD2 + #2A0B1C + #141318 + #3A383E + #0E0E13 + #1C1B20 + #201F25 + #2A292F + #35343A + #EDC06C + #412D00 + #5D4200 + #FFDEA6 + #B5D087 + #233600 + #384D12 + #D1ECA0 + #F1C470 + #201400 + #B28B3D + #000000 + #B9D48A + #0E1900 + #809956 + #000000 + #FFFAF7 + #000000 + #F1C470 + #000000 + #F5FFDC + #000000 + #B9D48A + #000000 + \ No newline at end of file diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml index 54bd3c2c0..70c888084 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -747,4 +747,9 @@ Notifications from %s Notifications from %s have been dismissed. %s will now appear in your notification list. + Dismiss + Just once + Monthly + Yearly + Currency \ No newline at end of file From 658177538b994a492d86959e6aed8b5b80d9a142 Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 15 Apr 2024 17:02:11 +0300 Subject: [PATCH 02/19] Fix dark theme --- .../joinmastodon/android/fragments/HomeTimelineFragment.java | 4 ++++ .../joinmastodon/android/ui/views/CurrencyAmountInput.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 1d60f042a..2310721a6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -264,6 +264,8 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD E.register(this); updateUpdateState(GithubSelfUpdater.getInstance().getState()); } + if(currentDonationCampaign!=null) + showDonationBanner(currentDonationCampaign); } @Override @@ -618,6 +620,8 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD if(GithubSelfUpdater.needSelfUpdating()){ E.unregister(this); } + donationBanner=null; + donationBannerDismissing=false; } private void updateUpdateState(GithubSelfUpdater.UpdateState state){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java index bbd98310b..6537220d9 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java @@ -294,7 +294,6 @@ public class CurrencyAmountInput extends LinearLayout implements CustomViewHelpe public CurrencySymbolSpan(Paint paint){ this.paint=new Paint(paint); this.paint.setTextSize(paint.getTextSize()*0.66f); - this.paint.setAlpha(77); } @Override @@ -304,6 +303,8 @@ public class CurrencyAmountInput extends LinearLayout implements CustomViewHelpe @Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint){ + this.paint.setColor(paint.getColor()); + this.paint.setAlpha(77); if(!symbolBeforeAmount) x+=dp(2); canvas.drawText(currentCurrency.symbol, x, top+dp(1.5f)-this.paint.ascent(), this.paint); From 977fc2483f412d616860aa218082a42cfbab89e7 Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 15 Apr 2024 17:46:03 +0300 Subject: [PATCH 03/19] Update "masterial" colors to correct ones --- .../src/main/res/values/colors_masterial.xml | 412 +++++++++--------- 1 file changed, 206 insertions(+), 206 deletions(-) diff --git a/mastodon/src/main/res/values/colors_masterial.xml b/mastodon/src/main/res/values/colors_masterial.xml index 4221dff37..88fce83a7 100644 --- a/mastodon/src/main/res/values/colors_masterial.xml +++ b/mastodon/src/main/res/values/colors_masterial.xml @@ -1,162 +1,162 @@ - #5E5791 + #4000DD #FFFFFF - #E5DEFF - #1A1249 - #5F5C71 + #6648FF + #FFFFFF + #5D51AF #FFFFFF - #E5DFF9 - #1C192C - #7B5265 + #B0A5FF + #220C73 + #810082 #FFFFFF - #FFD8E7 - #301121 + #B722B7 + #FFFFFF #BA1A1A #FFFFFF #FFDAD6 #410002 #FCF8FF - #1C1B20 + #1C1A25 #FCF8FF - #1C1B20 - #E5E0EC - #47464F - #78767F - #C9C5D0 + #1C1A25 + #E5DFF6 + #474557 + #787588 + #C9C4DA #000000 - #313036 - #F4EFF7 + #312F3B + #F3EEFE #C7BFFF #E5DEFF - #1A1249 + #180065 #C7BFFF - #463F77 - #E5DFF9 - #1C192C - #C8C3DC - #474459 - #FFD8E7 - #301121 - #ECB8CE - #613B4D - #DDD8E0 + #4000DC + #E5DEFF + #180065 + #C7BFFF + #453895 + #FFD7F6 + #380039 + #FFAAF5 + #800082 + #DCD8E7 #FCF8FF #FFFFFF - #F7F2FA - #F1ECF4 - #EBE6EF - #E5E1E9 - #423B73 + #F6F1FF + #F1EBFB + #EBE6F6 + #E5E0F0 + #3C00D1 #FFFFFF - #746DA9 + #6648FF #FFFFFF - #434055 + #413391 #FFFFFF - #767288 + #7368C7 #FFFFFF - #5D3749 + #7A007B #FFFFFF - #94687B + #B722B7 #FFFFFF #8C0009 #FFFFFF #DA342E #FFFFFF #FCF8FF - #1C1B20 + #1C1A25 #FCF8FF - #1C1B20 - #E5E0EC - #44424B - #605E67 - #7C7983 + #1C1A25 + #E5DFF6 + #434153 + #605D70 + #7C788C #000000 - #313036 - #F4EFF7 + #312F3B + #F3EEFE #C7BFFF - #746DA9 + #7058FF #FFFFFF - #5C558E + #552BFB #FFFFFF - #767288 + #7368C7 #FFFFFF - #5D596F + #5A4EAC #FFFFFF - #94687B + #C330C2 #FFFFFF - #795063 + #A400A6 #FFFFFF - #DDD8E0 + #DCD8E7 #FCF8FF #FFFFFF - #F7F2FA - #F1ECF4 - #EBE6EF - #E5E1E9 - #211950 + #F6F1FF + #F1EBFB + #EBE6F6 + #E5E0F0 + #1E0077 #FFFFFF - #423B73 + #3C00D1 #FFFFFF - #222033 + #1F0671 #FFFFFF - #434055 + #413391 #FFFFFF - #381728 + #430044 #FFFFFF - #5D3749 + #7A007B #FFFFFF #4E0002 #FFFFFF #8C0009 #FFFFFF #FCF8FF - #1C1B20 + #1C1A25 #FCF8FF #000000 - #E5E0EC - #24232B - #44424B - #44424B + #E5DFF6 + #242232 + #434153 + #434153 #000000 - #313036 + #312F3B #FFFFFF #EFE9FF - #423B73 + #3C00D1 #FFFFFF - #2C255B + #280094 #FFFFFF - #434055 + #413391 #FFFFFF - #2D2A3E + #2A197A #FFFFFF - #5D3749 + #7A007B #FFFFFF - #442233 + #550056 #FFFFFF - #DDD8E0 + #DCD8E7 #FCF8FF #FFFFFF - #F7F2FA - #F1ECF4 - #EBE6EF - #E5E1E9 - #7A590C + #F6F1FF + #F1EBFB + #EBE6F6 + #E5E0F0 + #7B5800 #FFFFFF - #FFDEA6 - #271900 - #4F6628 + #FFC758 + #503800 + #476800 #FFFFFF - #D1ECA0 - #121F00 + #CAFF71 + #3A5700 #583E00 #FFFFFF - #936F23 + #986D00 #FFFFFF - #34490F + #314A00 #FFFFFF - #657C3C + #588000 #FFFFFF #2F1F00 #FFFFFF @@ -164,173 +164,173 @@ #FFFFFF #182600 #FFFFFF - #34490F + #314A00 #FFFFFF #C7BFFF - #2F285F - #463F77 - #E5DEFF - #C8C3DC - #312E41 - #474459 - #E5DFF9 - #ECB8CE - #482536 - #613B4D - #FFD8E7 + #2B009E + #4D1AF4 + #FAF5FF + #C7BFFF + #2E1E7E + #3D308E + #D6CFFF + #FFAAF5 + #5B005C + #970099 + #FFF5F9 #FFB4AB #690005 #93000A #FFDAD6 - #141318 - #E5E1E9 - #141318 - #E5E1E9 - #47464F - #C9C5D0 - #928F99 - #47464F + #13121D + #E5E0F0 + #13121D + #E5E0F0 + #474557 + #C9C4DA + #928EA3 + #474557 #000000 - #E5E1E9 - #313036 - #5E5791 + #E5E0F0 + #312F3B + #582FFE #E5DEFF - #1A1249 + #180065 #C7BFFF - #463F77 - #E5DFF9 - #1C192C - #C8C3DC - #474459 - #FFD8E7 - #301121 - #ECB8CE - #613B4D - #141318 - #3A383E - #0E0E13 - #1C1B20 - #201F25 - #2A292F - #35343A + #4000DC + #E5DEFF + #180065 + #C7BFFF + #453895 + #FFD7F6 + #380039 + #FFAAF5 + #800082 + #13121D + #3A3844 + #0E0D17 + #1C1A25 + #201E29 + #2A2934 + #35333F #CCC4FF - #150B44 - #9189C7 + #130056 + #8F7FFF #000000 - #CDC8E1 - #161426 - #928EA5 + #CCC4FF + #130056 + #9084E6 #000000 - #F1BCD2 - #2A0B1C - #B28498 + #FFB1F5 + #2F0030 + #E552E1 #000000 #FFBAB1 #370001 #FF5449 #000000 - #141318 - #E5E1E9 - #141318 + #13121D + #E5E0F0 + #13121D #FEF9FF - #47464F - #CDC9D4 - #A5A1AC - #85828C + #474557 + #CDC8DE + #A4A0B5 + #848195 #000000 - #E5E1E9 - #2A292F - #474179 + #E5E0F0 + #2A2934 + #4100DF #E5DEFF - #0F053F + #0F0048 #C7BFFF - #352E65 - #E5DFF9 - #110F21 - #C8C3DC - #363447 - #FFD8E7 - #230716 - #ECB8CE - #4F2B3C - #141318 - #3A383E - #0E0E13 - #1C1B20 - #201F25 - #2A292F - #35343A + #3000AE + #E5DEFF + #0F0048 + #C7BFFF + #342584 + #FFD7F6 + #260027 + #FFAAF5 + #650066 + #13121D + #3A3844 + #0E0D17 + #1C1A25 + #201E29 + #2A2934 + #35333F #FEF9FF #000000 #CCC4FF #000000 #FEF9FF #000000 - #CDC8E1 + #CCC4FF #000000 - #FFF9F9 + #FFF9FA #000000 - #F1BCD2 + #FFB1F5 #000000 #FFF9F9 #000000 #FFBAB1 #000000 - #141318 - #E5E1E9 - #141318 + #13121D + #E5E0F0 + #13121D #FFFFFF - #47464F + #474557 #FEF9FF - #CDC9D4 - #CDC9D4 + #CDC8DE + #CDC8DE #000000 - #E5E1E9 + #E5E0F0 #000000 - #292258 + #25008C #E9E3FF #000000 #CCC4FF - #150B44 - #E9E3FD + #130056 + #E9E3FF #000000 - #CDC8E1 - #161426 - #FFDEEA + #CCC4FF + #130056 + #FFDDF6 #000000 - #F1BCD2 - #2A0B1C - #141318 - #3A383E - #0E0E13 - #1C1B20 - #201F25 - #2A292F - #35343A - #EDC06C + #FFB1F5 + #2F0030 + #13121D + #3A3844 + #0E0D17 + #1C1A25 + #201E29 + #2A2934 + #35333F + #FFEBCE #412D00 - #5D4200 - #FFDEA6 - #B5D087 + #F9B928 + #463100 + #FFFFFF #233600 - #384D12 - #D1ECA0 - #F1C470 - #201400 - #B28B3D - #000000 - #B9D48A - #0E1900 - #809956 - #000000 + #A5E820 + #2E4600 + #FFEBCE + #412D00 + #F9B928 + #150C00 + #FFFFFF + #233600 + #A5E820 + #162300 #FFFAF7 #000000 - #F1C470 + #FFC03B #000000 - #F5FFDC + #FFFFFF #000000 - #B9D48A + #A5E820 #000000 \ No newline at end of file From 104896ae1b89b11dd7fd66a39ffdb1f23a0b73ae Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 15 Apr 2024 20:05:12 +0300 Subject: [PATCH 04/19] Custom layout for suggested amount buttons --- mastodon/build.gradle | 2 +- .../android/ui/sheets/DonationSheet.java | 68 +++++++++++++++++-- .../src/main/res/layout/sheet_donation.xml | 3 +- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/mastodon/build.gradle b/mastodon/build.gradle index c7148d802..3dbf0d6ca 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -13,7 +13,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 33 - versionCode 94 + versionCode 95 versionName "2.5.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java index 4fa4ab52d..f14140cdc 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java @@ -5,6 +5,7 @@ import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; +import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -24,6 +25,7 @@ import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.views.CurrencyAmountInput; import java.text.NumberFormat; +import java.util.Arrays; import java.util.Currency; import java.util.List; import java.util.Locale; @@ -31,6 +33,7 @@ import java.util.stream.Collectors; import androidx.annotation.NonNull; import me.grishka.appkit.Nav; +import me.grishka.appkit.utils.CustomViewHelper; import me.grishka.appkit.utils.V; import me.grishka.appkit.views.BottomSheet; @@ -128,7 +131,7 @@ public class DonationSheet extends BottomSheet{ button=findViewById(R.id.button); buttonText=findViewById(R.id.button_text); - LinearLayout suggestedAmounts=findViewById(R.id.suggested_amounts); + ViewGroup suggestedAmounts=findViewById(R.id.suggested_amounts); for(int i=0;iopenWebView()); + + Arrays.stream(getCurrentSuggestedAmounts(campaign.defaultCurrency)).min().ifPresent(amountField::setAmount); } @Override @@ -285,4 +288,61 @@ public class DonationSheet extends BottomSheet{ MONTHLY, YEARLY } + + public static class SuggestedAmountsLayout extends ViewGroup implements CustomViewHelper{ + private int visibleChildCount; + private static final int H_GAP=24; + private static final int V_GAP=8; + private static final int ROW_HEIGHT=32; + + public SuggestedAmountsLayout(Context context){ + this(context, null); + } + + public SuggestedAmountsLayout(Context context, AttributeSet attrs){ + this(context, attrs, 0); + } + + public SuggestedAmountsLayout(Context context, AttributeSet attrs, int defStyle){ + super(context, attrs, defStyle); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ + visibleChildCount=0; + for(int i=0;i4 ? dp(ROW_HEIGHT*2+V_GAP) : dp(ROW_HEIGHT)); + int buttonsPerRow=visibleChildCount>4 ? 3 : visibleChildCount; + int buttonWidth=(width-dp(H_GAP)*(buttonsPerRow-1))/buttonsPerRow; + for(int i=0;i4 ? 3 : visibleChildCount; + int buttonWidth=(width-dp(H_GAP)*(buttonsPerRow-1))/buttonsPerRow; + for(int i=0;i - Date: Thu, 18 Apr 2024 02:43:19 +0300 Subject: [PATCH 05/19] Add arrows to currency selector --- .../android/ui/views/CurrencyAmountInput.java | 3 +++ .../drawable/ic_unfold_more_wght600_15pt_8x20px.xml | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 mastodon/src/main/res/drawable/ic_unfold_more_wght600_15pt_8x20px.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java index 6537220d9..bae0f93c8 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/CurrencyAmountInput.java @@ -78,6 +78,9 @@ public class CurrencyAmountInput extends LinearLayout implements CustomViewHelpe currencyBtn.setMinimumWidth(0); currencyBtn.setMinWidth(0); currencyBtn.setOnClickListener(v->showCurrencySelector()); + currencyBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_unfold_more_wght600_15pt_8x20px, 0, 0, 0); + currencyBtn.setCompoundDrawableTintList(currencyBtn.getTextColors()); + currencyBtn.setCompoundDrawablePadding(dp(4)); addView(currencyBtn, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); edit=new ActualEditText(context); diff --git a/mastodon/src/main/res/drawable/ic_unfold_more_wght600_15pt_8x20px.xml b/mastodon/src/main/res/drawable/ic_unfold_more_wght600_15pt_8x20px.xml new file mode 100644 index 000000000..2e09a03dd --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_unfold_more_wght600_15pt_8x20px.xml @@ -0,0 +1,11 @@ + + + + + From b5aa1a459816195d48cf3dd8f6c77c0c1187c9b1 Mon Sep 17 00:00:00 2001 From: Grishka Date: Thu, 18 Apr 2024 02:55:07 +0300 Subject: [PATCH 06/19] Cache donation campaign responses --- .../android/api/MastodonAPIController.java | 10 ++++++++++ .../joinmastodon/android/api/MastodonAPIRequest.java | 5 +++++ .../api/requests/catalog/GetDonationCampaigns.java | 1 + 3 files changed, 16 insertions(+) diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIController.java b/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIController.java index 384378dfe..a2d2a320a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIController.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIController.java @@ -12,10 +12,12 @@ import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; import org.joinmastodon.android.BuildConfig; +import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.api.gson.IsoInstantTypeAdapter; import org.joinmastodon.android.api.gson.IsoLocalDateTypeAdapter; import org.joinmastodon.android.api.session.AccountSession; +import java.io.File; import java.io.IOException; import java.io.Reader; import java.time.Instant; @@ -29,6 +31,8 @@ import java.util.concurrent.TimeUnit; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import me.grishka.appkit.utils.WorkerThread; +import okhttp3.Cache; +import okhttp3.CacheControl; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; @@ -49,8 +53,11 @@ public class MastodonAPIController{ .connectTimeout(60, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) + .cache(new Cache(new File(MastodonApp.context.getCacheDir(), "http"), 10*1024*1024)) .build(); + private static final CacheControl NO_CACHE_WHATSOEVER=new CacheControl.Builder().noCache().noStore().build(); + private AccountSession session; static{ @@ -80,6 +87,9 @@ public class MastodonAPIController{ if(token!=null) builder.header("Authorization", "Bearer "+token); + if(!req.cacheable) + builder.cacheControl(NO_CACHE_WHATSOEVER); + if(req.headers!=null){ for(Map.Entry header:req.headers.entrySet()){ builder.header(header.getKey(), header.getValue()); diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIRequest.java b/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIRequest.java index f308d8720..c780bbcf1 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIRequest.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/MastodonAPIRequest.java @@ -46,6 +46,7 @@ public abstract class MastodonAPIRequest extends APIRequest{ boolean canceled; Map headers; long timeout; + boolean cacheable; private ProgressDialog progressDialog; protected boolean removeUnsupportedItems; @@ -132,6 +133,10 @@ public abstract class MastodonAPIRequest extends APIRequest{ this.timeout=timeout; } + protected void setCacheable(){ + cacheable=true; + } + protected String getPathPrefix(){ return "/api/v1"; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java index e6f018efa..937aa6cc2 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java @@ -12,6 +12,7 @@ public class GetDonationCampaigns extends MastodonAPIRequest{ super(HttpMethod.GET, null, DonationCampaign.class); this.locale=locale; this.seed=seed; + setCacheable(); } @Override From d0d899c73d6a74ab634b29312c1b5b435a3ef12b Mon Sep 17 00:00:00 2001 From: Grishka Date: Thu, 18 Apr 2024 02:58:42 +0300 Subject: [PATCH 07/19] Check account age for donation eligibility --- .../org/joinmastodon/android/api/session/AccountSession.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java index 55cdac05f..1276bf81e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java @@ -33,6 +33,8 @@ import org.joinmastodon.android.model.TimelineMarkers; import org.joinmastodon.android.model.Token; import org.joinmastodon.android.utils.ObjectIdComparator; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -43,6 +45,7 @@ import me.grishka.appkit.api.ErrorResponse; public class AccountSession{ private static final String TAG="AccountSession"; + private static final int MIN_DAYS_ACCOUNT_AGE_FOR_DONATIONS=28; public Token token; public Account self; @@ -277,7 +280,7 @@ public class AccountSession{ } public boolean isEligibleForDonations(){ - return "mastodon.social".equalsIgnoreCase(domain) || "mastodon.online".equalsIgnoreCase(domain); + return ("mastodon.social".equalsIgnoreCase(domain) || "mastodon.online".equalsIgnoreCase(domain)) && self.createdAt.isBefore(Instant.now().minus(MIN_DAYS_ACCOUNT_AGE_FOR_DONATIONS, ChronoUnit.DAYS)); } public int getDonationSeed(){ From 31af0251ea136df6a9662c25353a687329219ddc Mon Sep 17 00:00:00 2001 From: Grishka Date: Thu, 18 Apr 2024 02:59:45 +0300 Subject: [PATCH 08/19] Update endpoint --- mastodon/build.gradle | 2 +- .../android/api/requests/catalog/GetDonationCampaigns.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 3dbf0d6ca..0129f1144 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -13,7 +13,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 33 - versionCode 95 + versionCode 96 versionName "2.5.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java index 937aa6cc2..0291d2930 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java @@ -20,7 +20,7 @@ public class GetDonationCampaigns extends MastodonAPIRequest{ Uri.Builder builder=new Uri.Builder() .scheme("https") .authority("api.joinmastodon.org") - .path("/donations/campaigns") + .path("/v1/donations/campaigns/active") .appendQueryParameter("platform", "android") .appendQueryParameter("locale", locale) .appendQueryParameter("seed", seed); From c94e1f939a08597b6f9d1333feaf7953eea67d6f Mon Sep 17 00:00:00 2001 From: Grishka Date: Tue, 21 May 2024 20:17:46 +0300 Subject: [PATCH 09/19] Add staging environment toggle --- mastodon/build.gradle | 2 +- .../requests/catalog/GetDonationCampaigns.java | 7 +++++++ .../fragments/HomeTimelineFragment.java | 9 +++++++-- .../settings/SettingsDebugFragment.java | 18 +++++++++++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 18684e10b..3145761ad 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -13,7 +13,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 33 - versionCode 97 + versionCode 98 versionName "2.5.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java index 0291d2930..ebeda3f7d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/catalog/GetDonationCampaigns.java @@ -7,6 +7,7 @@ import org.joinmastodon.android.model.donations.DonationCampaign; public class GetDonationCampaigns extends MastodonAPIRequest{ private final String locale, seed; + private boolean staging; public GetDonationCampaigns(String locale, String seed){ super(HttpMethod.GET, null, DonationCampaign.class); @@ -15,6 +16,10 @@ public class GetDonationCampaigns extends MastodonAPIRequest{ setCacheable(); } + public void setStaging(boolean staging){ + this.staging=staging; + } + @Override public Uri getURL(){ Uri.Builder builder=new Uri.Builder() @@ -24,6 +29,8 @@ public class GetDonationCampaigns extends MastodonAPIRequest{ .appendQueryParameter("platform", "android") .appendQueryParameter("locale", locale) .appendQueryParameter("seed", seed); + if(staging) + builder.appendQueryParameter("environment", "staging"); return builder.build(); } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 2310721a6..bc19dec60 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -5,6 +5,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; +import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; import android.text.SpannableStringBuilder; @@ -32,6 +33,7 @@ import android.widget.Toolbar; import com.squareup.otto.Subscribe; +import org.joinmastodon.android.BuildConfig; import org.joinmastodon.android.E; import org.joinmastodon.android.R; import org.joinmastodon.android.api.MastodonAPIRequest; @@ -110,8 +112,11 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD // TODO how often do we do this request? Maybe cache something somewhere? if(AccountSessionManager.get(accountID).isEligibleForDonations()){ - new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed())) - .setCallback(new Callback<>(){ + GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed())); + if(BuildConfig.DEBUG && getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false)){ + req.setStaging(true); + } + req.setCallback(new Callback<>(){ @Override public void onSuccess(DonationCampaign result){ if(result==null) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java index 35b9554d4..ce6e0add9 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsDebugFragment.java @@ -1,5 +1,7 @@ package org.joinmastodon.android.fragments.settings; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; import android.widget.Toast; @@ -9,6 +11,7 @@ import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.HomeFragment; import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment; +import org.joinmastodon.android.model.viewmodel.CheckableListItem; import org.joinmastodon.android.model.viewmodel.ListItem; import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper; import org.joinmastodon.android.updater.GithubSelfUpdater; @@ -18,6 +21,8 @@ import java.util.List; import me.grishka.appkit.Nav; public class SettingsDebugFragment extends BaseSettingsFragment{ + private CheckableListItem donationsStagingItem; + @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); @@ -29,7 +34,8 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ resetUpdateItem=new ListItem<>("Reset self-updater", null, this::onResetUpdaterClick), new ListItem<>("Reset search info banners", null, this::onResetDiscoverBannersClick), new ListItem<>("Reset pre-reply sheets", null, this::onResetPreReplySheetsClick), - new ListItem<>("Clear dismissed donation campaigns", null, this::onClearDismissedCampaignsClick) + new ListItem<>("Clear dismissed donation campaigns", null, this::onClearDismissedCampaignsClick), + donationsStagingItem=new CheckableListItem<>("Use staging environment for donations", null, CheckableListItem.Style.SWITCH, getPrefs().getBoolean("donationsStaging", false), this::toggleCheckableItem) )); if(!GithubSelfUpdater.needSelfUpdating()){ resetUpdateItem.isEnabled=selfUpdateItem.isEnabled=false; @@ -40,6 +46,12 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ @Override protected void doLoadData(int offset, int count){} + @Override + public void onStop(){ + super.onStop(); + getPrefs().edit().putBoolean("donationsStaging", donationsStagingItem.checked).apply(); + } + private void onTestEmailConfirmClick(ListItem item){ AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID); sess.activated=false; @@ -81,4 +93,8 @@ public class SettingsDebugFragment extends BaseSettingsFragment{ args.putString("account", accountID); Nav.goClearingStack(getActivity(), HomeFragment.class, args); } + + private SharedPreferences getPrefs(){ + return getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE); + } } From 4e1bf80e123a3684657465e6ed566875c2b29c6d Mon Sep 17 00:00:00 2001 From: Grishka Date: Thu, 13 Jun 2024 17:08:24 +0300 Subject: [PATCH 10/19] Make WebViewFragment work with predictive back --- .../android/fragments/WebViewFragment.java | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java index 6146abc7c..7cd3022a7 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/WebViewFragment.java @@ -1,6 +1,7 @@ package org.joinmastodon.android.fragments; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -10,14 +11,18 @@ import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; +import org.joinmastodon.android.BuildConfig; import org.joinmastodon.android.api.MastodonErrorResponse; import me.grishka.appkit.Nav; import me.grishka.appkit.fragments.LoaderFragment; -import me.grishka.appkit.fragments.OnBackPressedListener; -public abstract class WebViewFragment extends LoaderFragment implements OnBackPressedListener{ +public abstract class WebViewFragment extends LoaderFragment{ + private static final String TAG="WebViewFragment"; + protected WebView webView; + private Runnable backCallback=this::onGoBack; + private boolean backCallbackSet; @Override public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ @@ -31,18 +36,28 @@ public abstract class WebViewFragment extends LoaderFragment implements OnBackPr webView.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url){ + if(BuildConfig.DEBUG){ + Log.d(TAG, "onPageFinished: "+url); + } dataLoaded(); + updateBackCallback(); } @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){ onError(new MastodonErrorResponse(error.getDescription().toString(), -1, null)); + updateBackCallback(); } @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request){ return WebViewFragment.this.shouldOverrideUrlLoading(request); } + + @Override + public void doUpdateVisitedHistory(WebView view, String url, boolean isReload){ + updateBackCallback(); + } }); webView.getSettings().setJavaScriptEnabled(true); return webView; @@ -58,19 +73,28 @@ public abstract class WebViewFragment extends LoaderFragment implements OnBackPr webView.reload(); } - @Override - public boolean onBackPressed(){ - if(webView.canGoBack()){ - webView.goBack(); - return true; - } - return false; - } - @Override public void onToolbarNavigationClick(){ Nav.finish(this); } + private void updateBackCallback(){ + boolean canGoBack=webView.canGoBack(); + if(canGoBack!=backCallbackSet){ + if(canGoBack){ + addBackCallback(backCallback); + backCallbackSet=true; + }else{ + removeBackCallback(backCallback); + backCallbackSet=false; + } + } + } + + private void onGoBack(){ + if(webView.canGoBack()) + webView.goBack(); + } + protected abstract boolean shouldOverrideUrlLoading(WebResourceRequest req); } From 6270a3dfdcdcf14ad2d8feabc4167c08a6206b3b Mon Sep 17 00:00:00 2001 From: Grishka Date: Thu, 13 Jun 2024 18:58:24 +0300 Subject: [PATCH 11/19] Donations improvements --- mastodon/build.gradle | 2 +- mastodon/src/main/AndroidManifest.xml | 1 + .../android/DonationFragmentActivity.java | 29 ++++++ .../fragments/DonationWebViewFragment.java | 66 ++++++++++---- .../fragments/HomeTimelineFragment.java | 29 +++++- .../android/ui/sheets/DonationSheet.java | 13 +-- .../ui/sheets/DonationSuccessfulSheet.java | 36 ++++++++ mastodon/src/main/res/anim/fragment_enter.xml | 13 +++ mastodon/src/main/res/anim/fragment_exit.xml | 13 +++ mastodon/src/main/res/anim/no_op_300ms.xml | 4 + .../donation_successful_art.webp | Bin 0 -> 68154 bytes .../main/res/drawable/ic_campaign_20px.xml | 9 ++ .../interpolator-v21/cubic_bezier_default.xml | 3 + .../res/layout/sheet_donation_success.xml | 83 ++++++++++++++++++ mastodon/src/main/res/values-hdpi/misc.xml | 4 + mastodon/src/main/res/values-tvdpi/misc.xml | 4 + mastodon/src/main/res/values-xhdpi/misc.xml | 4 + mastodon/src/main/res/values-xxhdpi/misc.xml | 4 + mastodon/src/main/res/values-xxxhdpi/misc.xml | 4 + mastodon/src/main/res/values/misc.xml | 4 + mastodon/src/main/res/values/strings.xml | 3 + 21 files changed, 306 insertions(+), 22 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/DonationFragmentActivity.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSuccessfulSheet.java create mode 100644 mastodon/src/main/res/anim/fragment_enter.xml create mode 100644 mastodon/src/main/res/anim/fragment_exit.xml create mode 100644 mastodon/src/main/res/anim/no_op_300ms.xml create mode 100644 mastodon/src/main/res/drawable-nodpi/donation_successful_art.webp create mode 100644 mastodon/src/main/res/drawable/ic_campaign_20px.xml create mode 100644 mastodon/src/main/res/interpolator-v21/cubic_bezier_default.xml create mode 100644 mastodon/src/main/res/layout/sheet_donation_success.xml create mode 100644 mastodon/src/main/res/values-hdpi/misc.xml create mode 100644 mastodon/src/main/res/values-tvdpi/misc.xml create mode 100644 mastodon/src/main/res/values-xhdpi/misc.xml create mode 100644 mastodon/src/main/res/values-xxhdpi/misc.xml create mode 100644 mastodon/src/main/res/values-xxxhdpi/misc.xml create mode 100644 mastodon/src/main/res/values/misc.xml diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 8fc25ecc5..0328eaaee 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -13,7 +13,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 33 - versionCode 99 + versionCode 100 versionName "2.5.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mastodon/src/main/AndroidManifest.xml b/mastodon/src/main/AndroidManifest.xml index 7a97cfcee..122e86a72 100644 --- a/mastodon/src/main/AndroidManifest.xml +++ b/mastodon/src/main/AndroidManifest.xml @@ -79,6 +79,7 @@ + diff --git a/mastodon/src/main/java/org/joinmastodon/android/DonationFragmentActivity.java b/mastodon/src/main/java/org/joinmastodon/android/DonationFragmentActivity.java new file mode 100644 index 000000000..5a72cd463 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/DonationFragmentActivity.java @@ -0,0 +1,29 @@ +package org.joinmastodon.android; + +import android.os.Bundle; + +import org.joinmastodon.android.fragments.DonationWebViewFragment; + +import androidx.annotation.Nullable; +import me.grishka.appkit.FragmentStackActivity; + +// This exists because our designer wanted to avoid extra sheet showing/hiding animations. +// This is the only way to show a fragment on top of a sheet without having to rewrite way too many things. +public class DonationFragmentActivity extends FragmentStackActivity{ + @Override + protected void onCreate(@Nullable Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + if(savedInstanceState==null){ + DonationWebViewFragment fragment=new DonationWebViewFragment(); + fragment.setArguments(getIntent().getBundleExtra("fragmentArgs")); + showFragment(fragment); + overridePendingTransition(R.anim.fragment_enter, R.anim.no_op_300ms); + } + } + + @Override + public void finish(){ + super.finish(); + overridePendingTransition(0, R.anim.fragment_exit); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java index 6ca545c47..1770ccf3c 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/DonationWebViewFragment.java @@ -1,14 +1,20 @@ package org.joinmastodon.android.fragments; +import android.app.Activity; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.webkit.WebResourceRequest; +import org.joinmastodon.android.BuildConfig; import org.joinmastodon.android.E; import org.joinmastodon.android.R; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.DismissDonationCampaignBannerEvent; import org.joinmastodon.android.ui.M3AlertDialogBuilder; +import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet; import java.util.Objects; @@ -18,6 +24,14 @@ public class DonationWebViewFragment extends WebViewFragment{ public static final String SUCCESS_URL="https://sponsor.joinmastodon.org/donation/success"; public static final String FAILURE_URL="https://sponsor.joinmastodon.org/donation/failure"; + @Override + public void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + if(BuildConfig.DEBUG){ + setHasOptionsMenu(true); + } + } + @Override public void onViewCreated(View view, Bundle savedInstanceState){ super.onViewCreated(view, savedInstanceState); @@ -28,25 +42,47 @@ public class DonationWebViewFragment extends WebViewFragment{ protected boolean shouldOverrideUrlLoading(WebResourceRequest req){ String url=req.getUrl().buildUpon().clearQuery().fragment(null).build().toString(); if(url.equalsIgnoreCase(SUCCESS_URL)){ - new M3AlertDialogBuilder(getActivity()) - .setTitle("Success") - .setMessage("Some sort of UI that would tell the user that their payment was successful") - .setPositiveButton(R.string.ok, null) - .setOnDismissListener(dlg->Nav.finish(this)) - .show(); - String campaignID=getArguments().getString("campaignID"); - AccountSessionManager.getInstance().markDonationCampaignAsDismissed(campaignID); - E.post(new DismissDonationCampaignBannerEvent(campaignID)); + onSuccess(); return true; }else if(url.equalsIgnoreCase(FAILURE_URL)){ - new M3AlertDialogBuilder(getActivity()) - .setTitle("Failure") - .setMessage("Some sort of UI that would tell the user that their payment didn't go through") - .setPositiveButton(R.string.ok, null) - .setOnDismissListener(dlg->Nav.finish(this)) - .show(); + onFailure(); return true; } return false; } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ + super.onCreateOptionsMenu(menu, inflater); + if(BuildConfig.DEBUG){ + menu.add(0, 0, 0, "Simulate success"); + menu.add(0, 1, 0, "Simulate failure"); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item){ + if(item.getItemId()==0) + onSuccess(); + else if(item.getItemId()==1) + onFailure(); + return super.onOptionsItemSelected(item); + } + + private void onFailure(){ + new M3AlertDialogBuilder(getActivity()) + .setTitle("Failure") + .setMessage("Some sort of UI that would tell the user that their payment didn't go through") + .setPositiveButton(R.string.ok, null) + .setOnDismissListener(dlg->Nav.finish(this)) + .show(); + } + + private void onSuccess(){ + String campaignID=getArguments().getString("campaignID"); + AccountSessionManager.getInstance().markDonationCampaignAsDismissed(campaignID); + E.post(new DismissDonationCampaignBannerEvent(campaignID)); + getActivity().setResult(Activity.RESULT_OK); + getActivity().finish(); + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index bc19dec60..d43221358 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -6,6 +6,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.text.SpannableStringBuilder; @@ -55,6 +56,7 @@ import org.joinmastodon.android.model.donations.DonationCampaign; import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.StatusDisplayItem; import org.joinmastodon.android.ui.sheets.DonationSheet; +import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet; import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper; import org.joinmastodon.android.ui.viewcontrollers.HomeTimelineMenuController; import org.joinmastodon.android.ui.viewcontrollers.ToolbarDropdownMenuController; @@ -77,8 +79,11 @@ import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.utils.CubicBezierInterpolator; import me.grishka.appkit.utils.MergeRecyclerAdapter; import me.grishka.appkit.utils.V; +import me.grishka.appkit.views.BottomSheet; public class HomeTimelineFragment extends StatusListFragment implements ToolbarDropdownMenuController.HostFragment{ + private static final int DONATION_RESULT=211; + private ImageButton fab; private LinearLayout listsDropdown; private FixedAspectRatioImageView listsDropdownArrow; @@ -100,6 +105,7 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD private String maxID; private String lastSavedMarkerID; private DonationCampaign currentDonationCampaign; + private BottomSheet donationSheet; public HomeTimelineFragment(){ setListLayoutId(R.layout.fragment_timeline); @@ -129,6 +135,13 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD }) .execNoAuth(""); } + E.register(this); + } + + @Override + public void onDestroy(){ + super.onDestroy(); + E.unregister(this); } @Override @@ -639,6 +652,7 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD updateUpdateState(ev.state); } + @Subscribe public void onDismissDonationCampaignBanner(DismissDonationCampaignBannerEvent ev){ if(currentDonationCampaign!=null && ev.campaignID.equals(currentDonationCampaign.id)){ dismissDonationBanner(); @@ -699,6 +713,17 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD super.onDataLoaded(d, more); } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data){ + if(requestCode==DONATION_RESULT){ + if(donationSheet!=null) + donationSheet.dismissWithoutAnimation(); + if(resultCode==Activity.RESULT_OK){ + new DonationSuccessfulSheet(getActivity(), accountID).showWithoutAnimation(); + } + } + } + private String getCurrentListTitle(){ return switch(listMode){ case FOLLOWING -> getString(R.string.timeline_following); @@ -773,7 +798,9 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD } private void openDonationSheet(){ - new DonationSheet(getActivity(), currentDonationCampaign, accountID).show(); + donationSheet=new DonationSheet(getActivity(), currentDonationCampaign, accountID, intent->startActivityForResult(intent, DONATION_RESULT)); + donationSheet.setOnDismissListener(dialog->donationSheet=null); + donationSheet.show(); } private enum ListMode{ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java index f14140cdc..ee5f84984 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSheet.java @@ -2,6 +2,7 @@ package org.joinmastodon.android.ui.sheets; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; @@ -11,11 +12,11 @@ import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; +import org.joinmastodon.android.DonationFragmentActivity; import org.joinmastodon.android.R; import org.joinmastodon.android.fragments.DonationWebViewFragment; import org.joinmastodon.android.model.donations.DonationCampaign; @@ -29,10 +30,10 @@ import java.util.Arrays; import java.util.Currency; import java.util.List; import java.util.Locale; +import java.util.function.Consumer; import java.util.stream.Collectors; import androidx.annotation.NonNull; -import me.grishka.appkit.Nav; import me.grishka.appkit.utils.CustomViewHelper; import me.grishka.appkit.utils.V; import me.grishka.appkit.views.BottomSheet; @@ -40,6 +41,7 @@ import me.grishka.appkit.views.BottomSheet; public class DonationSheet extends BottomSheet{ private final DonationCampaign campaign; private final String accountID; + private final Consumer startCallback; private DonationFrequency frequency=DonationFrequency.MONTHLY; private View onceTab, monthlyTab, yearlyTab; @@ -50,11 +52,12 @@ public class DonationSheet extends BottomSheet{ private TextView buttonText; private Activity activity; - public DonationSheet(@NonNull Activity activity, DonationCampaign campaign, String accountID){ + public DonationSheet(@NonNull Activity activity, DonationCampaign campaign, String accountID, Consumer startCallback){ super(activity); this.campaign=campaign; this.accountID=accountID; this.activity=activity; + this.startCallback=startCallback; Context context=activity; View content=context.getSystemService(LayoutInflater.class).inflate(R.layout.sheet_donation, null); @@ -246,8 +249,8 @@ public class DonationSheet extends BottomSheet{ args.putString("url", builder.build().toString()); args.putString("account", accountID); args.putString("campaignID", campaign.id); - Nav.go(activity, DonationWebViewFragment.class, args); - dismiss(); + args.putBoolean("_can_go_back", true); + startCallback.accept(new Intent(activity, DonationFragmentActivity.class).putExtra("fragmentArgs", args)); } private static long getMinimumChargeAmount(String currency){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSuccessfulSheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSuccessfulSheet.java new file mode 100644 index 000000000..cce552032 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/sheets/DonationSuccessfulSheet.java @@ -0,0 +1,36 @@ +package org.joinmastodon.android.ui.sheets; + +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.fragments.ComposeFragment; +import org.joinmastodon.android.ui.utils.UiUtils; + +import androidx.annotation.NonNull; +import me.grishka.appkit.Nav; +import me.grishka.appkit.views.BottomSheet; + +public class DonationSuccessfulSheet extends BottomSheet{ + + public DonationSuccessfulSheet(@NonNull Context context, @NonNull String accountID){ + super(context); + View content=context.getSystemService(LayoutInflater.class).inflate(R.layout.sheet_donation_success, null); + setContentView(content); + setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.colorM3Surface), + UiUtils.getThemeColor(context, R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme()); + + content.findViewById(R.id.btn_done).setOnClickListener(v->dismiss()); + content.findViewById(R.id.btn_share).setOnClickListener(v->{ + Bundle args=new Bundle(); + args.putString("account", accountID); + args.putString("prefilledText", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi a sapien metus. Nunc feugiat a felis sed hendrerit."); + Nav.go((Activity) context, ComposeFragment.class, args); + dismiss(); + }); + } +} diff --git a/mastodon/src/main/res/anim/fragment_enter.xml b/mastodon/src/main/res/anim/fragment_enter.xml new file mode 100644 index 000000000..073d62d12 --- /dev/null +++ b/mastodon/src/main/res/anim/fragment_enter.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/anim/fragment_exit.xml b/mastodon/src/main/res/anim/fragment_exit.xml new file mode 100644 index 000000000..8dcf659c9 --- /dev/null +++ b/mastodon/src/main/res/anim/fragment_exit.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/anim/no_op_300ms.xml b/mastodon/src/main/res/anim/no_op_300ms.xml new file mode 100644 index 000000000..86216b32a --- /dev/null +++ b/mastodon/src/main/res/anim/no_op_300ms.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable-nodpi/donation_successful_art.webp b/mastodon/src/main/res/drawable-nodpi/donation_successful_art.webp new file mode 100644 index 0000000000000000000000000000000000000000..aea383724f2f9c7bb9673b055d0272691e470bdd GIT binary patch literal 68154 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�M-r`gBe1g zjG50DFPzW4*#TJYA+$_`h*5iPOd*fC9-SEXj2uV*r#Kh7a$%;y~atQNYu#}qa@~+D9^SZ(BtJ(rx_6fogXCpKVom~M3!uAb<=B{+AE2N_ zGQ+?9$o8tQ-ns(iC+4Nqmhh;F@dJf85{Su>H-8WJ`;#u!!4qS!t8L$D)r*vU9h?cQ zx`K!+rYVZJ;@rRv=LfsB}9%=}-ybk2qf42;WAz87_PM#{(JK`0B2Eb5Md9a^B>8OD`IHk<^>l}DQyGVg5Kuuwy`;}{3fLCK7kvYxb zZNL`^`cA&__ZW2j((fh1K#nSfT#Z6R1|om9BSz5pzIT4Y%K0iw!rWaWk19GTA(=T^ zC!wC<+HloG{?bXQNasixOy?_npW=2FN8)hM-OAw0U@I4^EEy-c4QXN$-YJZY@%sl3Hpn-$j*fn4BEY_Kz@Oy=;Dkt9B-E1u|3t%_pEB4yA-JfI)b9=N3gultuv>YY zqA%^{B$C&-Ox@H_fYxdqiut$e`S@CHzZ*57a2AoslfjJky~)~K%WDYp985Q=%FI))oJ{iEn

Z3P${dKbmkooU!iQ6);*+JAswgLO$x@YfT*6?AQc8tZewkjiJsrZ;VnZrwRH{W z#EH!L!DYU11j9i@^BDdq=CyMucSQ!4Q1Vg+zS`GWHgQgI+xWrq4C#XGC27vglIZxK zNH2o!0B@}0?8EpN=nKnH6nyuqGmVN=MKWZ-~U1bbcCw<^@=Abx0Jc7~VzrB{HryaUitT)r=M zo)7+e>71YFD;_~nb#%LP21P1%U0BxX3E$|CJx($GRBu-pb$nZq$ez`9O3jD()?GWZ zRLdkLC1?xw&Y@MS0q1Im`HR&!0Hl%5XWrthEr5UadN3@{!;k`2E+K*07zsyxIOXH8 z4s?|7pxIYpf?$@Uq;WAYO2XAl)DHs18O?L05yY0;_4S*f@rl@3)eK@p4>9z*2ViQw; z&7!5$Rh2a(w3)3ZF;qJ8(xOu?+@F})@i!HVl(T3MigUn!$ z_kuUfj7`JVSn{Im-FC%f4^O^F+4^5gpN(~aW&nEDO#;DeGoQZ;Q;Rz^e<~yixIg~a zlOe=@vUcp?EXaz&Pa{EzgaD|dgy9zF?CxucdyI14x@);94b%l~@A$vc&EJC@6u7vNc*f z_o~-JFUkc$4c2tOI_af0LWCK3&GBAewQEYHTtVrJXKq+vhUohsbbZ1^WohaSLkLqKpM$) z5ZOMzqa0T1|8V4g6Xn)qVEQCL1HI+_OLuKS)9xKxa6LAqQ2F9G2*@rOXNj+k1FyJt z1aRF+A&%S^b*G$G85~Fc-b#IZ#cZn!iC)0oKs0oRnP~IHNM^7JJxisWH6*kMQ zI}C{^A3qFygcb%2`@0Le2kw(Rs4x#;!edQuCWb}Vq2IJR zJuqZjC>T(@no5^(2-(a=9P0uP{WL4g315{#ya*7V;nz??46%V^btFXpsTLcaGWl*_ z9k>;#e#rp7{(xh%zd4W6gP7h)PjYsTUZefn#1#&)2ddhj*WM8w@yGWr(4;aP$`g}N zZE!(H=#cN|sCZV}5n11MX&nLYyZ$ZQS_5sxyQFgYuawIMe4a5Rda$LleCY62u%AY{ zKg2Bm(?bbKFbEY&v9T04xRQhnCVPia9hfNlY@6OyKD(nH%qK(_?@s2F%*_4P(Z;|A zq1HnJ0|3aTLuqnEVcKjq--$oS)A?lePo;fjjMm5|zcw3B72SV7`B(H(w6Y9rv?p!i z9ahQuN7FmaF1^Lu>J^>cD=OC+V^(Q{#OXp=(spEG?}zUDba@ab29*vbW9w>S{xehz zEn27u2$msURmM$X6)?+#)b@3i?;!ZD2y-Ef`n7~sx@mn1J04m75wajdc+l#VC7HlQi3V_0wiSd&tNZD#u zFi7D{Jtc9d1;eGyFEemhT3YJkzS3Q^!hwKeb-VwgZYs*4ZkTzg7;D>b#J49V8mPS_ zuguhrF-sZa3>XPWR8uY$5Zxl3PIXJ9H2lnN;bv|OZf9D5p4}9VVS9K5PZaO5rr+c5 zgy*%ln|J0z{)PFC2J$6|OmGM8MLF9@i2vabY9~rHs>AcAbU(?Sg#c@fnVYvVb2g@k z&iO&LaF6WhY3A9w42$e1DE)*asoni0q3%QzEY)$ALAfK1$2RtQ53AoE4pu!S(@gB$ zWf+8?wq4P_u_~`{YQAsHl;`L31Q5UXa1M@GD@sN~N(Iw&cYGm&{g1ayJq7m&awi6G zv1ia_M&MAJKGO%OwQ2KrC)zifaB)-h~%c$wr++P@D(0* zBn+|qLd@1c2l847*y2NU9eO0Q_wiTyR(#Xh_ndB6I&({2>6BD4Get?+5I#7r00005 zgOZ@g9$N1(0Nt+~T@wBmB0ePXrrI5xguOxS%y7gVl>CbNil9I#asi0F-NkWVD=jMB zm`Q-Wy{XaXHWC|fn350|$Ji5RT`R_MF zZhrHWa*SBZ=9n2}%<#$(Iz!VoBRMFynlWLZp)M?XH==b-`@6C#q2yc3(;|MauJB4y zP^CDxC$_34eitUWfDJaE;X4e*`Kduqcp;R^4|83|fG46{^3Hi1_S2G=aTGE*`tVk^ z>_E%H0>nKR({#8RG7)LS*8Cv*x2||q23g(0CUUCIKO~A(2gi@5%(XKHM%!Mv5#AExVZf;Akdt?%PbGUAZ(ZDm@c5xrAjitini)jJZac3h7v~N{F{!Qmt z38;R$S9`>NlzT5lYL^dBb1_=8Vkw$&h&G612m-%^bvB{Rg9hydsUg7j`nG*UNT6s~ zGX^&gxFnjh9U6sqLvL?jpawI6D4PwCr6?)~f$T^cZ(ptsOUs zpjJ*$`G?&9e~GT{hoYlhaRFsX*PDj%>R8kB@;3YDaK6q2$xI2HNKa~ zq2r5Y_A7kK{S!ft?y~h-UiY)m#*6i4L5)S)-3DrjIF5*|Ae^g-Ft?A4@-qWm~$d5dTq*aXdPhKV^ z6)P$QiQ|=OzOje5n5;Wk8lBk9bkLv1XKovJapBgd8|CS`7lbnc-e8Z_%P zM5WF}{Vi9Gjd@(Sse9dwj@Oh_k4opbX>j@MTuWE1`NmOqhW5cir9@&Doy9UsK*gd# z=nAd^sbwgM2&H#Lfh_xxBKPKwt<1HQRciq!?4*46jHx0)z{omEV#7Zy|NoLR>mH3o zIGrl z0IJNE^i8Z!zYp3Ky8|cy4iPE7wwm-FNDZJO*v9d5IqosP#+Em{Ia+|~oud4V*TirM zL|#<$z%0e#kk5dibW0s2|DYn&W!Nx(F3?(ai1-RAWK#Xqm`_99!WQ0Ud-$9*iBtg0zp65|g>lU=1>7(cNzXmgVSLm#cI{iU;!2V`nB)dIbS6su?Vh{O z37U}EJ52LmrtL2I!*tX3?5zohFI&R@-_p6-XH3YFSogRJSK&FXcQaqRr4$_sD90gO zO>;GiH8u#8=*UKmgvN;> z8uWZw#{Cmrn#_4Hk0=z5PIdB*BL`d`?K|z}Rb(a{v!?=l9zz`xQ|)eK8RGXGHlvSV z%na+99S_f756l|**Se>mN^z-NpOyIu-Zrt$Oj|cIC|Kf>jK26C3iFZreZ@dyR3M?@ z->n0UA4BHWb4PvA)X)6$OTe%mU4dgqT0d`}50-fY3-VAA+!dY&{3z;p7iEG9)JHn& zE#|Th=>1$03?LcO(}l1BWHv29@A8coi^?2Ue|Xn-K!eWuq9M4SKqSN)f{Bgl55^z} zMW9V9!o7(VmENILb?VcYDTDEfoPxA)fZoXtvZSr9tJRfbtQgp=?P%oeuc;Z8`dgAD z{*dGX083HQbdx}Q7Pz2-CdtPp`RVft{}AoCA>DHjoUkNaqqBl%)pZG74}}x09{cB; zP%J&iYA>x2IjihHc8d3&Z{khK)=FACnL%Hs1!N~3$V*Xo^RUlE03G}a#rUz0F07(M zgah03w%j!S_F&HLXf+fgLM`I)E+(K1fL7zvay`kdA=yQ`*mWwoxI0}?K>8)W-|-l> zwiOv!*u1Q__@Mc=A0Pn5V+XQm~z}6H?*Cf$U319ydVReme)%vl4WXl8Z zfw(~8k4&HdTzugSlzA-Vs+g3|&UptbrcY;yg zu>X3vswXozCJ2|ZWO=gxYQ?|wmYn1O(!f4TyyQ$+@t_*UzHQz|O{+?dv+9S@!gwf# zrIwdv7#4c7OO5g*)=&-|H~;_uPf$2^r8h^wh+BBg-S7QWMHc3{(H0D{7ct?JFVp9F zsE!*aJY$HJpjvq?LvA;_)UF*#C5ibOi6_&YGcqKfRazU1A>e)Z5A}qatguadH#j*M zJwY3ecrg(jv%5=IOQq>bQt>O2)ac54tcraD7WaG)mI*{>50RQIH*`VQv7oD%7CF89 z282l7M1`T2G-gsdPM8>^i_Y#Nh>FO~|Lf+>uSp&e0b0RBiD!JSequ@o!Y;asCuX>z^K&ysBu&8n3rMaegA1p+>!En8S*>Q+l379u&7lSdo*9@HI6+o)Q zHF4pJ1Au&cm;|R;fv~GRGGM0$=6T7t+#N)*JL^TtNTY1DSL-krdd{ojemV)6EcJkqqY-1BaF_3t1_ zn~FE*Ng!BjJ4Pp&*W$Vxs&?aSZ~UsrdndE%iZG&23kqu<-}XugCfF;BE?C-gZXuOu zk9hI43GkGH+TtsD*7dwH_LLCGg_Qj0$egeSu|Y9jQk>p~dD^7OCU0@fGz+eVE=`Dq z|3OBKehaB1#wNNIv$?+nBcBgNy~jW5bu~9(!Zr8{vk0Ewg=yx~`%gv9-aT3+Om5us zn3LH0a?7jODIDB1U)5DSmUwi%$-(k=EH{)s_eAm0JfkUx$Fg)mL zD-I%qBloE^PsiK645aBa>;$X_B^oQ3!uZK678iKX1XrU?n`|)r)i^8GlU2xqnlwFB zv^hf4bvQP^L)}meZDWqdcfEy^XH@2ubGB=Psf-`Vr~{GbA1kSbf9mjK(l0HyIK~EP z24E0;(1<~o9rdAY!t^Wv002;eqZi6j(2jGfS6n_LmXlU(3eRoD8l?{2bQUMwzFt&8tR0b~t0N`^-b?cYfhfT3(hTN{- z0=VXJ9*neCet5@6_#CQ^;_0_;!AtF=@`?7Jtq?UqQ_?u1`*xDsbAaAY*$`+6NP;Qk6&R2lqGq zv$s8|HX?gxLE}ig30IdV|KKMier~UT*`Ik^@JGXP1tNX?gK(bF7X7SZ^)@w!O9lqO z1MVPd;fv}B3n39|ZxjXf3t}b)$^3(9*k|*(a?pHMOXi(;l!X*PZ)S?pDothkA>Aa= zWio>Q5mu5z5zOP+1j%=Ky&^&t589h9L31~X?eHT>%)saAg+a|%B2;z9e)gR}hL_su zYRIKL723#If&pV)5-+4ldm6%#2Q~V`vx;#0vM)Y01S$A#5Uj%vcmfJW*Z5=efHrfW zE4Z(=RU@j?{~>|fPP)JmE|HU?La(e4P;kH#WT<9Io4$k=@{ImO$h=!t`pTd(X?IZs zgfmR!o+z(l2|37TerB2rDYgyydYAW90T~(`WfYobO=`%hY_yD3ssJwbxOJoA41kHv z>GGx~4}FwJ5PHK-OE3XQK)q4O6gda=m=624?vV4OOaKjeP!yIVkm~$I$=Be4Y8R73 zF{Y9pVKvwclfyD9%;u=$Q5!nt#AWd61N$77pq_zO{O3vDT}zBt#DR1NwL$;@0byYi zaR;K8^u^VY6TLyx9fw1N&CE)Yvr@kqQjalhF{=dY(!(%<)G^171vjeY9 z(A85h=LN>e2&0M51a%?mMj1yiQiiCWhn$hi^iNm^<7wHGOH`{^uD5s2JcKz9>kA=R z7PyzQJ$%+Ar!X^NXmz4E_f4aj_UNR$YY=@25aS6+EBzu>!v#ZlZXCmRQGZlP(1-Sm zUL#_o7^Y&9Yw)VkSci-@veNFVh%Gu$?3%cs1zkAL8e~OU7)Chcu(=N$!$fzf8-TxQz<)^)_ZdZIXXiC4kDfVFeSZYU8#<95-lG0}1EgZWfu z3&NX^B=)-Sk{rOSG{t9COGsx@@G1SqjDe_<(n%;-0ofhc_Tc}R?3$7Zf&~%aB~Z{Q z3h>CHrnCUkD*XKsbnK9q2X{!Lg_VJb*(pF8O)L}2((8MM3COO3|u~yj-QZmr1cze-71T6Q68EwRXXPc3(=sA`Bw8_2Lb$`M}&9jmkkE z{vxdBMx7(GNg5OPj^*5@eY!#KY%pAZjSCK^XfX?L*p7MP|0~LpgO^UA^D}_^R|#PRx1bjhB8aDQ(YOR{PW{!A+=N@DCYazJJ6gZ~+B-&W?m)2t9y8_W9?AH*cKb zD_Gt1S9E4ZUisuyECBdFBinzKFJsPyyh##al0t*3BI4&eHl^7Hz{H@J4#s#<~JR2?AJkRW;UK_#3$hwqJzxE7gjWe6`ARJRMCTJ4%6nt z-Wc0(rV>Fb9lcpUdmw~{fI58g9Bp82gu#B?pa1|qZ+~KV^%zerVQJ2wIY=_7=%`1& z0?V(RKrn{Vwi^QBa43AUW+8yc9?b%c2JWBvuC`X^Wmim7o*pSbsJLM-1sa?_Hft6b zS}Q+l;H+)AYdwFj&2l9??n7_hf4w}|E`a(X{trJyBK*>eB{ zOnJ_A-srbXC&nWt?F>xAC&CJ0>qw!~1h^07f4jp6Ti>IvPN;^e(!mK?GKsz2*PcB1 zQOYolV&_hUGC_CUUW%R}%l~^?BS`3d4a8?Ch+L5y9}_pUHk2-~|243E@W2bWRg4)T zj9_t9T`!___TB?+i6a>ntvs_^KD=g+-yo+gtH+ErMgqXP)5?|v(AjPE5n`T`Bvslt zrFVCfs8;SDE>BE=8zc@%8%4x`8U$~nj=o|dJTCgPfMq50Uo(}bwwJ`p!}meRsJ!j*7B zn%PD5{ui<=BrtIEbQLxKrOb@>CSP=ZLa$Cq2sZu$k*Nfx*SgJVbQ*FsjYnV& zJI65IrtTi}8s1U7@NLC0w>nh<;iO666MpB}MdLt;Nhn;X6X@uNrrBzcyYRKcd;*_B z$(Ps#y0ZxbQ1dBlmMi?e0HQ%=n?FOewzKSH6I^qX0d-&A*z4J!ovWMvxvu+W5*7VN zmWsZ>b(=w&QzL~f(Kf(#f}@wU2}9DP1?w;yA=o*S@B+ki%A`re+@~O8{7W+t2>I`Q zA=`kwJNd`AWg0%>8<*@o?=n(1qq(?n7*^Tu7@u+Cu9%kF^UOmOrSxMX6-Q`>P`Z3w z(iD?Z^bQN_O!*a0;D&czh-Cf)%z8YWaQKsJw*Qqq-$;JKL7I?TOtwq9Js#iVkTA}; zm5}bniVV;NL$*X1ePTH@QKgCwyiHX%xoJy~G`qVbi#w~vRlhs1{ z+F&fA=8PN+di2J-a|E>A8o``EROn@V9xSBpVVBCohh4y*d`e5kcN9MJjZry~1hkBY zjSYJvEUwV>IiT!V(%*ih)5y+PC-Am-8)O!(M9TvMrK0v1f!Cx!GH_<3(>z0L-|Jx~ zjsff{E8yA5s;*-+S*c(dKI!3J68l3dM0rKTletv%5QklE=sawoYa`JF(Al!05>JN0 zJLt_j{%Wj;bsy!L{K3iQriQ`h;*L(1^I3I4?rDj!vsG)xW<8MLga7~l_TsJdHQyPI zGEk!NjMu!3 zh?h&Z$UdC;?qffZByjo}3)u8x()YGR8alurngv}rHAtn@<(GJ4s288ZLGa0JF`pl6je6ST)V4lIL+ z1jxZQzY5r*uS}O@IsfZ2`(DY4-=={9HoX9jjfhA>DENlm@}JL-e<8tJ7z*y~E5^~- z8$Htq{P&9dJEFHfv<%?ITl2CscLNE%WRz<&e~WS@6`dR_J~#weTg-gT3xJE0-;I3h zZ<9-83n(s`weSYndZJ13C=)FUJcQL)lZmqC=D^dAhcrn?lsv3^`H(7l(kQ~UvVPy5 zUoj5G3p-zdX!(wuO9)O|_nx@#5ZJ{+bu|uG1PA&{bRSLg^rT_#m+sbNiO~kW>)}H6 zr#HP|SPB6#^7j=U5+=~F`aXV4fYbIyZ`o`r2PM?m7)L8+W z7Dvi=p={jCC9q-_XUL(jCD4~qq#b9SNpEdlam#t4JL$ub2!=+-)_Lu zQv*8U#W(o2ck{Q})1T2p(2l(dRiTUVLp*`)YMgqdt}KT!n_D)=Vug)5_LIZv!Jo+vd6|f&%tlXrm6ffKj$1gh&3doiJwUzyxpZgk|(o& z5;IhoZV$9=>~9^I5l_A`Yj+s{;-9KrGkRQ?RAAP#c;_aDI0xubDzlVo0A3lckm|V* z74KE{bqByV4t?+e;JG9l+1eg}PZuq?m9Ey5FAMtC;d-5{*=`YdgwbUF3SLh*M8j!R z;GerbJIXP3GfBRQb}D#3eXu{i*MiY{IvdRz>|i?6T3L^rk)!4tLL}RZ$f6Fi9-7~^ zarC1Cab+<<)p2JvzmqXc=&fhy?t+~HQN+%III8ecZqjACve525nEoS~n_E||0v8BX zBKKUmI3zuzCy($URy|{B$(QYI$pV#fvH1H2}-iw^c8;PfTP$35M#1{^5X)wuRuPjTJFd-RNHDdiGqiP0fTZOwST?`Mr~31 zn$($Zq>0ue5HoUQnJ_#1gNhxfd3cPKz9P(z+c{EM&%Yz-PoT)Sm0 z)eeAKbo$A;dqQ8YD5rQ-e%^;uChuB@ON(SKwfYlSYDhm=*OSvjdj@0y>L2f~5Om84 zpo&}u2s9(8(of*DMLVQ+E$80AQS`jX`7_2kvo+ne6iI2jm+smK&8i`Sy}-V}OA}E6 zA5K;f5ip<1D@FC6B!A*W#`S3mLxW~>+f|#Vr_)qLqRMXkRl=7`MfEXgQd!3NZ|Ny& z$H4{>yU)W>?!mh0*k1nQT4L1T;lOn&_G|W{0D*Yr_Ncqiumr*ec=2X_b+(f7gB`C$ z?#V98&3E(CC#!YDC*2O&f8WUNF-mTIGCIhy+rRL~FoDkxt|-+?qx(nQD~yb)e#2k| zq&4<5tDE{_FR&QW7y??hZS*`}zdqyPAXPQ(i+qM{?kFGWZvJ1Bs>K^Lz^Shl09-|5 zXXP(UNr6-I?=*lOmcRL$PEDXbW6Hj)EPzj`$mNlZPR(aLbJNnr7@~Xa;v1*TDq%Ga zWtjAw2Wq!?)Y(ky0lMIL0DweW9cNjHyPyi@Ey4*$Cq-FFgq z2ERfflU7@>)4PFc(<2TRe3kpDfFt+hB+NJ5uIgXL00001tT_sGEpw=&t(!zAK-cy(#%*tv z{{l?JnM4n-8C_lvzqsF((#F0SJ+5jj;pC5_w8w9H@*K=Ssk^DYgV*J=!%ASP{xLze zJ6zqiRfoN6>mpisafUM2Y0m?T;4qPguXj51`ZfyU5~4mr&+maD?6F9y%jwrJp=Uyb zF8?k%)ex&fW-g~Ce6WEn>mh)dxA2|7H^EZzear(C7DTD-yN8U`yvxFc5B*sW7L&tx zgLyIAm?4vTIz!k>S`SI=v5DG-9I)kWoJ_AymsDhle%9jl_0gQ+229TuPUBx$jUXp4 zzUyn1spJWP2M($(u^2%;afw0_r=tCpf=u%2yBy&o4YY+AtA_1_^Stp}EQFVVT8k}W zhL-xF$f#N>lD#vbWha_E1xaD--K6{khrXFRT*U&;f+(O~BRpn(RKw&5?ii4xbh1%fAj_W^k`T=VB_l6jy2011ukFQ{6@z1J4b9-ncpQXM*TLkExf3znNnn{MWv zU?J!T)u;3YtV8$}3%XPB9UB!L{@pGtt&h9v3n#%OG;MbQLOQ_cXQw~=&{W@CkCKKM z{1+hSoPeJ+fWxM$wn=?!mPAV#X@dk@!83*VkMpH%Zq$9)kh{QOA)NY7$!;kj`H~74 zj9z+m#eN-i)wP&j zAM~FnfsX|r{Xsl+0K}tu{>sLMkBMKi(LD-Ii&F|B`($o4n5mDZ9XErf-aSRnQK*(e z&3XmD8AdMLn^>VZCpUUKPSebM8N=XF&wgpG3GJr(fcBLmM z{y_l%tu`oqa!7>8Y?3Cs|BSwjc-Bw&Bbw?w;Q%M6Q=|=C`N?~I6OdU|$h?WoJ10LJ z!8a=l#jpUHsgxC^AcMWt0jUjYm&p{rHZcw`B6b@MlKD@>?569=+Hll&Y=Z{CIhcAz zvUN%!JcEC&G8C}#cWx4BfF}8dwFIHWzM;#4!?VTH(AZgjP{=?hr=I|`^pVw-4Jn)- z`0GHbhMQ~$q5BlMAe7U`B0;A`OqZCI;P8^+2~60!GSLu?E9don23*t=>cIUW_#^FpAi9Q3 zb;OFYk{qONok)S$|D?%!fZThb`d-AmYlnu?T^5<8(~OUZXIUuflem~id^aU?^9sjK z#v1zo0000`adxbrW9~*C7L3V${Ju+4T&=%|0z9yg$LOJ{ z?2Yktkxz_th(h!HZ%;CxuyLK6X}y5R2F2j|hWZShM%b^mY}|sm;XvYq^3eB?61RFo}Et z6nW~lV!igQ2(>45zb$|bqlrRGO2H1OkNt_yQI!5iFi(98TYV8WXc6bCbJjED^#bd{e4iIbDN*Q_BT_b}8M&=UX^j)JKi=4_%B)Nmxw<0p(}vEPU^Y zl#o;Gq}$Bd%7zBRY6=E96g^zeTrb9R`5}0P3_4HSdL(z+`l4BJ?FMyUL2I=T zjMXNgp*k{G%lYPy*QHCi?%Z^Uk4U$=v!v7H2C2El-Myq=L{m>Zccn3U_)B8Lx?JDr zth!Iw*h9rYPy-WbEoscH_*oC#8_2qOdg)`m*yT-mWIDZ!5eCP@V>;fSrBvkVOcYz; zeoC=M?iGg#u%=TNlBfP(izjy(dT{`0n`Y$rK&cv~0?i*odOhi10YUrN$A^L&@%mG5 zyxfdo^nd@y1{wf=tAEVa@)%xb+<_bja}we)HCC?i%|0tw7?w_rm%Y)s=Z`tj1Y;%OtTFxO%L$C7W+#NI#YjmNPO63F7aJ4inXY|%K?N`F$n+SDH0o65LF+3C%pwm7JxGXnX; zhfoD@D|!Dkno59>fB*nbT$)L0>>g2qiN{7cP+LpjM8(oqs6&Zp1md}=5#TbI8=bOW zWB2VYi=G3ckdx8snM#L;lg*pWisn@5tLoAuiz(x?KcTGj;G2o`O7P6rTs@Bxna}A; z{ir)-vmE`)6gO=WvMbVtuaJZQ3o~RF1>xs~T0e6tf66eUPWPBVK{e_q!1$(nP=a-O zIQJ(G4rf|tZ6KBErAvNMAe)e2)UM7h2! zYgF&iTVSx_ebRkP3u^Gd0$f=sJZ9y#1rJ{zFK;IzxJ~n@6?}>g{1V1Mz0@U!lZ$lP%aefBZexv9#uM`I06*(l=@b73xa8^)3C29 z;kSBFa;A=iTVTj8_2ji%Jc{mQ_-bAu^4Csn%DRnWsU0Q2a9kO#J6ju(b_MWo9OnVe zc7*Y9mf(CCOaDTwU`xx)DI`Uc-x>FUG2T9vR2dxuh88rrwhMAhz2aET z*!x8~DzLo+dUxDHG&K_EO|KD=a8u%wMBC zb8~c3vrRWeL*HmC`b+~UW;AfarE#qQ2xnEvYAl;sy?Sg(i#(sfhuTZHIzA}u8F8iy z{D4AvO0at1Kj-78RF9Cn^wvPqita&qc+z}zFWH;1ar-v$Qo5 z`J{UQZa|U0njz~C%L`0Jcw5lJoWlbAcuXxurFYO?U$FK-(5~vQh!Cb(=wggz>A&^N z7HDQj;ipnR;%wuNO;7l?`KQ^pA$S!`Al24_nPyk#?G|RUt3SxTneKOZmW5x#y8&{{ zOZF4Wg!AfEJIXC5J%o%{JfZ6_V7tf3Ob+q^jId!a}ePUtW7Y3jL zQd^Af2l6z>Yh|Fl+b}0#d|1GQT*pog*!pME`t9mF@a^~NkTUdWojfW3zKrwDY3J9* zJ0DF^3PfK{#*}~n026feWKqDvy>oLWWd3xB8m#{&9Dd@5S6NpyNoe6_{qA>zqk$-t zG7P2|b<5off_Ho?X@yCJb50UBNi54#;Q(45w@&OWWk)@o2lCjmpYtV1MqzS0eJ1wU zxsgr#OH;nwKQ3SXX?9f2^33or^F=i`ctB@aUA2~Bp}NUhG#9Nw8_ zPXPBqck@FJv6`T_5xaU`>aU8U*-)2omhyfy^;xC+&;;w^ij+Ldl~NS2 zg7RvByadNwldciV;bjnCtGbuQEYv?U)Tz^41BI>~nZQZkNZ^?Hn7~?|kqVXSM`;d7 z55|^Im+oS9Hw}I9wX_S-hguc+b~c}kA7QH^4chE{FDhKs7g#|J368Z=DL`S@FJ!eZf|LZunvyuo41KPK19snD24&vYf_=3P$iG55%An za;9*Q94~i`k5&pLlq4ycDm%tF0D&WcNncsg#f>49iPw9m?P)uyx0-lOAqn$j3++D2 z+%|`*OaJQf5satlj%F$Tz&O+gJ_aO>C$uWo)z7=IlA~Wtv z6%RQ+kB>En0{7pKGB^4}L4|rPmnf@~Z=X$u=;s=f^XUP1OOom2!2{rQ+n|zC2_xLIV=tr{%eNWc52O!Ju0*Or8FJcjf_+HU2bqn0rP)C{h^VO4iMkaAt*7b z)}Ubr695bKJSY{ts+yn&0wcg?v$-!^*^cAb^6~mL)6&R4-P+~654g9+j2a#)!5bzv z{28_Xdzt`uzorLp77&>+4CHFr?v}*zreCHVZ0&i!EliScW(wpI3K*<}q+7@TjUV^m z{M;nG|JAkvQ!9~_w*fH7y=c$;Xd+g@lLKlSsU>Uy&_r6AHZqD*2U&0AsWr72`4hK_aJpuIxh)TmJ z5Owo*3Y;IsK^P_FX{W(h6RZYsX? z`FeM5WDvmIX)GeMO4b8RIUqbcF!Zd-W^`J36)$2sX%>r2DM5B|o+oRE_K1~X_&YAq zcdXkxP}IO#EZancp73)*gW4{e?E83TxV};!8N{6=_HCji=Yc)8l(+}aKNNyZ1!0o| zZVS}OB+s6yGBl8Mh287AI5>Ge9>S#qhYUfF@OjAjYEitT1=I}~esUZC*bb5J_knw6 zp|>?zep1d(oZfJABpJ}v)029$|3j@AXVc(zHpPx5YRyzmo$d>RjNe_Z9~UNCFAl3ex(|H zYN+TazJ%}Lij!NN8|2;jnX*q22e;`zNMSNR)jos4r4uh05kk8@&>Ym8Y+g~(>Sg&< zRUoj^6at>riJ$ugde@9L%Rpui9$}g^tVq80ca_e(amC1rW0(i?UkNhyuBKZBPVgdq zEr8GS0wW%VU=o~mTXLWT-yDEID2BVO9m`PYd5S8@;{!hq)Mju?wYNkr-Qf!wWr-HW zj>Hq{(*18A>Pjn^uU~8YQy1!XaXc!o8&9->w#l!T&v7OWR!Mc`jDbeJCcZa6V7FF0-CrX&FMjCyMkIX^Tlo)Q5oWdI>`d)b*#_V5Om6&F9OOJ|0SeN@!#4xbi3c zIZy#q(9%z{Dja%CrQEvv20;Z`jn69R$6%O8@KXSd$aUuJ3XXu$ScLaSPqDxX;_6GIEYY$((um_j}Q==yBNFD@&n78d2Hj#k@$ltsDKQj%d<6F1cALIGoFakBD%ZC zOp1m?SVeJNzyJUM07X*loe+o#I{j|POKCuB%-c2k;D#IiZisp07>?pPG=HAwcX%!LY6-C-|3#cFweH~x=9r2#GDGxBVQ)?{ z4nI5#sr6HQx`(A5V3)fe2-@1&u@LsD$k7IiWpSE@IdTMH@L{@b?Hy> zIOs$aL;wICr$qBO3Mkq1HMV2Vu~?-%CSqDRORyBRYUjN~XuyzK3UHB!qsJbQnxpx^ zjy@i(@8GAub`lO+B36_&F?S{w_}x{HFI+Wd6v1z7?mlUq)Z)J28!I)e`J|U*Nw0;Q zYqi?@-x%p*Egy(!XHB>Or(QDcSGHMioQPo86GOsQD)b~olevlGrJ;-IV>=&xN-nE; znB;)WgsmN}ITg~9e3ysT6f#1I%M+UkuDlW{G4Le|H4P+!3bRq|Ip zZ(S~A%{i3H1&M*6ygZ=(J7TmVQyIoEz5w zM1j?fF_P_F?0$TIdVi5%I&X?DgrChO(4kC|X!am*P}t!96x}q6$WMq(jHbB-g;p>X zJkBqC0!L3WlAbf-cP<~2Cu7-8Xt+n8<=z(;T#W zFn}8z*0>}<$8Jbf@A_%UMS;~=QE=#Kl(I4kNcZ{cN6Lz_?U05p$7%tCh5GPDgZV1{AL=IuA z1S|dn)V373MU*?wW!lDUT`rye$Q~VsgZHkNH(ciz|G|tdV^PfdxJ|fX+7tJ@kNs6y z080g3&WjO>lQ!mRzSOYoBTw`!-})i2PMC|~8&664-JXeUZhYzliiy<70w7clM(Pa- zV2A-GGk@`mHspr+kehAv&!VK8Q_P=l%<7P&Gf#Grnltew@T_Swy6eT!yyu6potBt5 z$gg25DAtoG?q|Iex;N{#WOix8L64^6O+DB$|IHffh!|AmjfP>Q93{hbVub17;10$;(q`D0p8ALc#0G(!N^3Km&-C$qqoa5X7N>?pDG}_ zF z{zF`4Q=5v%*t9w2S6tfeC*`!C^@*(MiYh_-+^xD6N$)5Uv$u75doIVWFE7s~)+Ovz ztEKZ6jM)PDK==Kl5`UL9CY8M2XzfNv=TR?>&0$FpAZ6GAj1kpF9IeQL{hz?juk+*r zr!QpkTsqIz#@8TXkv8`i*tXj)!m8a!e(Zh)R;g? zzB<#uII{Xh4}f7}9D2xzRC_5M4RyKx*?Oy(xABy#C{-wB6}(FK!44;>1?b#WhBmA~ zO||kNU({%Er zgn~>Ft~6V)#6d;0LWaT9b|zGby0;Q0Og~WL;|MOboA_pY^xNHNdth+?UTwztb~5tQ z=IH?A(2}C{I|90+TlmR>QHYVP;Oqo>}2I?b_nL(56@B z%NoYo+Zw0!n<~+`P8#XB^W-PrU@0UKUZo1cyy*JjFiOrXIKD`LI4SRssbmf7Rb?9zs0$1MNM@ERvn{~GL+ z7c zL4tAZh23gnn7<-`7_bCd}G#0=>R4Hq+u(>PgFj?@e z!Y88S9J?%aNI$onRb>f>@o_pROkdqYi$=>vYlnh-3knd^VySI6 z=i*ZU6eju3@u(s~32y|UOYm+xT_S*Dy#r4UY{uP>2ZGzKKH3TTV^?ESG)J0+nPkP* z&oSh95hN(U0$6YJ$*zCra()W@fJSg#rz#EI(^?!jZEE^`4SUIuOk+n0?8CRz!c=Dc zQ!m?@iXvlzeaQg?D4iGJvh*3mCRpzrP(v^$D=%)JOH;K%{tXTpaM8N20|uB1&WIT- ztEuzk1%3o^;mjX7^nFh+KFY+Pr|MBOD_FDhQy41?_3KgCVN@drm)VMc)LlV((8Z5+ z4fdVatgyB7WgoImPlrtuW(Jtpo|!zA@#9ZIuv5<%f*adL2F?;*&!gZ`rHWcDP!cq) zEMw8jISUf)Un7t4T0*qhR+-lhV}qdpLwy2BXqWN!l&pRZu#1=^cbtb*Ic_lYWBre% z^)*QY^f*v@d$IN1p`kzl_-L&wJo_SzCJR#9C>gJ}AmBg(cch#Vr3g3K{vQ}P|B;8a z&HnKH;}YBOHn+-<+LGks>>Er(u-}E_i$FG`R@eod8^*Qnx!IV7cqJ~8&u61;CtPRH z^QistUTn5v3lEaWJ$J8b;N?#UR0Z2m4LQUttN5Gk&*~nb&N%QzE|m=f`v^RUj^lwzPbXkqODaDWfc!OdoZ=56fAVuWR()M!*C4KE5&H4 zqa4tC;<~vY=)rQ7*m(su9#=I@2p&Ii4YmV%hj|h^C=h#Qh4~bD*2jo@D zYyQ}=W=dk9d^-is&Ma+jWHGvkfQ`_)T12XBY55Me8jS?)wU8)EShB9w3Oey%e@JaUnVA>lkJuR}?rCJSsY*WZe;GbIF;Zz~YX6FL)zi`|9AM|~7MLw#3M70`( z4n1z_JLv0E6#_C}M0~dZOIf6)*1NhPQ*aPq6HQs>LE*s-T@%cA0!*jGM9F> zWow^uLaeyh35^suaQg05R}d+c_?7orq78qlE}Abl*&CYOLrfRjYD@B#V?kIta94c} zyYbGxTDf>az#AYdg-RztE4MO5^?a>dwE_zCjpyD)BhxAZO@9Ju)^c2U*sdf7(+)B= zF>+T1ct(@lIc(p+j#n$v?C-Vgz>`Sk)*9#JIG|Hzy7lt}eg>P+ERj&&c30!*w%9C? z3jy^mFCNPC=xa-CI{_<8X_MnEhUSs96>hp+aHia>#J&vCcHQO258408r+HAaZE|AQ z4q47;0w+>~R~oeFjzq5MyZ6SA{mTKY|8jf47lFdJ%7x|tSyLGUAU%&iT@f7jjb6AR z9mtq+fjMZrl?deFsF8pdy&NwR7I%Ri9W)+%>N1xdkU9aQ{L&VB?LcN%3v`C_5~l*1 zsW&@t%lb1Wx<2n6DY#|M?c&(SD~!zqQ~m6eF%DA)1E8R24D6wA5zxWoOCaujPs3@J zC9`qZI)3Ph`*iBLHn>~ojwCInD>(BAh!W%HRd7FU=A`Pw7L;LJnQ+HVjyCLNIWCGk z!HPT3f8+Pt3O4SpnfxzJ&oR|)LYeNp<4LKI&-F*SYnbNFSlt(xpyiL5+2 zj{U3@8;?AO*4irHGE}89q0tX>02;6$o-BY9a3=fy{%dZgjuHB7;Og{*SFG`M$b<$ zvt=0~AAOLY0#gHW6{eQIHh2^CSO+AvRn1M0sB+NlcmhmW~la$l}#ND;7)fXGR=B9@vP)mn?LtOw2#u0|9? zRPE8+AUyjpN4WV&VTq9sDbfAbW8ypNf}w( zoIvs82ahP8TK8^8F*CN#CURZ2}N`M&Sb+t%I=>+=0;4=YuKGJwbqJc8rdk) z*Eh59>S2~AV_)BZjCWFhdY`xN<-Eg`NPW$yV{hOfM*agThSRsaLJNsU`?$Oo()|rs5|6RdEBdv2r!^;n1ssXE} zzqriJ4l>dutQr9ntmJ?N%X$m#BUH}{I|VmBZ0wMh@xAQf>yRD!x+Tz7?q)9zd6^Xa zGz<=9r(7j1XDs~UNzZqB{-+93^nj2fObxmcHDDn3klCzO%8D@hdYP&qey9gNci51R zU$X~r9xUInXXjzgAgc#v!Gb77Cd+6s(7@^$IRKB%+zcQjS_fq0@xW@Sp_xY!+|Y(ftc`$GxWj2^n;osgYy;7CKS*<{-UE}90KZ&?$j+Q*bhA1}%H7|g zmk&j6Gh=S{5A2J`*ueti1uu}x9C+4IzaV9c9m|PE;XbF@-Rd>VnlCIM7sWihydPZ_jdbxZyx20W@Gm@;bpm2EK5m7yAj*c@ zz@Bx7kbq-!?g7L15%zn-&Pi{<6>v#P;r-9;lld{V>>%r|yd#6Vhpu74$aG%+k2m&X zlcXy)0cY1D`~-(kyoBN1@O?EK&fDLey6a@pyMp+x>1r^ zmT4;LJoM1tQtEfiZ#v4`fi3^Z3@Bw>*8OQuBf@uQc@|0 z9451Lz!!jop7add%>yWOOTR_)eUQ&D)`jS;zPlre;+Md9M}Bx38m~aG*vzJ5AT)wT z$dH5&tm8OUywlU=T|O{aQvtopAYhMB6tz za(`?!xiyv)Y34@%mZGc?>ZJUo4^)SUu9+Q2=#`IM`EGf@8O``KY%E|^kZy+9vjBxg zKG=oPG!QKo98JR?Hj13iL6IOtrs|fh2&YuGFXCN!^rx@&WGBThB2Z+ob|$X6J5tAD z=|ocS*GiHvm^WlEs2;s;hdn4o%@gy#pu$ATxsxkTgDAI?9tp^HE}hDQFIEJ8Dpzzj z6U9;zi->Q15RTYp%=L+s>DY92I(^vudZJ`TROHeOb3gz9EV-iZ9%o($(47()uB*)? z#HqZF)Kn06d=9^G?xS*%h(G;7Xznf3o3cQmVrk6z{N3n86zK&)4UrA9c+N?r6$Ium zT+dvBg6SJeE<+KJ7nf%t<#K;8JV9M)D&(_I?g33- ztKNz@382?E4Z7D;Z9DUJ2N+vLu&rwja;|wZO2GZ*>}d_P0nUrz8@oTC=8Z1FJk2R? zx-IiD@W`b0>r0DoXKAW#7qyOdPO|6mF9vsAQ(T8Y`F2aC4V>~+#ku8Je6tT9jSQfH z0Aix$&E<#WXwco!pIK`>$2Jb?nUY!T?OW2=2y;dkFfp$cS73G8xdHc)`}D1jr?TY1 zY;*@JrJccIlUaqDh_++Zg$7t{k`f#7NGTw(02!{|KHlTI@mNL_Kmh60JvD0&!$9Qk z1cf5|Z+w3;2r2MG9}X5pZ>MxdVY78HmDSTK2v3BUzTevp1NKRh%J-tC`KoZ}TWzd- zb`8*dqRVH6Zvw3^;J&UbOM_<%qm}uNlb;DIkFLi(NM@k zGXF)`f5@sU;t{#($2CQd?TV-Wtq%s7%L|J^!$ndB!>*tT7Myn8M5xKJ91d1n4Oc`_ zNL^L1QQ-DOi}}hc%IbAZ$EBtU#+5wyMUUHOP-N{*oX+2%#4!-D!ayuw1MY5)a6)HK zXK=dLfYVeE@!;+c9q^$Kh-%zr#YYGT=2!{p6hIBK6uoH0VPdWnq$@uCpKD6HmC1Wc8w8Vs`b%C{Y ziLD^~n^{<%^X%A4gdA+rjl0>Bo}l9pI5NosunX^>`7{n=}01_mm`N}*^uxjA4V!2o>Ny9UWb@_=zD`@?NsBB9=VH! z=5a)8mmfx!{ErU`o8iPzT9sdHlG5c)V0UhzoC07y@5QN_if>BI=@;c}?-0+eZn&YL z>6O`ms2m5oI2o41n-##~Vs^Z4@l!Vv_+DZ<_ydW*7+`+KGg2Y-ntg1Am}X8>DhH5N z1CfFnSM^eh9t3VXF9~}{)Mf*0e!Q+tH({lu*#epE*Qpj>4MmFqXUWy|BN0t<=~(1> ze^xm?N7BT7iErBAv^svatxA`Q$G?yWxH~spX5ZaVzD#^^ZOaqLMj+ zDb(*=d#GtES+f2DO-~X@;Mu3Ua2ahCMS?5spw}`U42{|R7djCJWGa4Ch%i))7fO=8 z_ooT{e>;a~PsWBHL$hTztobq1^S@+s8oCI$_R46k-bLOrbLXf~5`^c87KLb=PgPX@xnOz}tlWlt65D zzkfP#NyHG?&6ZVizTE|ME;1H1eyOFvglBUQuEe&zQ>8pRq=Q?Xp*lz0>Fu`iL44@f zrc_HxZ5wc1`hEjR<+ZOi-ub+bDD3yen-NS?Gble0p%=97%0tF{)R3z%4PpBCJAwzT z$96#T?8~htR;P`{800ei<5~7CASRyWCe5vIprR`Z{yK%~GgrzP|0;XLobSm=H&E?w zADSt++&y0MrK%}pwk4_tywArs)7b(y9hWdAQ#&?39sLvd{?GD|MQcK*M)cVa4Mt*^)RiO>qR4h7`!L>WAqQE6-0>zrI+sgpRydWd;nLI`&_-M>K zPu1&kpNGM_fYpYmvyOPg92fUC$Y&VlrS0(Q8TfF zEd?h%sQ@(Hf;W!TLxlqt*)->OB2}TYVEnJ!g#mhn{0|^31iOnr$JK$(P>&W^uE!z) z&`vh@H}GWQrOND8lFJB@x0yw+g7(O0(`FiD>F578$b%{+z<=wnhQ_B%nST75cn4(& ziF+U9;ee0ClbHWtTnMn|a$BP^}VTlXU;qNn=Ec)%0UoC!vEd!J?hf^ zjX>8uAza`+oYJjIn^0Cz6jj`|F4D?3NgqT_4$9PV+BD!wtSG*SoiZ|EYU8u%u2;=^ z6#{Gd1>mAt0`x=n!si3xTNyRwq>0Afq*2R@)W@ae;7KpUH1FMoGiV0nqLL73oO><~ zBv$XAYCVuj(KPV7;01NrNsHT2`}xf?r~m;5PewEsQQi6ULs3N!7SRq*H=7`}fyX!; zmI@jHFg9AuFg*MpZ=LRL%1@H_hJzp`nG< zpcv;hT^h|`d7DK8bG6!FEzx@t9t?hv>-45uBsYi$=a?BzVRIRW!R;@L3-1DZT>By+ zKYlS~?ONARqFy_LJw16!<$z@~_={Y>VUzx5uQXH!~R zP^7FxYKuCEYTr!vi%N~ciRw#imbVwGZ~Rw=P?X*3dfQfJC37*_1r1QTI>jB>ru8D;HvDpRL|b9IOgjL?xGJ+QTyIqY}l5}Ar@+o_+7 zpNlFK{RIjVX-1wmPTBK|$a%I78iqs!=1j1Zj?`77Mrx3DdDs>nR_$6ZC^j9=0CBu$ zHTz1YSMfVKFMF_9%t||P?nT|HR9(Z^FxF2mK5WU1f2E!(Y@8Yl4*S2gXWZx3|CtX_ zid*v3ALJY&PnV)2l_73UVT&h!#>pE3!yJzW@-vv#=To`XY5QXBDESqz5xKa+#EsUK zeGVkl649tduz_Z5#H%<1f(FL%*tT-0=e!LG#@I=;;U0?SKDbD|D01ryak?-^hcAGm zV`vM#l@NZu5DYn{H%{?;*jf$+;s*>}#sidgyBnD40g0lA!ccg6{>Id%#tK!Z@iON` z=nX9dX{B-gGff!(Z2}_j(UL&=B>_LmY`E_uL`cu)}U1lQQ zd6Z&RKnX;ixqS~jSX`rkw_0{cl&kb1C^9fiz!e_Pkq$YM%YQsj(9Xh8hdM?@m!2*z` zS^S{j5kx-&JWS4|qfcjpjzOZoA~8 zx2dLE{BRIhxW@5UA47>EB&w&EuAQP9!vnVQ^ALZfu0D>*t0uO900000Y8teeDf0Rk zJ!>is3@o!O8=6o^9*RxTLa$W)ZdAXrDxw!0!1}r%eU8AL{;z=*bH!=#nVm=mTweiB zUw=_&>}tUpJLCOadHwLaPRy^tx(wB ziy&vOa`K8oI!oCemW~L%E9`5L`o^nv(WV**Rx@g! zZ6S@|F=-ND1wg)Y`xoec#ZD+C!T7FP{{3|yV9Mh9V zkN=EMonkCad?K)7M~)T5Tt@AlQEHmZqzT1^;Kekxvl9BRWZWejH=(k_UIiW5wKKuk zM6{VK9Tw&S&{Jm%ZKbaeKx2D%kda}iEodcj{~E7VD)CGhjvI9wqbf@uM9;M6Dz4x! z8X;S&hUL|1EQGTIUAJ^VsJOQ9Y2P1O*3GQQDM7y+CE+xEguQ3)Gy`1qc7)Ma5fRyb z*HUKKtFwuDMzq{1xuvntr2rAKBG%27aWBvJJ?zw4TxsQ-ForNf2rRxws5oX z{q^e*R#@7budCCerm=tEzPwqs2@~e%q<{a1bwg0~tF$}F9)7$ca$ZUR0PUmNDO6F# zLk;Q89P?6+@*Pb}9j>Vx*?HEHiTlM@go?Qd*})q>12FG5v6+G}6M5SPYQ82)H@Vw0 zJocm#{P>*{*8^P8(s>He8u2P!;XxXCiAAteuY~>M4BYey5LgFnfvD|HKRPF_2DzY6 zMxIj%>20y2S(uLMzIiRbN9B^eCok}IN^(LQ86H$UV5pPnK?g&v{h`kLF5xrC#qErd zB&{?^*d8azsd7hHXhpjRM@D|byu-v$>~fj*LGY(Qym~0!%t}0xaOp1Id~zJF7_iK= zmv!rTAEM__4Jo|b8h`5db?n}!J<%+A+VGcx`_D2Z=@y+s8l9Tk5f0=}Wvt5tA3g}K ze}2F2W0Hn0 z2yR2UR!~(oX|TH1?un(8%FGS|_-+(7tO#vl9DOJN00ps+6q5UFV}ntBLK)3UC$2k66F;|QD*T{^hJGYI59hr7!^m3u& zB(j`a)E>H!C&Wu`r8a?D?`f#cx03D({}qztILeOxF}}FN&y)Ky8Aq?iG-^U~uW= zHeP&WIHlE5GkQ_$Pyhff<)V48vugN4)a)yOrby@vVAjEwVzr^#-ll~XcJsmoc4}*)7R%_ZKumoH(V2+F%T26A+93e z6U+N7R%1lT&drJ3Ayj`x2i_hDN*5H*Q7IotcKw3EWx(`D2GfDVVt#>ADn(v zyY2T-;E6?|S6`3iZF&t+VVk=qWiWt;h~udTUrepIvgJtrckt6~^AFH21IR(>c~2;m zS;t=8>u2^tLQu*FtN0(ChHt-q6lU4&EuqxjXlDmj(x%ESd!G5Gm5d2MS+>f zK*K6YsVCQFxcC4700fCrB|hXw->qTD;)(FnSFp#>5?*}BjhAouIWdGHVX4<}_^Uuc zil2%k`S+kUCtv{8zJ(~nj)Oh@pB951g<$;0^v*jjTS};#0EPett^O=4W~ma{M@0Ix zstu`V1FnKFAchh5FY0Huo0z`-lV3x(S3w-xE>+k{-~@yrF4<@bmdZ-Ss%Vohw4I2z z&>0tGJAwzVWkB$|t!VGSxUg$W@44_!15uAIYo{dnkW@ZEgy8cHL-_r8CpWp|)>r0y z`1;o4_RF8k!^^0yO*hVha{qLWStD3Sl$`G325eIB5Hm4AC9D;_e+qr&y^XjJ+2wg5r9nuLYKjij$6+sTp>n~i?g907@ zEkxBmAJH(?CaT9KRY-8{I>Q;UaR`Z|oa|A=Ov$i0bci@?scK))e)eO7u1y04%(8P! zC?XVc!MtCIK$YKs=QPJnFH$4{ua!4#w2Ad9rEk2vlW zf-j%ZXcX)0sRv;zUuXV}*4K0wU;sl}w1vRVhy%If#AW+Yk#Xkj8zey&4(#r=Flz<`-b%M-LUwDC$`B*Pu;;9KEqzv_|?> zOiub>vve;glVs}gfo1*hCpHVTZ#2!q9$G1uBA{c+G+QhqeD|Y0P7{Dln}g2FY`Js3 z&WO3_7X>Y{l=|^%C#2Y@2?VVoP?JnHW-9pQKmo9ypnO3GQyN|)8v2CmiC2L=gAJm$ z|M76#ham2A_KvR50RXQpc`Y11XGT=?vMseE!ARE)=3tw3nvW$%lZ{fdTyDpk=1SFD z{ZZkXjTw{MqrXRcpC7O1B@Py!-2Ik_wi(!tSEBqQW*8JVduV_drY=S0l|AxfsJ|tE zD7!b-j=YP48BBl7*A^W`Tyl64Mt<813_5n{87wakH;YA z5zL~W#RR}$Wa1509Y-PT*%&RgdO>gSKgpU1_#|rP?+WDSHc-EGp;%RB~LIB|ZoP zG5`629F;AD4Hn4KP3wL<6T!L=ceg~(#8KDRiE#G^xX{(&}RXn8DJW+LxJpv`$e7zjC;S;j+6ukyRr z6Fv!>KLkgHWuF@3X}0ei8qYYD?JCR_pj!Y^IUelTmA7N0>gUfqRYQJ^ zGHJ%Nkg%hno$t7<>;P^5BF7xyteJY4MIo%#lL3~A@|A^ zc)&w)oL}ZmYQ}M}r3zk>?{j~8{6L99MsAzHLM&cVE-)$rV~khc7yb4X3un;=D?YU$a6^EA9kQy=GWM8uhiw=i!E%l?W=hdW31 z)KqiR4U%dktmYz)WBqy6u4LJ81p5)U?n@$9Fs}p{5gcxrQ-ir3QI3@?-Fc)w2@;Fk z_`H&mj5L1$E`fig^sYu`VH7-UROfX*o7Psb0Hgt(l^(cges}|2DQT(qL_R)NknTxg zQ43)gO)P|#wj=-m0001P`MSV?Ci8l(qyWRPlU6>6?1GbB<-?$SxH&?gIoNE6pNGX5 zknAZ1<#j!$vSxqiYhNh2avIixOpYm`(<=aVN{f2OiY}L^BoOn7jgze}VTpcZD#ebX zZRn)bMYl&X3wzq&FdHEhb0{rXO+ehfV+=Wp-z94uJM2-J;|K#x_>^*x0>G(sLi_vR z&4F5@$!B^+I_PRM2b4cq7a@(MCG(kSWJ`BQgX5#Rv816J=+y2kDl*iEr9{8Pijbt+ ze_rr=PX$RPr(Fs-3t^`L6dq05#K-Z$JP50Q}zyPgJUkSS$|lh+z=Vy`!Z{A2z;s^j4^{ zMyAhO7zTP9yA+^-xT5|k&ZEXFa67h$%hcUF0b2Lb9Xe+LP@tF4M3=Ka_Xw9a2YCI0 zg3I%Wrsr(tkU$X!$wPDc=ersry<3>uwcxolGvpi1fEG<@Xm8BEc7P&u+A2Atw5u1l z{d5!*Rizp0EsMOmLmTR=Y?xpsI5nK}Xy=~ugXq#@h zoMMBXvt3L(F!NZcX5a)+8Oo6!anCWxlhm$YV|I|wDsFH9000vr<9Xg&Nv_!$2D|F@ z+N;%Hcai7G3CpyU0x~F9${#C86J07Q>m@iQ&r}7}5QYm{WPg~)w#0&OktDafbHdGN z>uK6hMYLCu1fT+s!T;i{#jh7`-8Ab?uh7PwdCLy`5m{INH&s~Y z$6Ueisq@=+Z3vq^HT~<)y_EugLNgxJYi+nKVa@R^tYboxi@V{m+>;ahGhevZHr%+~Y3h@8N5vGEVyPw?n>% zuj^CRw57Wja_-_j%)YMeQM-Kcms8e9-iwB|mM&=(Z_o+-Y|1pFO_Os^#)b3q&-uof z2YP=y_u7rG^V9;?T&@O&sK}; Y`(~DCB_7KM&Rj6gVOKZ+HjXp`0BKyHyZ`_I literal 0 HcmV?d00001 diff --git a/mastodon/src/main/res/drawable/ic_campaign_20px.xml b/mastodon/src/main/res/drawable/ic_campaign_20px.xml new file mode 100644 index 000000000..b386285c5 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_campaign_20px.xml @@ -0,0 +1,9 @@ + + + diff --git a/mastodon/src/main/res/interpolator-v21/cubic_bezier_default.xml b/mastodon/src/main/res/interpolator-v21/cubic_bezier_default.xml new file mode 100644 index 000000000..9d568940b --- /dev/null +++ b/mastodon/src/main/res/interpolator-v21/cubic_bezier_default.xml @@ -0,0 +1,3 @@ + + diff --git a/mastodon/src/main/res/layout/sheet_donation_success.xml b/mastodon/src/main/res/layout/sheet_donation_success.xml new file mode 100644 index 000000000..a96006654 --- /dev/null +++ b/mastodon/src/main/res/layout/sheet_donation_success.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + +