From b2d49c31435a1d5e802aa605e842dc723c32db9c Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 15 Apr 2024 16:36:59 +0300 Subject: [PATCH] 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 5077aae0..c7148d80 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 6e226bb6..3a027e7e 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 00000000..bf8b711c --- /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 00000000..e6f018ef --- /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 43190c73..55cdac05 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 07e5059d..621c5a19 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 00000000..101369e1 --- /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 00000000..6ca545c4 --- /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 174aa233..1d60f042 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 00000000..6146abc7 --- /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 755238e8..35b9554d 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 00000000..819011d0 --- /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 00000000..4fa4ab52 --- /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 00000000..bbd98310 --- /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 00000000..de2ddedd --- /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 d1136625..3072547e 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 00000000..13f79a32 --- /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 00000000..2e796f13 --- /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 00000000..c4066a42 --- /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 00000000..5f252b53 --- /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 00000000..c25e4be1 --- /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 defa53bc..e39c2057 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 00000000..05cb1085 --- /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 00000000..4221dff3 --- /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 54bd3c2c..70c88808 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