diff --git a/mastodon/build.gradle b/mastodon/build.gradle
index 8fc25ecc..0328eaae 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 7a97cfce..122e86a7 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 00000000..5a72cd46
--- /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 6ca545c4..1770ccf3 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 bc19dec6..d4322135 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 f14140cd..ee5f8498 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 00000000..cce55203
--- /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 00000000..073d62d1
--- /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 00000000..8dcf659c
--- /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 00000000..86216b32
--- /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 00000000..aea38372
Binary files /dev/null and b/mastodon/src/main/res/drawable-nodpi/donation_successful_art.webp differ
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 00000000..b386285c
--- /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 00000000..9d568940
--- /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 00000000..a9600665
--- /dev/null
+++ b/mastodon/src/main/res/layout/sheet_donation_success.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values-hdpi/misc.xml b/mastodon/src/main/res/values-hdpi/misc.xml
new file mode 100644
index 00000000..0539fe64
--- /dev/null
+++ b/mastodon/src/main/res/values-hdpi/misc.xml
@@ -0,0 +1,4 @@
+
+
+ 150
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values-tvdpi/misc.xml b/mastodon/src/main/res/values-tvdpi/misc.xml
new file mode 100644
index 00000000..b712242e
--- /dev/null
+++ b/mastodon/src/main/res/values-tvdpi/misc.xml
@@ -0,0 +1,4 @@
+
+
+ 133
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values-xhdpi/misc.xml b/mastodon/src/main/res/values-xhdpi/misc.xml
new file mode 100644
index 00000000..cc9bd8ba
--- /dev/null
+++ b/mastodon/src/main/res/values-xhdpi/misc.xml
@@ -0,0 +1,4 @@
+
+
+ 200
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values-xxhdpi/misc.xml b/mastodon/src/main/res/values-xxhdpi/misc.xml
new file mode 100644
index 00000000..37e9754f
--- /dev/null
+++ b/mastodon/src/main/res/values-xxhdpi/misc.xml
@@ -0,0 +1,4 @@
+
+
+ 300
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values-xxxhdpi/misc.xml b/mastodon/src/main/res/values-xxxhdpi/misc.xml
new file mode 100644
index 00000000..19cd19f4
--- /dev/null
+++ b/mastodon/src/main/res/values-xxxhdpi/misc.xml
@@ -0,0 +1,4 @@
+
+
+ 400
+
\ No newline at end of file
diff --git a/mastodon/src/main/res/values/misc.xml b/mastodon/src/main/res/values/misc.xml
new file mode 100644
index 00000000..ff1f7fbe
--- /dev/null
+++ b/mastodon/src/main/res/values/misc.xml
@@ -0,0 +1,4 @@
+
+
+ 100
+
\ 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 a61ce3aa..e129ffe9 100644
--- a/mastodon/src/main/res/values/strings.xml
+++ b/mastodon/src/main/res/values/strings.xml
@@ -771,4 +771,7 @@
Monthly
Yearly
Currency
+ Spread the word
+ Thank you for your contribution!
+ You should receive an email confirming your donation soon.
\ No newline at end of file