diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README _JAVA.md b/README _JAVA.md index 06c6d18..5975d2e 100644 --- a/README _JAVA.md +++ b/README _JAVA.md @@ -1,33 +1,28 @@ -ZarinPal In App Billing - Purchase SDK | MPG -============================================ -ZarinPal Purchase SDK Provides payment methods on your Android Application. +# ZarinPal In App Billing - Purchase SDK | MPG +ZarinPal Purchase SDK Provides payment methods on your Android Application. +# Introduction -Introduction -============= ZarinPal in-app purchases are the simplest solution to selling digital products or content on Android apps. So many app developers who want to sell digital goods or offer premium membership to users can simply use the it, in-app billing process for smooth and easy checkouts. -

sample

+# Requirements -Requirements -============ - -* Android 5.0 (API level 21) and above -* Android Gradle Plugin 3.5.1 -* Gradle 5.4.1+ -* AndroidX (as of v11.0.0) +- Android 5.0 (API level 21) and above +- Android Gradle Plugin 3.5.1 and above(this 8.1.4) +- Gradle 5.4.1 and above (this 8.5) +- AndroidX (as of v11.0.0) -Installation -============ +# Installation **Step 1** Add this to your root build.gradle at the end of repositories. + ```gradle allprojects { ext.zarinpalSdkVersion = (LATEST_VERSION_REALEASE) //inform of Releases: https://github.com/ZarinPal/Android-SDK/releases @@ -35,41 +30,42 @@ Add this to your root build.gradle at the end of repositories. ... mavenCentral() } -``` +``` **Step 2** Add the dependency: + ```gradle dependencies { implementation 'com.zarinpal:payment-provider:ext.zarinpalSdkVersion' } -``` - +``` If your project and business trusted to ZarinPal, SDK ables to providing **Mobile Payment Gateway** on your App so You should add the **MPG** dependency: + ```gradle dependencies { implementation 'com.zarinpal:payment-provider:ext.zarinpalSdkVersion' implementation 'com.zarinpal:mpg:ext.zarinpalSdkVersion' } -``` +``` -How to use -========== +# How to use + +- add Permissions in your `Manifest.xml`: -* add Permissions in your `Manifest.xml`: ```xml -``` +``` -Initialize the billing client -============================= +# Initialize the billing client **Step 1** -* `ZarinPalClientBilling` provides to create the billing client instance: +- `ZarinPalClientBilling` provides to create the billing client instance: + ```java BillingClientStateListener listener = new BillingClientStateListener() { @@ -92,30 +88,30 @@ Initialize the billing client .setNightMode(AppCompatDelegate.MODE_NIGHT_YES) .build(); - -``` + +``` **Step 2** For start purchase you need a `Purchase` instance, `Purchase` has 3 type of Payment: -* as **Payment Request** by `asPaymentRequest()` -* as **Authority ID** by `asAuthority()` -* as **Sku ID** by `asSku()` +- as **Payment Request** by `asPaymentRequest()` +- as **Authority ID** by `asAuthority()` +- as **Sku ID** by `asSku()` If you would create payment Authority on Client, You must use `asPayementRequest()`, this method needs below parameters: **Require Parameters:** -* Merchant id: An unique ID of your business payment gateway. -* Amount: Amount of Purchase. -* Callback URL: A valid `URI` or `URL` Address for sending result purchase. -* Description: A Content for showing payer. +- Merchant id: An unique ID of your business payment gateway. +- Amount: Amount of Purchase. +- Callback URL: A valid `URI` or `URL` Address for sending result purchase. +- Description: A Content for showing payer. **Optional Parameters:** -* Mobile: Valid Mobile number of payer. -* Email: Valid Email Address of payer. +- Mobile: Valid Mobile number of payer. +- Email: Valid Email Address of payer. ```java Purchase purchase = Purchase.newBuilder().asPaymentRequest( @@ -124,15 +120,18 @@ If you would create payment Authority on Client, You must use `asPayementRequest "http:\\YOUR_SEVER_URL.com", "1000IRR Purchase" ).build(); -``` +``` Maybe You had `Authority`, here You must use `asAuthority()` + ```java Purchase purchase = Purchase.newBuilder() .asAuthority("AUTHORITY_RESOLVED") .build(); -``` +``` + for `Sku` purchase: + ```java Purchase purchase = Purchase.newBuilder() .asSku("SKU_ID") // SKU_ID is an Id that you've generated on ZarinPal panel. @@ -142,6 +141,7 @@ for `Sku` purchase: **Step 3** You must call `purchase` method to begin flow payment: + ```java client.launchBillingFlow(purchase, new FutureCompletionListener() { @Override @@ -158,22 +158,22 @@ You must call `purchase` method to begin flow payment: } } }); -``` - +``` + **Step 4** Finally if your eligible to have payment process through **MPG** You should adding `usesCleartextTraffic` to application tag in your `Manifest.xml` + ```xml - + -``` +``` -SKU Query -========= +# SKU Query The ZarinPal Library stores the query results in a List of SkuPurchased objects. You can then call `querySkuPurchased` and you appear sku purchased with inforamtion in your view and provide service. @@ -183,8 +183,8 @@ The ZarinPal Library stores the query results in a List of SkuPurchased objects. .setSkuList(skus) .orderByMobile("0935******") .build(); - - + + client.querySkuPurchased(skuQuery, new FutureCompletionListener>() { @Override public void onComplete(TaskResult> task) { @@ -198,20 +198,18 @@ The ZarinPal Library stores the query results in a List of SkuPurchased objects. } } }); -```` +``` -Features -======== +# Features **Dark Mode** ```java client.setNightMode(AppCompatDelegate.MODE_NIGHT_YES) -``` +``` **Appear Invoice** ```java client.enableShowInvoice() -``` - +``` diff --git a/README.md b/README.md index 5e2d153..28cbc23 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,28 @@ -ZarinPal In App Billing - Purchase SDK | MPG -============================================ -ZarinPal Purchase SDK Provides payment methods on your Android Application. [Java Readme](https://github.com/ZarinPal/Android-SDK/blob/master/README%20_JAVA.md) here if You want to develop it. +# ZarinPal In App Billing - Purchase SDK | MPG +ZarinPal Purchase SDK Provides payment methods on your Android Application. [Java Readme](https://github.com/armanhossiny/Android-SDK-ZarinPal/blob/master/README%20_JAVA.md) here if You want to develop it. +# Introduction -Introduction -============= ZarinPal in-app purchases are the simplest solution to selling digital products or content on Android apps. So many app developers who want to sell digital goods or offer premium membership to users can simply use the it, in-app billing process for smooth and easy checkouts. -

sample

+# Requirements -Requirements -============ - -* Android 5.0 (API level 21) and above -* Android Gradle Plugin 3.5.1 -* Gradle 5.4.1+ -* AndroidX (as of v11.0.0) +- Android 5.0 (API level 21) and above +- Android Gradle Plugin 3.5.1 and above(this 8.1.4) +- Gradle 5.4.1 and above (this 8.5) +- AndroidX (as of v11.0.0) -Installation -============ +# Installation **Step 1** Add this to your root build.gradle at the end of repositories. + ```gradle allprojects { ext.zarinpalSdkVersion = (LATEST_VERSION_REALEASE) //inform of Releases: https://github.com/ZarinPal/Android-SDK/releases @@ -35,48 +30,49 @@ Add this to your root build.gradle at the end of repositories. ... mavenCentral() } -``` +``` **Step 2** Add the dependency: + ```gradle dependencies { implementation 'com.zarinpal:payment-provider:ext.zarinpalSdkVersion' } -``` - +``` If your project and business trusted to ZarinPal, SDK ables to providing **Mobile Payment Gateway** on your App so You should add the **MPG** dependency: + ```gradle dependencies { implementation 'com.zarinpal:payment-provider:ext.zarinpalSdkVersion' implementation 'com.zarinpal:mpg:ext.zarinpalSdkVersion' } -``` +``` + +# How to use -How to use -========== +- add Permissions in your `Manifest.xml`: -* add Permissions in your `Manifest.xml`: ```xml -``` +``` -Initialize the billing client -============================= +# Initialize the billing client **Step 1** -* `ZarinPalClientBilling` provides to create the billing client instance: +- `ZarinPalClientBilling` provides to create the billing client instance: + ```kotlin val client = ZarinPalBillingClient.newBuilder(this) .enableShowInvoice() .setListener(stateListener) .setNightMode(AppCompatDelegate.MODE_NIGHT_YES) .build() - + private val stateListener = object : BillingClientStateListener { override fun onClientSetupFinished(state: ClientState) { //Observing client states @@ -87,30 +83,30 @@ Initialize the billing client //When Service disconnect } } - -``` + +``` **Step 2** For start purchase you need a `Purchase` instance, `Purchase` has 3 type of Payment: -* as **Payment Request** by `asPaymentRequest()` -* as **Authority ID** by `asAuthority()` -* as **Sku ID** by `asSku()` +- as **Payment Request** by `asPaymentRequest()` +- as **Authority ID** by `asAuthority()` +- as **Sku ID** by `asSku()` If you would create payment Authority on Client, You must use `asPayementRequest()`, this method needs below parameters: **Require Parameters:** -* Merchant id: An unique ID of your business payment gateway. -* Amount: Amount of Purchase. -* Callback URL: A valid `URL` Address for sending result purchase. -* Description: A Content for showing payer. +- Merchant id: An unique ID of your business payment gateway. +- Amount: Amount of Purchase. +- Callback URL: A valid `URL` Address for sending result purchase. +- Description: A Content for showing payer. **Optional Parameters:** -* Mobile: Valid Mobile number of payer. -* Email: Valid Email Address of payer. +- Mobile: Valid Mobile number of payer. +- Email: Valid Email Address of payer. ```kotlin val purchase = Purchase.newBuilder() @@ -120,15 +116,18 @@ If you would create payment Authority on Client, You must use `asPayementRequest "http:\\YOUR_SEVER_URL.com", "1000IRR Purchase" ).build() -``` +``` Maybe You had `Authority`, here You must use `asAuthority()` + ```kotlin val purchase = Purchase .newBuilder() .asAuthority("AUTHORITY_RESOLVED") .build() -``` +``` + for `Sku` purchase: + ```kotlin val purchase = Purchase.newBuilder() .asSku("SKU_ID") // SKU_ID is an Id that you've generated on ZarinPal panel. @@ -138,6 +137,7 @@ for `Sku` purchase: **Step 3** You must call `purchase` method to begin flow payment: + ```kotlin client.launchBillingFlow(purchase, object : FutureCompletionListener { override fun onComplete(task: TaskResult) { @@ -147,28 +147,28 @@ You must call `purchase` method to begin flow payment: //here you can send receipt data to your server //sentToServer(receipt) - + } else { task.failure?.printStackTrace() } } }) -``` - +``` + **Step 4** Finally if your eligible to have payment process through **MPG** You should adding `usesCleartextTraffic` to application tag in your `Manifest.xml` + ```xml - + -``` +``` -SKU Query -========= +# SKU Query The ZarinPal Library stores the query results in a List of SkuPurchased objects. You can then call `querySkuPurchased` and you appear sku purchased with inforamtion in your view and provide service. @@ -177,8 +177,8 @@ The ZarinPal Library stores the query results in a List of SkuPurchased objects. .setSkuList(listOf("SKU_ID_000", "SKU_ID_001")) .orderByMobile("0935******") .build() - - + + client.querySkuPurchased(skuQuery, object : FutureCompletionListener> { override fun onComplete(task: TaskResult>) { if (task.isSuccess){ @@ -191,19 +191,20 @@ The ZarinPal Library stores the query results in a List of SkuPurchased objects. } } }) -```` +``` + +# KTX -KTX -==== a Kotlin extensions for the ZarinPal SDK for Android and Utility Library. These extensions provide Kotlin language features in `Coroutines` async method: ```gradle dependencies { implementation 'com.zarinpal:payment-provider-ktx:ext.zarinpalSdkVersion' } -``` +``` and to invoke `purchase` suspendable method in coroutine scope to start purchase flow: + ```kotlin CoroutineScope(Dispatchers.IO).launch { try { @@ -216,6 +217,7 @@ and to invoke `purchase` suspendable method in coroutine scope to start purchase ``` invoke `querySkuPurchased`suspendable method in coroutine scope to start purchase flow: + ```kotlin CoroutineScope(Dispatchers.IO).launch { try { @@ -229,51 +231,39 @@ invoke `querySkuPurchased`suspendable method in coroutine scope to start purchas } ``` -Contract -======== +# Contract + A contract is a middlware between ZarinPal SDK and your server that provides a new payment provider as credit or digital wallet. + ```gradle dependencies { implementation 'com.zarinpal:contract:ext.zarinpalSdkVersion' } -``` +``` -Features -======== +# Features **Dark Mode** ```kotlin client.setNightMode(AppCompatDelegate.MODE_NIGHT_YES) -``` +``` **Appear Invoice** ```kotlin client.enableShowInvoice() -``` - - - - - - +``` -Releases -======== +# Releases -* The Changelog provides a summary of changes in each release - -* The migration guide provides instructions on upgrading from old SDK. - +- The Changelog provides a summary of changes in each release +- The migration guide provides instructions on upgrading from old SDK. -Proguard -======== +# Proguard The ZarinPal Android SDK will configure your app’s procured (ruls or text file link) -Developed By -============ +# Developed By The Product developed by ZarinPal Team also You can Communicate and open issue - diff --git a/Sample/.gitignore b/Sample/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/Sample/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/Sample/.idea/.gitignore b/Sample/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/Sample/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/Sample/.idea/.name b/Sample/.idea/.name new file mode 100644 index 0000000..9daee13 --- /dev/null +++ b/Sample/.idea/.name @@ -0,0 +1 @@ +zarinpal \ No newline at end of file diff --git a/Sample/.idea/compiler.xml b/Sample/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/Sample/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Sample/.idea/gradle.xml b/Sample/.idea/gradle.xml new file mode 100644 index 0000000..ae388c2 --- /dev/null +++ b/Sample/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/Sample/.idea/kotlinc.xml b/Sample/.idea/kotlinc.xml new file mode 100644 index 0000000..0fc3113 --- /dev/null +++ b/Sample/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Sample/.idea/misc.xml b/Sample/.idea/misc.xml new file mode 100644 index 0000000..8978d23 --- /dev/null +++ b/Sample/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/Sample/.idea/vcs.xml b/Sample/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/Sample/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Sample/app/build.gradle b/Sample/app/build.gradle deleted file mode 100644 index 4454e38..0000000 --- a/Sample/app/build.gradle +++ /dev/null @@ -1,54 +0,0 @@ -plugins { - id 'com.android.application' - id 'kotlin-android' -} - - -project.ext { - zarinpalSdkVersion = "0.5.3" -} - -android { - compileSdk 31 - - defaultConfig { - applicationId "com.zarinpal.sample.inappbilling" - minSdk 21 - targetSdk 31 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } - - viewBinding { - enabled = true - } - -} - -dependencies { - - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.4.1' - implementation 'com.google.android.material:material:1.5.0' - implementation "com.zarinpal:payment-provider:" + project.ext.zarinpalSdkVersion - - //If you have access to mpg by ZarinPal. - implementation "com.zarinpal:mpg:" + project.ext.zarinpalSdkVersion - -} \ No newline at end of file diff --git a/Sample/app/build.gradle.kts b/Sample/app/build.gradle.kts new file mode 100644 index 0000000..3f35fe5 --- /dev/null +++ b/Sample/app/build.gradle.kts @@ -0,0 +1,72 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "ir.nujen.zarinpal" + compileSdk = 34 + + defaultConfig { + applicationId = "ir.nujen.zarinpal" + minSdk = 24 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.4.3" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +dependencies { + + implementation("androidx.core:core-ktx:1.12.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") + implementation("androidx.activity:activity-compose:1.8.2") + implementation(platform("androidx.compose:compose-bom:2023.03.00")) + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-graphics") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.compose.material3:material3") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00")) + androidTestImplementation("androidx.compose.ui:ui-test-junit4") + debugImplementation("androidx.compose.ui:ui-tooling") + debugImplementation("androidx.compose.ui:ui-test-manifest") + //-----------------------------------------------------------zarinpal + implementation("com.zarinpal:payment-provider:0.6.3") + implementation("com.zarinpal:mpg:0.6.3") +} \ No newline at end of file diff --git a/Sample/app/src/androidTest/java/com/zarinpal/sample/inappbilling/ExampleInstrumentedTest.kt b/Sample/app/src/androidTest/java/ir/nujen/zarinpal/ExampleInstrumentedTest.kt similarity index 82% rename from Sample/app/src/androidTest/java/com/zarinpal/sample/inappbilling/ExampleInstrumentedTest.kt rename to Sample/app/src/androidTest/java/ir/nujen/zarinpal/ExampleInstrumentedTest.kt index eb156d4..7f7708c 100644 --- a/Sample/app/src/androidTest/java/com/zarinpal/sample/inappbilling/ExampleInstrumentedTest.kt +++ b/Sample/app/src/androidTest/java/ir/nujen/zarinpal/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.zarinpal.sample.inappbilling +package ir.nujen.zarinpal import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.zarinpal.sample.inappbilling", appContext.packageName) + assertEquals("ir.nujen.zarinpal", appContext.packageName) } } \ No newline at end of file diff --git a/Sample/app/src/main/AndroidManifest.xml b/Sample/app/src/main/AndroidManifest.xml index 1295bce..4a6f528 100644 --- a/Sample/app/src/main/AndroidManifest.xml +++ b/Sample/app/src/main/AndroidManifest.xml @@ -1,18 +1,22 @@ - + xmlns:tools="http://schemas.android.com/tools"> + android:theme="@style/Theme.Zarinpal" + tools:targetApi="31"> + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.Zarinpal"> diff --git a/Sample/app/src/main/java/com/zarinpal/sample/inappbilling/MainActivity.kt b/Sample/app/src/main/java/com/zarinpal/sample/inappbilling/MainActivity.kt deleted file mode 100644 index 88f4c6f..0000000 --- a/Sample/app/src/main/java/com/zarinpal/sample/inappbilling/MainActivity.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.zarinpal.sample.inappbilling - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import android.util.Log -import android.view.View -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatDelegate -import com.zarinpal.ZarinPalBillingClient -import com.zarinpal.billing.purchase.Purchase -import com.zarinpal.client.BillingClientStateListener -import com.zarinpal.client.ClientState -import com.zarinpal.provider.core.future.FutureCompletionListener -import com.zarinpal.provider.core.future.TaskResult -import com.zarinpal.provider.model.response.Receipt -import com.zarinpal.sample.inappbilling.databinding.ActivityMainBinding - -class MainActivity : AppCompatActivity() { - - private var client: ZarinPalBillingClient? = null - - companion object { - const val TAG = "InAppBilling Sample: " - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - - val txtReceipt = findViewById(R.id.txt_receipt) - - val billingClientStateListener = object : BillingClientStateListener { - override fun onClientServiceDisconnected() { - Log.d(TAG, "onClientServiceDisconnected") - } - - override fun onClientSetupFinished(state: ClientState) { - Log.d(TAG, "onClientSetupFinished ${state.name}") - - } - } - - - val purchaseCompletedListener = object : FutureCompletionListener { - override fun onComplete(task: TaskResult) { - Log.d(TAG, "onComplete Receipt is ${task.isSuccess}") - - if (task.isSuccess) { - txtReceipt.text = "Receipt: \n" + - "Transaction id: ${task.success?.transactionID}\n" + - "Amount: ${task.success?.amount}\n" + - "Date: ${task.success?.date}\n" + - "Status: ${task.success?.isSuccess}\n" - } else { - - txtReceipt.text = "Receipt failed: \n" + - "${task.failure?.message}" - } - - } - } - - - - client = ZarinPalBillingClient.newBuilder(this) - .setNightMode(AppCompatDelegate.MODE_NIGHT_YES) - .enableShowInvoice() - .setListener(billingClientStateListener) - .build() - - - findViewById(R.id.btn_payment_request).setOnClickListener { - client?.launchBillingFlow(getPurchaseAsPaymentRequest(), purchaseCompletedListener) - } - - findViewById(R.id.btn_authority).setOnClickListener { - client?.launchBillingFlow(getPurchaseAsAuthority(), purchaseCompletedListener) - } - - findViewById(R.id.btn_sku).setOnClickListener { - client?.launchBillingFlow(getPurchaseAsSku(), purchaseCompletedListener) - } - - } - - private fun getPurchaseAsPaymentRequest(): Purchase { - val merchantId = "6c64a645-1b28-4956-b32e-7b777864121a" - val amount = 1000L - val description = "Payment Request via ZarinPal SDK" - val callback = "https://google.com" // Your Server address - - - return Purchase.newBuilder() - .asPaymentRequest(merchantId, amount, callback, description) - .build() - - } - - - private fun getPurchaseAsAuthority(): Purchase { - - val authority = "" // The authority that resolved from ZarinPal - return Purchase.newBuilder() - .asAuthority(authority) - .build() - - } - - private fun getPurchaseAsSku(): Purchase { - val sku = "" // sku created from ZarinPal - return Purchase.newBuilder() - .asSku(sku) - .build() - } -} \ No newline at end of file diff --git a/Sample/app/src/main/java/ir/nujen/zarinpal/MainActivity.kt b/Sample/app/src/main/java/ir/nujen/zarinpal/MainActivity.kt new file mode 100644 index 0000000..f3817ed --- /dev/null +++ b/Sample/app/src/main/java/ir/nujen/zarinpal/MainActivity.kt @@ -0,0 +1,143 @@ +package ir.nujen.zarinpal + +import android.os.Bundle +import android.util.Log +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatDelegate +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import ir.nujen.zarinpal.ui.theme.ZarinpalTheme +import com.zarinpal.ZarinPalBillingClient +import com.zarinpal.billing.purchase.Purchase +import com.zarinpal.client.BillingClientStateListener +import com.zarinpal.client.ClientState +import com.zarinpal.provider.core.future.FutureCompletionListener +import com.zarinpal.provider.core.future.TaskResult +import com.zarinpal.provider.model.response.Receipt + + + + +class MainActivity : ComponentActivity() { + private var client: ZarinPalBillingClient? = null + private var purchaseCompletedListener: FutureCompletionListener? = null + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val TAG = "InAppBilling Sample: " + + val billingClientStateListener = object : BillingClientStateListener { + override fun onClientServiceDisconnected() { + Log.d(TAG, "onClientServiceDisconnected") + } + + override fun onClientSetupFinished(state: ClientState) { + Log.d(TAG, "onClientSetupFinished ${state.name}") + + } + } + + + purchaseCompletedListener = object : FutureCompletionListener { + override fun onComplete(task: TaskResult) { + Log.d(TAG, "onComplete Receipt is ${task.isSuccess}") + + if (task.isSuccess) { + /* txtReceipt.text = "Receipt: \n" + + "Transaction id: ${task.success?.transactionID}\n" + + "Amount: ${task.success?.amount}\n" + + "Date: ${task.success?.date}\n" + + "Status: ${task.success?.isSuccess}\n"*/ + } else { + + /* txtReceipt.text = "Receipt failed: \n" + + "${task.failure?.message}"*/ + } + + } + } + + client = ZarinPalBillingClient.newBuilder(this) + .setNightMode(AppCompatDelegate.MODE_NIGHT_YES) + .enableShowInvoice() + .setListener(billingClientStateListener) + .build() + + setContent { + ZarinpalTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + Greeting() + } + } + } + } + + + @Composable + fun Greeting() { + Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.height(200.dp)) { + Button(onClick = { client?.launchBillingFlow(getPurchaseAsPaymentRequest(), purchaseCompletedListener) }) { + Text("Pay as Payment Request",) + } + Button(onClick = { client?.launchBillingFlow(getPurchaseAsAuthority(), purchaseCompletedListener) }) { + Text("Pay as Authority") + } + Button(onClick = { client?.launchBillingFlow(getPurchaseAsSku(), purchaseCompletedListener) }) { + Text("Pay as Sku") + } + + } + Column(horizontalAlignment = Alignment.CenterHorizontally,verticalArrangement = Arrangement.Center, modifier = Modifier.height(200.dp)) { + Text("Result of Receipt!") + } + } + + //------------------------- zarinpanl merchantId + private fun getPurchaseAsPaymentRequest(): Purchase { + val merchantId = "6c64a645-1b28-4956-b32e-7b777864121a" + val amount = 1000L + val description = "Payment Request via ZarinPal SDK" + val callback = "https://google.com" // Your Server address + + + return Purchase.newBuilder() + .asPaymentRequest(merchantId, amount, callback, description) + .build() + + } + + + private fun getPurchaseAsAuthority(): Purchase { + + val authority = "" // The authority that resolved from ZarinPal + return Purchase.newBuilder() + .asAuthority(authority) + .build() + + } + + private fun getPurchaseAsSku(): Purchase { + val sku = "" // sku zarinpall + return Purchase.newBuilder() + .asSku(sku) + .build() + } + +} diff --git a/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Color.kt b/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Color.kt new file mode 100644 index 0000000..cc21f9f --- /dev/null +++ b/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package ir.nujen.zarinpal.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Theme.kt b/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Theme.kt new file mode 100644 index 0000000..bc28122 --- /dev/null +++ b/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Theme.kt @@ -0,0 +1,70 @@ +package ir.nujen.zarinpal.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun ZarinpalTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Type.kt b/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Type.kt new file mode 100644 index 0000000..90cafd9 --- /dev/null +++ b/Sample/app/src/main/java/ir/nujen/zarinpal/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package ir.nujen.zarinpal.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/Sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Sample/app/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from Sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Sample/app/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/Sample/app/src/main/res/layout/activity_main.xml b/Sample/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index c44dafb..0000000 --- a/Sample/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - -