mirror of
				https://framagit.org/tom79/fedilab-tube
				synced 2025-06-05 21:09:11 +02:00 
			
		
		
		
	Merge branch 'donation_google' into develop
# Conflicts: # .gitignore
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -12,3 +12,4 @@ | ||||
| /app/google_full/ | ||||
| /app/google_acad/ | ||||
| /app/src/google_donation/res/values/data.xml | ||||
| /keystore.properties | ||||
|   | ||||
| @@ -1,7 +1,21 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply plugin: "androidx.navigation.safeargs" | ||||
|  | ||||
|  | ||||
| def keystorePropertiesFile = rootProject.file("keystore.properties") | ||||
| def keystoreProperties = new Properties() | ||||
| keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) | ||||
|  | ||||
| android { | ||||
|     signingConfigs { | ||||
|         full_version { | ||||
|             storeFile file(keystoreProperties['storeFile']) | ||||
|             storePassword keystoreProperties['storePassword'] | ||||
|             keyPassword keystoreProperties['keyPassword'] | ||||
|             keyAlias keystoreProperties['keyAlias'] | ||||
|  | ||||
|         } | ||||
|     } | ||||
|     compileSdkVersion 30 | ||||
|     buildToolsVersion "30.0.2" | ||||
|  | ||||
| @@ -9,8 +23,8 @@ android { | ||||
|  | ||||
|         minSdkVersion 21 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 34 | ||||
|         versionName "1.11.0" | ||||
|         versionCode 35 | ||||
|         versionName "1.11.1-test" | ||||
|         multiDexEnabled true | ||||
|         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||||
|     } | ||||
| @@ -22,6 +36,7 @@ android { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||||
|             signingConfig signingConfigs.full_version | ||||
|         } | ||||
|     } | ||||
|     compileOptions { | ||||
| @@ -117,27 +132,27 @@ android { | ||||
|     sourceSets { | ||||
|         fdroid_peertube_apps_educ { | ||||
|             res.srcDirs = ['src/main/res', 'src/acad/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/acad/java'] | ||||
|             java.srcDirs = ['src/main/java', 'src/acad/java', 'src/no_google_donation/java'] | ||||
|         } | ||||
|         google_peertube_apps_educ { | ||||
|             res.srcDirs = ['src/main/res', 'src/acad/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/acad/java'] | ||||
|             java.srcDirs = ['src/main/java', 'src/acad/java', 'src/no_google_donation/java'] | ||||
|         } | ||||
|         fdroid_full { | ||||
|             res.srcDirs = ['src/main/res', 'src/full/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java', 'src/no_google_donation/java'] | ||||
|         } | ||||
|         google_full { | ||||
|             res.srcDirs = ['src/main/res', 'src/full/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java'] | ||||
|             res.srcDirs = ['src/main/res', 'src/full/res', 'src/google_donation/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java', 'src/google_donation/java'] | ||||
|         } | ||||
|         queermotion { | ||||
|             res.srcDirs = ['src/main/res', 'src/queermotion/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java', 'src/no_google_donation/java'] | ||||
|         } | ||||
|         bittube { | ||||
|             res.srcDirs = ['src/main/res', 'src/bittube/res'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java'] | ||||
|             java.srcDirs = ['src/main/java', 'src/full/java', 'src/no_google_donation/java'] | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -200,6 +215,7 @@ dependencies { | ||||
|     implementation 'com.fasterxml.jackson.core:jackson-core:2.12.0' | ||||
|     implementation 'org.slf4j:slf4j-simple:1.7.30' | ||||
|  | ||||
|     google_fullImplementation "com.android.billingclient:billing:3.0.2" | ||||
|  | ||||
|     fdroid_peertube_apps_educImplementation 'org.matomo.sdk:tracker:4.1.2' | ||||
|     google_peertube_apps_educImplementation 'org.matomo.sdk:tracker:4.1.2' | ||||
|   | ||||
| @@ -0,0 +1,278 @@ | ||||
| package app.fedilab.fedilabtube; | ||||
| /* Copyright 2021 Thomas Schneider | ||||
|  * | ||||
|  * This file is a part of TubeLab | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|  * GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|  * Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|  * see <http://www.gnu.org/licenses>. */ | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentStatePagerAdapter; | ||||
| import androidx.viewpager.widget.PagerAdapter; | ||||
| import androidx.viewpager.widget.ViewPager; | ||||
|  | ||||
| import com.android.billingclient.api.AcknowledgePurchaseParams; | ||||
| import com.android.billingclient.api.BillingClient; | ||||
| import com.android.billingclient.api.BillingClientStateListener; | ||||
| import com.android.billingclient.api.BillingResult; | ||||
| import com.android.billingclient.api.ConsumeParams; | ||||
| import com.android.billingclient.api.ConsumeResponseListener; | ||||
| import com.android.billingclient.api.Purchase; | ||||
| import com.android.billingclient.api.PurchasesUpdatedListener; | ||||
| import com.android.billingclient.api.SkuDetailsParams; | ||||
| import com.google.android.material.snackbar.Snackbar; | ||||
| import com.google.android.material.tabs.TabLayout; | ||||
|  | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
|  | ||||
| import app.fedilab.fedilabtube.databinding.ActivityDonationBinding; | ||||
|  | ||||
| import app.fedilab.fedilabtube.fragment.MySubscriptionDonationsFragment; | ||||
| import app.fedilab.fedilabtube.fragment.DonationsFragment; | ||||
|  | ||||
|  | ||||
| public class DonationActivity extends AppCompatActivity implements PurchasesUpdatedListener { | ||||
|  | ||||
|  | ||||
|     DonationsFragment donationsFragment; | ||||
|     DonationsFragment subscriptionDonationsFragment; | ||||
|     MySubscriptionDonationsFragment mySubscriptionDonationsFragment; | ||||
|     private ActivityDonationBinding binding; | ||||
|     private BillingClient billingClient; | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         binding = ActivityDonationBinding.inflate(getLayoutInflater()); | ||||
|         View view = binding.getRoot(); | ||||
|         setContentView(view); | ||||
|         billingClient = BillingClient.newBuilder(this) | ||||
|                 .setListener(this) | ||||
|                 .enablePendingPurchases() | ||||
|                 .build(); | ||||
|         billingClient.startConnection(new BillingClientStateListener() { | ||||
|             @Override | ||||
|             public void onBillingSetupFinished(@NotNull BillingResult billingResult) { | ||||
|                 if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { | ||||
|                     // The BillingClient is ready. You can query purchases here. | ||||
|                     donationsFragment.initialized(billingClient); | ||||
|                     subscriptionDonationsFragment.initialized(billingClient); | ||||
|  | ||||
|                     List<Purchase> purchases = queryPurchases(); | ||||
|                     if (purchases != null) { | ||||
|                         for (Purchase purchase : purchases) { | ||||
|                             if (!purchase.isAutoRenewing()) { | ||||
|                                 ConsumeParams consumeParams = | ||||
|                                         ConsumeParams.newBuilder() | ||||
|                                                 .setPurchaseToken(purchase.getPurchaseToken()) | ||||
|                                                 .build(); | ||||
|  | ||||
|                                 ConsumeResponseListener listener = (billingResult1, purchaseToken) -> { | ||||
|                                     //noinspection StatementWithEmptyBody | ||||
|                                     if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK) { | ||||
|                                         // Handle the success of the consume operation. | ||||
|                                     } | ||||
|                                 }; | ||||
|                                 billingClient.consumeAsync(consumeParams, listener); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onBillingServiceDisconnected() { | ||||
|                 // Try to restart the connection on the next request to | ||||
|                 // Google Play by calling the startConnection() method. | ||||
|             } | ||||
|         }); | ||||
|         if (getSupportActionBar() != null) | ||||
|             getSupportActionBar().setDisplayHomeAsUpEnabled(true); | ||||
|         donationsFragment = new DonationsFragment(); | ||||
|         Bundle bundle1 = new Bundle(); | ||||
|         bundle1.putSerializable("isSubscriptions", false); | ||||
|         donationsFragment.setArguments(bundle1); | ||||
|  | ||||
|  | ||||
|         subscriptionDonationsFragment = new DonationsFragment(); | ||||
|         Bundle bundle2 = new Bundle(); | ||||
|         bundle2.putSerializable("isSubscriptions", true); | ||||
|         subscriptionDonationsFragment.setArguments(bundle2); | ||||
|  | ||||
|         mySubscriptionDonationsFragment = new MySubscriptionDonationsFragment(); | ||||
|  | ||||
|         binding.tablayout.addTab(binding.tablayout.newTab().setText(getString(R.string.one_time))); | ||||
|         binding.tablayout.addTab(binding.tablayout.newTab().setText(getString(R.string.subscriptions))); | ||||
|         binding.tablayout.addTab(binding.tablayout.newTab().setText(getString(R.string.my_subscriptions))); | ||||
|         binding.viewpager.setOffscreenPageLimit(3); | ||||
|  | ||||
|         PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager()); | ||||
|         binding.viewpager.setAdapter(mPagerAdapter); | ||||
|         binding.viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { | ||||
|             @Override | ||||
|             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { | ||||
|  | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onPageSelected(int position) { | ||||
|                 TabLayout.Tab tab = binding.tablayout.getTabAt(position); | ||||
|                 if (tab != null) | ||||
|                     tab.select(); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onPageScrollStateChanged(int state) { | ||||
|  | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         binding.tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { | ||||
|             @Override | ||||
|             public void onTabSelected(TabLayout.Tab tab) { | ||||
|                 binding.viewpager.setCurrentItem(tab.getPosition()); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onTabUnselected(TabLayout.Tab tab) { | ||||
|  | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onTabReselected(TabLayout.Tab tab) { | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private List<Purchase> queryPurchases() { | ||||
|         Purchase.PurchasesResult purchasesResult = billingClient.queryPurchases(BillingClient.SkuType.SUBS); | ||||
|         List<Purchase> purchases = purchasesResult.getPurchasesList(); | ||||
|         List<String> isSubscriptions = new ArrayList<>(); | ||||
|         HashMap<String, Purchase> map = new HashMap<>(); | ||||
|         if (purchases != null) { | ||||
|             for (Purchase purchase : purchases) { | ||||
|                 try { | ||||
|                     if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { | ||||
|                         JSONObject purchaseJson = new JSONObject(purchase.getOriginalJson()); | ||||
|                         String productId = purchaseJson.getString("productId"); | ||||
|                         isSubscriptions.add(productId); | ||||
|                         map.put(productId, purchase); | ||||
|                     } | ||||
|                 } catch (JSONException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|             SkuDetailsParams.Builder paramsSub = SkuDetailsParams.newBuilder(); | ||||
|             paramsSub.setSkusList(isSubscriptions).setType(BillingClient.SkuType.SUBS); | ||||
|             billingClient.querySkuDetailsAsync(paramsSub.build(), | ||||
|                     (billingResult2, skuDetailsList) -> mySubscriptionDonationsFragment.initialized(skuDetailsList, map, billingClient)); | ||||
|         } else { | ||||
|             mySubscriptionDonationsFragment.initialized(new ArrayList<>(), map, billingClient); | ||||
|         } | ||||
|         return purchases; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == android.R.id.home) { | ||||
|             finish(); | ||||
|             return true; | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) { | ||||
|         String message; | ||||
|         if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK | ||||
|                 && purchases != null) { | ||||
|             for (Purchase purchase : purchases) { | ||||
|                 if (!purchase.isAutoRenewing()) { | ||||
|                     ConsumeParams consumeParams = | ||||
|                             ConsumeParams.newBuilder() | ||||
|                                     .setPurchaseToken(purchase.getPurchaseToken()) | ||||
|                                     .build(); | ||||
|  | ||||
|                     ConsumeResponseListener listener = (billingResult1, purchaseToken) -> { | ||||
|                     }; | ||||
|                     billingClient.consumeAsync(consumeParams, listener); | ||||
|                 } else { | ||||
|                     if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { | ||||
|                         if (!purchase.isAcknowledged()) { | ||||
|                             AcknowledgePurchaseParams acknowledgePurchaseParams = | ||||
|                                     AcknowledgePurchaseParams.newBuilder() | ||||
|                                             .setPurchaseToken(purchase.getPurchaseToken()) | ||||
|                                             .build(); | ||||
|                             billingClient.acknowledgePurchase(acknowledgePurchaseParams, b -> { | ||||
|                             }); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     queryPurchases(); | ||||
|                 } | ||||
|             } | ||||
|             message = getString(R.string.donation_succeeded_null); | ||||
|         } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { | ||||
|             message = getString(R.string.donation_cancelled); | ||||
|         } else { | ||||
|             message = getString(R.string.toast_error); | ||||
|         } | ||||
|         View parentLayout = findViewById(android.R.id.content); | ||||
|         Snackbar snackbar = Snackbar.make(parentLayout, message, Snackbar.LENGTH_INDEFINITE); | ||||
|         snackbar.setAction(R.string.close, view -> snackbar.dismiss()); | ||||
|         snackbar.show(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Pager adapter for the 2 fragments | ||||
|      */ | ||||
|     private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { | ||||
|  | ||||
|         ScreenSlidePagerAdapter(FragmentManager fm) { | ||||
|             super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); | ||||
|         } | ||||
|  | ||||
|         @NotNull | ||||
|         @Override | ||||
|         public Fragment getItem(int position) { | ||||
|             if (position == 0) { | ||||
|                 return donationsFragment; | ||||
|             } else if (position == 1) { | ||||
|                 return subscriptionDonationsFragment; | ||||
|             } else { | ||||
|                 return mySubscriptionDonationsFragment; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         @Override | ||||
|         public int getCount() { | ||||
|             return 3; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,91 @@ | ||||
| package app.fedilab.fedilabtube.drawable; | ||||
| /* Copyright 2021 Thomas Schneider | ||||
|  * | ||||
|  * This file is a part of TubeLab | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|  * GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|  * Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|  * see <http://www.gnu.org/licenses>. */ | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
|  | ||||
| import com.android.billingclient.api.BillingClient; | ||||
| import com.android.billingclient.api.BillingFlowParams; | ||||
| import com.android.billingclient.api.SkuDetails; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
|  | ||||
| import app.fedilab.fedilabtube.DonationActivity; | ||||
| import app.fedilab.fedilabtube.R; | ||||
| import app.fedilab.fedilabtube.databinding.DrawerDonationBinding; | ||||
|  | ||||
|  | ||||
| public class DonationButtonAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     private final List<SkuDetails> skuDetails; | ||||
|     private final BillingClient billingClient; | ||||
|     private Context context; | ||||
|     private final boolean isSubscription; | ||||
|  | ||||
|     public DonationButtonAdapter(List<SkuDetails> skuDetails, BillingClient billingClient, boolean subscription) { | ||||
|         this.isSubscription = subscription; | ||||
|         this.skuDetails = skuDetails; | ||||
|         this.billingClient = billingClient; | ||||
|     } | ||||
|  | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||
|         context = parent.getContext(); | ||||
|         DrawerDonationBinding itemBinding = DrawerDonationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); | ||||
|         return new ViewHolder(itemBinding); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { | ||||
|         final ViewHolder holder = (ViewHolder) viewHolder; | ||||
|         SkuDetails skuDetail = skuDetails.get(position); | ||||
|         String currency = skuDetail.getPriceCurrencyCode(); | ||||
|         String price = skuDetail.getPrice(); | ||||
|         if (isSubscription) { | ||||
|             holder.binding.buttonDonation.setText(String.format(Locale.getDefault(), "%s %s / %s", price, currency, context.getString(R.string.month))); | ||||
|         } else { | ||||
|             holder.binding.buttonDonation.setText(String.format(Locale.getDefault(), "%s %s", price, currency)); | ||||
|         } | ||||
|  | ||||
|         holder.binding.buttonDonation.setOnClickListener(v -> { | ||||
|             BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() | ||||
|                     .setSkuDetails(skuDetail) | ||||
|                     .build(); | ||||
|             billingClient.launchBillingFlow((DonationActivity) context, billingFlowParams); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return skuDetails.size(); | ||||
|     } | ||||
|  | ||||
|     static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|         DrawerDonationBinding binding; | ||||
|  | ||||
|         ViewHolder(DrawerDonationBinding itemView) { | ||||
|             super(itemView.getRoot()); | ||||
|             binding = itemView; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,128 @@ | ||||
| package app.fedilab.fedilabtube.drawable; | ||||
| /* Copyright 2021 Thomas Schneider | ||||
|  * | ||||
|  * This file is a part of TubeLab | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|  * GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|  * Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|  * see <http://www.gnu.org/licenses>. */ | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
|  | ||||
| import com.android.billingclient.api.BillingClient; | ||||
| import com.android.billingclient.api.ConsumeParams; | ||||
| import com.android.billingclient.api.ConsumeResponseListener; | ||||
| import com.android.billingclient.api.Purchase; | ||||
| import com.android.billingclient.api.SkuDetails; | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import app.fedilab.fedilabtube.R; | ||||
| import app.fedilab.fedilabtube.databinding.DrawerMyDonationBinding; | ||||
| import es.dmoral.toasty.Toasty; | ||||
|  | ||||
|  | ||||
| public class DonationHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     private final List<SkuDetails> skuDetailsList; | ||||
|     private final BillingClient billingClient; | ||||
|     private Context context; | ||||
|     private final HashMap<String, Purchase> map; | ||||
|  | ||||
|     public DonationHistoryAdapter(List<SkuDetails> SkuDetailsList, HashMap<String, Purchase> map, BillingClient billingClient) { | ||||
|         this.skuDetailsList = SkuDetailsList; | ||||
|         this.billingClient = billingClient; | ||||
|         this.map = map; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||
|         context = parent.getContext(); | ||||
|         DrawerMyDonationBinding itemBinding = DrawerMyDonationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); | ||||
|         return new ViewHolder(itemBinding); | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { | ||||
|         final ViewHolder holder = (ViewHolder) viewHolder; | ||||
|         SkuDetails skuDetails = skuDetailsList.get(position); | ||||
|         holder.binding.productTitle.setText(skuDetails.getTitle()); | ||||
|         holder.binding.productName.setText(skuDetails.getDescription()); | ||||
|         holder.binding.productInfo.setText(skuDetails.getOriginalPrice()); | ||||
|  | ||||
|         holder.binding.cancelDonation.setOnClickListener(v -> { | ||||
|  | ||||
|             AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); | ||||
|             dialogBuilder.setMessage(R.string.cancel_subscription_confirm); | ||||
|  | ||||
|             dialogBuilder.setPositiveButton(R.string.cancel_subscription, (dialog, id) -> { | ||||
|                 JSONObject skudetailsJson; | ||||
|                 try { | ||||
|                     skudetailsJson = new JSONObject(skuDetails.getOriginalJson()); | ||||
|                     String productId = skudetailsJson.getString("productId"); | ||||
|                     if (map.containsKey(productId)) { | ||||
|                         Purchase purchase = map.get(productId); | ||||
|                         if (purchase != null) { | ||||
|                             ConsumeParams consumeParams = | ||||
|                                     ConsumeParams.newBuilder() | ||||
|                                             .setPurchaseToken(purchase.getPurchaseToken()) | ||||
|                                             .build(); | ||||
|                             if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { | ||||
|                                 ConsumeResponseListener listener = (billingResult1, purchaseToken) -> { | ||||
|                                     if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK) { | ||||
|                                         Toasty.success(context, context.getString(R.string.subscription_cancelled), Toasty.LENGTH_LONG).show(); | ||||
|                                     } | ||||
|                                     skuDetailsList.remove(skuDetails); | ||||
|                                     notifyDataSetChanged(); | ||||
|                                 }; | ||||
|                                 billingClient.consumeAsync(consumeParams, listener); | ||||
|                             } | ||||
|  | ||||
|                         } | ||||
|                     } | ||||
|                 } catch (JSONException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|                 dialog.dismiss(); | ||||
|             }); | ||||
|             dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); | ||||
|             AlertDialog alertDialogLogoutAccount = dialogBuilder.create(); | ||||
|             alertDialogLogoutAccount.show(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return skuDetailsList.size(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|         DrawerMyDonationBinding binding; | ||||
|  | ||||
|         ViewHolder(DrawerMyDonationBinding itemView) { | ||||
|             super(itemView.getRoot()); | ||||
|             binding = itemView; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,112 @@ | ||||
| package app.fedilab.fedilabtube.fragment; | ||||
| /* Copyright 2021 Thomas Schneider | ||||
|  * | ||||
|  * This file is a part of TubeLab | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|  * GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|  * Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|  * see <http://www.gnu.org/licenses>. */ | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
|  | ||||
| import com.android.billingclient.api.BillingClient; | ||||
| import com.android.billingclient.api.SkuDetailsParams; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import app.fedilab.fedilabtube.R; | ||||
| import app.fedilab.fedilabtube.databinding.FragmentDonationsBinding; | ||||
| import app.fedilab.fedilabtube.drawable.DonationButtonAdapter; | ||||
|  | ||||
|  | ||||
| public class DonationsFragment extends Fragment { | ||||
|  | ||||
|     public static final String[] donations = {"1", "2", "5", "10"}; | ||||
|     private FragmentDonationsBinding binding; | ||||
|     private View rootView; | ||||
|     private Context context; | ||||
|     private boolean isSubscriptions; | ||||
|  | ||||
|     @Override | ||||
|     public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | ||||
|         binding = FragmentDonationsBinding.inflate(LayoutInflater.from(context)); | ||||
|         rootView = binding.getRoot(); | ||||
|         context = getContext(); | ||||
|         Bundle bundle = this.getArguments(); | ||||
|         if (bundle != null) { | ||||
|             isSubscriptions = bundle.getBoolean("isSubscriptions", false); | ||||
|         } | ||||
|         int donationText; | ||||
|         if (isSubscriptions) { | ||||
|             donationText = R.string.recurrent_donation_text; | ||||
|         } else { | ||||
|             donationText = R.string.one_time_donation_text; | ||||
|         } | ||||
|         binding.donationText.setText(donationText); | ||||
|         binding.loader.setVisibility(View.VISIBLE); | ||||
|         binding.lvProducts.setVisibility(View.GONE); | ||||
|         return rootView; | ||||
|     } | ||||
|  | ||||
|     public void initialized(BillingClient bc) { | ||||
|  | ||||
|  | ||||
|         List<String> donationsList = new ArrayList<>(); | ||||
|         for (String val : donations) { | ||||
|             donationsList.add("tubelab_donation_" + val + (isSubscriptions ? "_s" : "")); | ||||
|         } | ||||
|         SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); | ||||
|         if (isSubscriptions) { | ||||
|             params.setSkusList(donationsList).setType(BillingClient.SkuType.SUBS); | ||||
|         } else { | ||||
|             params.setSkusList(donationsList).setType(BillingClient.SkuType.INAPP); | ||||
|         } | ||||
|         bc.querySkuDetailsAsync(params.build(), | ||||
|                 (billingResult, skuDetailsList) -> { | ||||
|                     binding.loader.setVisibility(View.GONE); | ||||
|                     binding.lvProducts.setVisibility(View.VISIBLE); | ||||
|                     if (skuDetailsList != null) { | ||||
|                         Collections.sort(skuDetailsList, (obj1, obj2) -> obj1.getPrice().compareTo(obj2.getPrice())); | ||||
|                     } | ||||
|                     DonationButtonAdapter donationButtonAdapter = new DonationButtonAdapter(skuDetailsList, bc, isSubscriptions); | ||||
|                     binding.lvProducts.setAdapter(donationButtonAdapter); | ||||
|                     binding.lvProducts.setLayoutManager(new LinearLayoutManager(context)); | ||||
|                 }); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
|         rootView = null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(Bundle saveInstance) { | ||||
|         super.onCreate(saveInstance); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onAttach(@NonNull Context context) { | ||||
|         super.onAttach(context); | ||||
|         this.context = context; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,80 @@ | ||||
| package app.fedilab.fedilabtube.fragment; | ||||
| /* Copyright 2021 Thomas Schneider | ||||
|  * | ||||
|  * This file is a part of TubeLab | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|  * GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|  * Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|  * see <http://www.gnu.org/licenses>. */ | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
|  | ||||
| import com.android.billingclient.api.BillingClient; | ||||
| import com.android.billingclient.api.Purchase; | ||||
| import com.android.billingclient.api.SkuDetails; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
|  | ||||
| import app.fedilab.fedilabtube.databinding.FragmentMyDonationsBinding; | ||||
| import app.fedilab.fedilabtube.drawable.DonationHistoryAdapter; | ||||
|  | ||||
| public class MySubscriptionDonationsFragment extends Fragment { | ||||
|  | ||||
|     private FragmentMyDonationsBinding binding; | ||||
|     private View rootView; | ||||
|     private Context context; | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | ||||
|         binding = FragmentMyDonationsBinding.inflate(LayoutInflater.from(context)); | ||||
|         rootView = binding.getRoot(); | ||||
|         context = getContext(); | ||||
|         binding.loader.setVisibility(View.VISIBLE); | ||||
|         binding.lvPurchases.setVisibility(View.GONE); | ||||
|         return rootView; | ||||
|     } | ||||
|  | ||||
|     public void initialized(List<SkuDetails> skuDetailsList, HashMap<String, Purchase> map, BillingClient bc) { | ||||
|         binding.loader.setVisibility(View.GONE); | ||||
|         binding.lvPurchases.setVisibility(View.VISIBLE); | ||||
|  | ||||
|         DonationHistoryAdapter donationHistoryAdapter = new DonationHistoryAdapter(skuDetailsList, map, bc); | ||||
|         binding.lvPurchases.setAdapter(donationHistoryAdapter); | ||||
|         binding.lvPurchases.setLayoutManager(new LinearLayoutManager(context)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
|         rootView = null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(Bundle saveInstance) { | ||||
|         super.onCreate(saveInstance); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onAttach(@NonNull Context context) { | ||||
|         super.onAttach(context); | ||||
|         this.context = context; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										60
									
								
								app/src/google_donation/res/layout/activity_donation.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/src/google_donation/res/layout/activity_donation.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?><!-- | ||||
|     Copyright 2021 Thomas Schneider | ||||
|  | ||||
|     This file is a part of TubeLab | ||||
|  | ||||
|     This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|     GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|     License, or (at your option) any later version. | ||||
|  | ||||
|     TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|     Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
| --> | ||||
| <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:fitsSystemWindows="true" | ||||
|     tools:context=".ShowChannelActivity"> | ||||
|  | ||||
|     <com.google.android.material.appbar.AppBarLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:fitsSystemWindows="true" | ||||
|         app:theme="@style/ThemeOverlay.AppCompat.ActionBar"> | ||||
|  | ||||
|         <com.google.android.material.appbar.CollapsingToolbarLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:fitsSystemWindows="true" | ||||
|             app:contentScrim="?attr/colorPrimary" | ||||
|             app:expandedTitleMarginEnd="64dp" | ||||
|             app:expandedTitleMarginStart="48dp" | ||||
|             app:layout_scrollFlags="scroll|exitUntilCollapsed"> | ||||
|  | ||||
|  | ||||
|         </com.google.android.material.appbar.CollapsingToolbarLayout> | ||||
|  | ||||
|         <com.google.android.material.tabs.TabLayout | ||||
|             android:id="@+id/tablayout" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             app:tabGravity="fill" | ||||
|             app:tabMode="fixed" | ||||
|             app:tabSelectedTextColor="?colorAccent" | ||||
|             app:tabTextColor="@android:color/white" /> | ||||
|     </com.google.android.material.appbar.AppBarLayout> | ||||
|  | ||||
|     <androidx.viewpager.widget.ViewPager | ||||
|         android:id="@+id/viewpager" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="5dp" | ||||
|         app:layout_behavior="@string/appbar_scrolling_view_behavior" /> | ||||
|  | ||||
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | ||||
							
								
								
									
										23
									
								
								app/src/google_donation/res/layout/drawer_donation.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/src/google_donation/res/layout/drawer_donation.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content"> | ||||
|  | ||||
|     <Button | ||||
|         android:id="@+id/button_donation" | ||||
|         style="@style/Widget.AppCompat.Button.Colored" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="20dp" | ||||
|         android:paddingStart="40dp" | ||||
|         android:paddingTop="15dp" | ||||
|         android:paddingEnd="40dp" | ||||
|         android:paddingBottom="15dp" | ||||
|         android:textSize="25sp" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|  | ||||
							
								
								
									
										54
									
								
								app/src/google_donation/res/layout/drawer_my_donation.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								app/src/google_donation/res/layout/drawer_my_donation.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|  | ||||
|     android:layout_margin="10dp"> | ||||
|  | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_margin="10dp"> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/product_title" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:textSize="16sp" | ||||
|             app:layout_constraintEnd_toStartOf="@+id/cancel_donation" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" /> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/product_name" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="10dp" | ||||
|             app:layout_constraintEnd_toStartOf="@+id/cancel_donation" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/product_title" /> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/product_info" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="10dp" | ||||
|             app:layout_constraintEnd_toStartOf="@+id/cancel_donation" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/product_name" /> | ||||
|  | ||||
|         <ImageButton | ||||
|             android:id="@+id/cancel_donation" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:contentDescription="@string/cancel" | ||||
|             android:src="@drawable/ic_baseline_delete_24" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" /> | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|  | ||||
| </androidx.cardview.widget.CardView> | ||||
|  | ||||
|  | ||||
							
								
								
									
										59
									
								
								app/src/google_donation/res/layout/fragment_donations.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/src/google_donation/res/layout/fragment_donations.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?><!-- | ||||
|     Copyright 2021 Thomas Schneider | ||||
|  | ||||
|     This file is a part of TubeLab | ||||
|  | ||||
|     This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|     GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|     License, or (at your option) any later version. | ||||
|  | ||||
|     TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|     Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
| --> | ||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:paddingLeft="@dimen/fab_margin" | ||||
|     android:paddingRight="@dimen/fab_margin"> | ||||
|  | ||||
|     <LinearLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:orientation="vertical"> | ||||
|  | ||||
|         <TextView | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_margin="20dp" | ||||
|             android:gravity="center" | ||||
|             android:id="@+id/donation_text" /> | ||||
|  | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:id="@+id/lv_products" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:divider="@null" | ||||
|             android:scrollbars="none" /> | ||||
|     </LinearLayout> | ||||
|  | ||||
|     <!-- Main Loader --> | ||||
|     <RelativeLayout | ||||
|         android:id="@+id/loader" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:gravity="center" | ||||
|         android:visibility="gone"> | ||||
|  | ||||
|         <com.github.ybq.android.spinkit.SpinKitView xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|             style="@style/progress" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             app:SpinKit_Color="?colorAccent" /> | ||||
|     </RelativeLayout> | ||||
| </RelativeLayout> | ||||
|  | ||||
							
								
								
									
										59
									
								
								app/src/google_donation/res/layout/fragment_my_donations.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/src/google_donation/res/layout/fragment_my_donations.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?><!-- | ||||
|     Copyright 2021 Thomas Schneider | ||||
|  | ||||
|     This file is a part of TubeLab | ||||
|  | ||||
|     This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|     GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|     License, or (at your option) any later version. | ||||
|  | ||||
|     TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|     Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
| --> | ||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:paddingLeft="@dimen/fab_margin" | ||||
|     android:paddingRight="@dimen/fab_margin"> | ||||
|  | ||||
|     <LinearLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:orientation="vertical"> | ||||
|  | ||||
|         <TextView | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_margin="20dp" | ||||
|             android:gravity="center" | ||||
|             android:text="@string/donations_description" /> | ||||
|  | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:id="@+id/lv_purchases" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:divider="@null" | ||||
|             android:scrollbars="none" /> | ||||
|     </LinearLayout> | ||||
|  | ||||
|     <!-- Main Loader --> | ||||
|     <RelativeLayout | ||||
|         android:id="@+id/loader" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:gravity="center" | ||||
|         android:visibility="gone"> | ||||
|  | ||||
|         <com.github.ybq.android.spinkit.SpinKitView xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|             style="@style/progress" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             app:SpinKit_Color="?colorAccent" /> | ||||
|     </RelativeLayout> | ||||
| </RelativeLayout> | ||||
|  | ||||
| @@ -3,7 +3,7 @@ | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     package="app.fedilab.fedilabtube"> | ||||
|  | ||||
|  | ||||
|     <uses-permission android:name="com.android.vending.BILLING" /> | ||||
|     <application | ||||
|         android:name=".FedilabTube" | ||||
|         android:allowBackup="false" | ||||
| @@ -30,5 +30,10 @@ | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".DonationActivity" | ||||
|             android:configChanges="orientation|screenSize" | ||||
|             android:label="@string/support_the_app" | ||||
|             android:windowSoftInputMode="stateAlwaysHidden" /> | ||||
|     </application> | ||||
| </manifest> | ||||
| @@ -687,7 +687,11 @@ public class MainActivity extends AppCompatActivity implements ChromeCastsListen | ||||
|         MenuItem incognitoItem = menu.findItem(R.id.action_incognito); | ||||
|         MenuItem instanceItem = menu.findItem(R.id.action_change_instance); | ||||
|         MenuItem accountItem = menu.findItem(R.id.action_account); | ||||
|         MenuItem donateItem = menu.findItem(R.id.action_donate); | ||||
|  | ||||
|         if (BuildConfig.full_instances && BuildConfig.google_restriction) { | ||||
|             donateItem.setVisible(true); | ||||
|         } | ||||
|  | ||||
|         if (BuildConfig.surfing_mode && ((Helper.isLoggedIn(MainActivity.this) && typeOfConnection == NORMAL) || typeOfConnection == SURFING)) { | ||||
|             binding.instances.setVisibility(View.VISIBLE); | ||||
| @@ -847,6 +851,9 @@ public class MainActivity extends AppCompatActivity implements ChromeCastsListen | ||||
|         } else if (item.getItemId() == R.id.action_about) { | ||||
|             Intent intent = new Intent(MainActivity.this, AboutActivity.class); | ||||
|             startActivity(intent); | ||||
|         } else if (item.getItemId() == R.id.action_donate) { | ||||
|             Intent intent = new Intent(MainActivity.this, DonationActivity.class); | ||||
|             startActivity(intent); | ||||
|         } else if (item.getItemId() == R.id.action_incognito) { | ||||
|             item.setChecked(!item.isChecked()); | ||||
|             final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); | ||||
|   | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_baseline_attach_money_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/drawable/ic_baseline_attach_money_24.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:tint="?attr/colorControlNormal" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z" /> | ||||
| </vector> | ||||
| @@ -67,4 +67,10 @@ | ||||
|         android:icon="@drawable/ic_baseline_info_24" | ||||
|         android:title="@string/about_the_app" | ||||
|         app:showAsAction="ifRoom" /> | ||||
|     <item | ||||
|         android:id="@+id/action_donate" | ||||
|         android:icon="@drawable/ic_baseline_attach_money_24" | ||||
|         android:title="@string/make_a_donation" | ||||
|         android:visible="false" | ||||
|         app:showAsAction="ifRoom" /> | ||||
| </menu> | ||||
|   | ||||
| @@ -455,5 +455,21 @@ | ||||
|     <string name="watermark">Watermark</string> | ||||
|     <string name="toast_code_error">An error occurred! The instance did not return an authorisation code!</string> | ||||
|     <string name="remote_account_from"><b>%1$s</b> remote account connected with the app.\n\nYou can proceed to some limited actions.</string> | ||||
|     <string name="donate">Donate</string> | ||||
|     <string name="my_donations">My donations</string> | ||||
|     <string name="one_time_donation_text">Here, you can make a one time donation for supporting the development of the app. This action will not bring extra features!</string> | ||||
|     <string name="recurrent_donation_text">Here, you can make a recurrent donation for supporting the development of the app. This action will not bring extra features!</string> | ||||
|     <string name="make_a_donation">Make a donation</string> | ||||
|     <string name="donations_description">Here you will find the list of your recurrent  donations made to support the development of the app! Thank you!</string> | ||||
|     <string name="support_the_app">Support the app</string> | ||||
|     <string name="donation_cancelled">Donation has been cancelled!</string> | ||||
|     <string name="donation_succeeded_null">Thank you for your donation!</string> | ||||
|     <string name="donation_succeeded">Thank you for your donation of %1$s!</string> | ||||
|     <string name="one_time">One time</string> | ||||
|     <string name="my_subscriptions">My subscription</string> | ||||
|     <string name="month">Month</string> | ||||
|     <string name="subscription_cancelled">Subscription cancelled!</string> | ||||
|     <string name="cancel_subscription">Cancel subscription</string> | ||||
|     <string name="cancel_subscription_confirm">Are you sure, you want to cancel that subscription?</string> | ||||
|  | ||||
| </resources> | ||||
| @@ -0,0 +1,20 @@ | ||||
| package app.fedilab.fedilabtube; | ||||
| /* Copyright 2021 Thomas Schneider | ||||
|  * | ||||
|  * This file is a part of TubeLab | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under the terms of the | ||||
|  * GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||||
|  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||||
|  * Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with TubeLab; if not, | ||||
|  * see <http://www.gnu.org/licenses>. */ | ||||
|  | ||||
| //Do nothing | ||||
| public class DonationActivity { | ||||
|  | ||||
| } | ||||
| @@ -20,7 +20,19 @@ apply plugin: 'de.undercouch.download' | ||||
|  | ||||
| group='com.github.TorrentStream' | ||||
|  | ||||
| def keystorePropertiesFile = rootProject.file("keystore.properties") | ||||
| def keystoreProperties = new Properties() | ||||
| keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) | ||||
|  | ||||
| android { | ||||
|     signingConfigs { | ||||
|         full_version { | ||||
|             storeFile file(keystoreProperties['storeFile']) | ||||
|             storePassword keystoreProperties['storePassword'] | ||||
|             keyAlias keystoreProperties['keyAlias'] | ||||
|             keyPassword keystoreProperties['keyPassword'] | ||||
|         } | ||||
|     } | ||||
|     compileSdkVersion 30 | ||||
|  | ||||
|     defaultConfig { | ||||
| @@ -32,6 +44,7 @@ android { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|             signingConfig signingConfigs.full_version | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user