diff --git a/.travis.yml b/.travis.yml
index 16a4d54552..88e4656f07 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,3 +24,8 @@ script:
- ./gradlew build
after_success:
- bash scripts/update-apk.sh
+
+branches:
+ only:
+ - master
+ - development
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3db8554c1c..d99a015e3c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,5 @@
## How to Contribute
-
+First please go through the [Open Source Developer Guide and Best Practices at FOSSASIA](https://blog.fossasia.org/open-source-developer-guide-and-best-practices-at-fossasia/)
### Raising an issue:
This is an Open Source project and we would be happy to see contributors who report bugs and file feature requests submitting pull requests as well.
This project adheres to the Contributor Covenant code of conduct.
diff --git a/README.md b/README.md
index 08004ca02a..013d15b805 100644
--- a/README.md
+++ b/README.md
@@ -5,22 +5,27 @@
[](https://groups.google.com/forum/#!forum/open-event)
[](https://twitter.com/eventyay)
-An events app to discover events happening around the world using the Open Event Platform on Eventyay.com.
+An events app to discover events happening around the world using the Open Event Platform on [Eventyay](https://eventyay.com).
+
+Eventyay Attendee App provides following features for users:
+- All events by the organizers can be viewed
+- Functionality to filter out events by date, time, location and event name
+- Users can buy tickets and register as attendees for any event
+- Pay for their orders via PayPal and Stripe
+- All important event details such as location, date, and timing of the event can be viewed
+- Users can view all the tickets bought for an event with their status
+- Easy check-in using QR code for Tickets and see check-in timings
+- Users can view similar events
+- Users have the privilege to mark an event as favorite
Application is available here:
-## Roadmap
-
-Planned features & enhancements are:
-
-
-
## Communication
-Please join our mailing list to discuss questions regarding the project: https://groups.google.com/forum/#!forum/open-event
+Please join our mailing list to discuss questions regarding the project [here](https://groups.google.com/forum/#!forum/open-event)
Our chat channel is on gitter [here](https://gitter.im/fossasia/open-event-attendee-android)
@@ -32,11 +37,12 @@ Our chat channel is on gitter [here](https://gitter.im/fossasia/open-event-atten
 |
+ |
 |
 |
- |
+ |
 |
 |
@@ -44,7 +50,7 @@ Our chat channel is on gitter [here](https://gitter.im/fossasia/open-event-atten
## Development
-A native Android app using Kotlin for writing code.
+A native Android app using Kotlin for writing code and [Open event server](https://github.com/fossasia/open-event-server) for API.
### Libraries used and their documentation
@@ -58,6 +64,10 @@ A native Android app using Kotlin for writing code.
- JSON API Converter [Docs](https://github.com/jasminb/jsonapi-converter)
- OkHttp [Docs](http://square.github.io/okhttp/)
- Room Persistence Library [Docs](https://developer.android.com/topic/libraries/architecture/room)
+- PayPal [Docs](https://github.com/paypal/PayPal-Android-SDK)
+- Navigation Architecture Component [Docs](https://developer.android.com/guide/navigation/navigation-getting-started)
+- Mapbox [Docs](https://docs.mapbox.com/)
+- Stetho [Docs](https://github.com/facebook/stetho)
### Project Conventions
@@ -108,13 +118,7 @@ Please help us follow the best practices to make it easy for the reviewer as wel
* If you would like to work on an issue, drop in a comment at the issue. If it is already assigned to someone, but there is no sign of any work being done, please free to drop in a comment so that the issue can be assigned to you if the previous assignee has dropped it entirely.
## For Testers: Testing the App
-If you are a tester and want to test the app, you have two ways to do that:
-1. **Installing APK on your device:** You can get debug APK as well as Release APK in apk branch of the repository. After each PR merge, both the APKs are automatically updated. So, just download the APK you want and install it on your device. The APKs will always be the latest one.
-
-## Open Event Attendee Android Suggestions
-
-- Suggestion form link: [Form](https://docs.google.com/forms/d/e/1FAIpQLSd7Y1T1xoXeYaAG_b6Tu1YYK-jZssoC5ltmQbkUX0kmDZaKYw/viewform)
-- Suggestion responses link: [Sheet](https://docs.google.com/spreadsheets/d/1SzR75MBEVrTY1sDM3KAMm9wltiulDAp0QT5hv9eJkKM/edit#gid=1676755229)
+**Installing APK on your device:** You can get debug APK as well as Release APK in apk branch of the repository. After each PR merge, both the APKs are automatically updated. So, just download the APK you want and install it on your device. The APKs will always be the latest one.
## License
diff --git a/app/build.gradle b/app/build.gradle
index 56ce131f28..bb0ab2d95b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "com.diffplug.gradle.spotless" version "3.24.2"
+ id "com.diffplug.gradle.spotless" version "3.24.3"
}
apply plugin: 'com.android.application'
@@ -11,6 +11,7 @@ apply plugin: "com.github.b3er.local.properties"
def STRIPE_API_TOKEN = System.getenv('STRIPE_API_TOKEN') ?: "YOUR_API_KEY"
def MAPBOX_KEY = System.getenv('MAPBOX_KEY') ?: "pk.eyJ1IjoiYW5nbWFzMSIsImEiOiJjanNqZDd0N2YxN2Q5NDNuNTBiaGt6eHZqIn0.BCrxjW6rP_OuOuGtbhVEQg"
+def PAYPAL_CLIENT_ID= System.getenv('PAYPAL_CLIENT_ID') ?: "YOUR_API_KEY"
def LOCAL_KEY_PRESENT = project.hasProperty('SIGNING_KEY_FILE') && rootProject.file(SIGNING_KEY_FILE).exists()
android {
@@ -22,8 +23,8 @@ android {
applicationId "com.eventyay.attendee"
minSdkVersion 21
targetSdkVersion 28
- versionCode 14
- versionName "0.7.0"
+ versionCode 15
+ versionName "0.8.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
@@ -58,6 +59,7 @@ android {
buildConfigField "String", "DEFAULT_BASE_URL", '"https://api.eventyay.com/v1/"'
buildConfigField "String", "MAPBOX_KEY", '"'+MAPBOX_KEY+'"'
buildConfigField "String", "STRIPE_API_KEY", '"'+STRIPE_API_TOKEN+'"'
+ buildConfigField "String", "PAYPAL_CLIENT_ID", '"'+PAYPAL_CLIENT_ID+'"'
resValue "string", "FRONTEND_HOST", "eventyay.com"
if (LOCAL_KEY_PRESENT || TRAVIS_BUILD)
signingConfig signingConfigs.release
@@ -66,6 +68,7 @@ android {
buildConfigField "String", "DEFAULT_BASE_URL", '"https://open-event-api-dev.herokuapp.com/v1/"'
buildConfigField "String", "MAPBOX_KEY", '"'+MAPBOX_KEY+'"'
buildConfigField "String", "STRIPE_API_KEY", '"'+STRIPE_API_TOKEN+'"'
+ buildConfigField "String", "PAYPAL_CLIENT_ID", '"'+PAYPAL_CLIENT_ID+'"'
resValue "string", "FRONTEND_HOST", "open-event-fe.netlify.com"
}
}
@@ -121,22 +124,22 @@ repositories {
}
dependencies {
- def lifecycle_version = "2.2.0-alpha03"
+ def lifecycle_version = "2.2.0-alpha05"
def koin_version = "2.0.1"
def roomVersion = "2.1.0"
- def ktx_version = "1.0.0"
- def ktx2_version = "2.0.0"
- def nav_version = "2.1.0-beta02"
+ def ktx_version = "1.1.0"
+ def ktx2_version = "2.1.0"
+ def nav_version = "2.1.0"
def anko_version = "0.10.8"
def paging_version = "2.1.0"
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.multidex:multidex:2.0.1'
- implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
+ implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'androidx.recyclerview:recyclerview:1.1.0-beta03'
- implementation 'com.google.android.material:material:1.1.0-alpha09'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0-beta04'
+ implementation 'com.google.android.material:material:1.1.0-alpha10'
implementation "androidx.browser:browser:1.0.0"
implementation 'androidx.exifinterface:exifinterface:1.0.0'
implementation "androidx.lifecycle:lifecycle-extensions:${lifecycle_version}"
@@ -146,7 +149,7 @@ dependencies {
implementation "androidx.room:room-rxjava2:${roomVersion}"
kapt "androidx.room:room-compiler:${roomVersion}"
testImplementation "androidx.room:room-testing:${roomVersion}"
- implementation 'androidx.preference:preference:1.1.0-rc01'
+ implementation 'androidx.preference:preference:1.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// KTX
@@ -172,9 +175,9 @@ dependencies {
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.6"
implementation 'com.github.jasminb:jsonapi-converter:0.9'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.1.0'
- implementation 'com.squareup.retrofit2:retrofit:2.6.1'
- implementation 'com.squareup.retrofit2:converter-jackson:2.6.1'
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.2.1'
+ implementation 'com.squareup.retrofit2:retrofit:2.6.2'
+ implementation 'com.squareup.retrofit2:converter-jackson:2.6.2'
// Cards Shimmer Animation
implementation 'com.facebook.shimmer:shimmer:0.5.0'
@@ -182,14 +185,14 @@ dependencies {
// RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
- implementation 'io.reactivex.rxjava2:rxjava:2.2.11'
- implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1'
+ implementation 'io.reactivex.rxjava2:rxjava:2.2.12'
+ implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2'
// Picasso
implementation 'com.squareup.picasso:picasso:2.71828'
// Stripe
- implementation 'com.stripe:stripe-android:10.3.0'
+ implementation 'com.stripe:stripe-android:11.1.4'
// QR Code
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
@@ -203,7 +206,7 @@ dependencies {
implementation "org.jetbrains.anko:anko-design:$anko_version"
//Mapbox java sdk
- implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:4.8.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:4.9.0'
// SimpleCropView
implementation 'com.isseiaoki:simplecropview:1.1.8'
@@ -215,7 +218,7 @@ dependencies {
testImplementation 'com.github.iamareebjamal:stetho-noop:1.2.1'
//LeakCanary
- debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-2'
+ debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-3'
// Paging
implementation "androidx.paging:paging-runtime:$paging_version"
@@ -231,11 +234,13 @@ dependencies {
implementation 'net.cachapa.expandablelayout:expandablelayout:2.9.2'
+ //PayPal
+ implementation 'com.paypal.sdk:paypal-android-sdk:2.16.0'
testImplementation 'junit:junit:4.12'
testImplementation 'org.threeten:threetenbp:1.4.0'
testImplementation "org.koin:koin-test:$koin_version"
- testImplementation 'androidx.arch.core:core-testing:2.0.1'
+ testImplementation 'androidx.arch.core:core-testing:2.1.0'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
diff --git a/app/schemas/org.fossasia.openevent.general.OpenEventDatabase/9.json b/app/schemas/org.fossasia.openevent.general.OpenEventDatabase/9.json
index 72ca4cf89e..861f489e6f 100644
--- a/app/schemas/org.fossasia.openevent.general.OpenEventDatabase/9.json
+++ b/app/schemas/org.fossasia.openevent.general.OpenEventDatabase/9.json
@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 9,
- "identityHash": "dfbd417bf9235824cb59ac1a0a03fa1f",
+ "identityHash": "ceaeb211922de9668d95362a86917dac",
"entities": [
{
"tableName": "Event",
@@ -701,7 +701,7 @@
},
{
"tableName": "Attendee",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `firstname` TEXT, `lastname` TEXT, `email` TEXT, `address` TEXT, `city` TEXT, `state` TEXT, `country` TEXT, `jobTitle` TEXT, `phone` TEXT, `taxBusinessInfo` TEXT, `billingAddress` TEXT, `homeAddress` TEXT, `shippingAddress` TEXT, `company` TEXT, `workAddress` TEXT, `workPhone` TEXT, `website` TEXT, `blog` TEXT, `github` TEXT, `facebook` TEXT, `twitter` TEXT, `gender` TEXT, `isCheckedIn` INTEGER, `checkinTimes` TEXT, `isCheckedOut` INTEGER NOT NULL, `pdfUrl` TEXT, `ticketId` TEXT, `event` INTEGER, `ticket` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`event`) REFERENCES `Event`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`ticket`) REFERENCES `Ticket`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `firstname` TEXT, `lastname` TEXT, `email` TEXT, `address` TEXT, `city` TEXT, `state` TEXT, `country` TEXT, `jobTitle` TEXT, `phone` TEXT, `taxBusinessInfo` TEXT, `billingAddress` TEXT, `homeAddress` TEXT, `shippingAddress` TEXT, `company` TEXT, `workAddress` TEXT, `workPhone` TEXT, `website` TEXT, `blog` TEXT, `github` TEXT, `facebook` TEXT, `twitter` TEXT, `gender` TEXT, `isCheckedIn` INTEGER, `checkinTimes` TEXT, `isCheckedOut` INTEGER NOT NULL, `pdfUrl` TEXT, `ticketId` TEXT, `checkedIn` TEXT, `checkedOut` TEXT, `event` INTEGER, `ticket` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`event`) REFERENCES `Event`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`ticket`) REFERENCES `Ticket`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@@ -871,6 +871,18 @@
"affinity": "TEXT",
"notNull": false
},
+ {
+ "fieldPath": "checkedIn",
+ "columnName": "checkedIn",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "checkedOut",
+ "columnName": "checkedOut",
+ "affinity": "TEXT",
+ "notNull": false
+ },
{
"fieldPath": "event",
"columnName": "event",
@@ -994,7 +1006,7 @@
},
{
"tableName": "Order",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `paymentMode` TEXT, `country` TEXT, `status` TEXT, `amount` REAL NOT NULL, `identifier` TEXT, `orderNotes` TEXT, `completedAt` TEXT, `city` TEXT, `address` TEXT, `createdAt` TEXT, `zipcode` TEXT, `paidVia` TEXT, `discountCodeId` TEXT, `ticketsPdfUrl` TEXT, `transactionId` TEXT, `isBillingEnabled` INTEGER NOT NULL, `taxBusinessInfo` TEXT, `company` TEXT, `event` INTEGER, `attendees` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `paymentMode` TEXT, `country` TEXT, `status` TEXT, `amount` REAL NOT NULL, `identifier` TEXT, `orderNotes` TEXT, `completedAt` TEXT, `state` TEXT, `city` TEXT, `address` TEXT, `createdAt` TEXT, `zipcode` TEXT, `paidVia` TEXT, `discountCodeId` TEXT, `ticketsPdfUrl` TEXT, `transactionId` TEXT, `isBillingEnabled` INTEGER NOT NULL, `taxBusinessInfo` TEXT, `company` TEXT, `isExpired` INTEGER, `event` INTEGER, `attendees` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
@@ -1044,6 +1056,12 @@
"affinity": "TEXT",
"notNull": false
},
+ {
+ "fieldPath": "state",
+ "columnName": "state",
+ "affinity": "TEXT",
+ "notNull": false
+ },
{
"fieldPath": "city",
"columnName": "city",
@@ -1110,6 +1128,12 @@
"affinity": "TEXT",
"notNull": false
},
+ {
+ "fieldPath": "isExpired",
+ "columnName": "isExpired",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
{
"fieldPath": "event",
"columnName": "event",
@@ -2211,7 +2235,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
- "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'dfbd417bf9235824cb59ac1a0a03fa1f')"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ceaeb211922de9668d95362a86917dac')"
]
}
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d4a7e94378..3933bce40a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -37,6 +37,13 @@
+
+
+
+
(json)
+ }
+
+ @TypeConverter
+ fun toJson(attendee: Attendee?) = ObjectMapper().writeValueAsString(attendee)
+}
diff --git a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeFragment.kt b/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeFragment.kt
index d9215c2713..b0ba3f139b 100644
--- a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeFragment.kt
@@ -1,7 +1,9 @@
package org.fossasia.openevent.general.attendees
import androidx.appcompat.app.AlertDialog
+import android.app.Activity
import android.content.Context
+import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.telephony.TelephonyManager
@@ -25,9 +27,16 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.navigation.Navigation.findNavController
import androidx.navigation.fragment.navArgs
import com.stripe.android.Stripe
-import com.stripe.android.TokenCallback
import com.stripe.android.model.Card
import com.stripe.android.model.Token
+import com.paypal.android.sdk.payments.PayPalService
+import com.paypal.android.sdk.payments.PayPalConfiguration
+import com.paypal.android.sdk.payments.PayPalPayment
+import com.paypal.android.sdk.payments.ShippingAddress
+import com.paypal.android.sdk.payments.PaymentActivity
+import com.paypal.android.sdk.payments.PaymentConfirmation
+import com.stripe.android.ApiResultCallback
+import java.math.BigDecimal
import kotlinx.android.synthetic.main.fragment_attendee.view.cvc
import kotlinx.android.synthetic.main.fragment_attendee.view.email
import kotlinx.android.synthetic.main.fragment_attendee.view.firstName
@@ -68,6 +77,7 @@ import kotlinx.android.synthetic.main.fragment_attendee.view.countryPicker
import kotlinx.android.synthetic.main.fragment_attendee.view.billingInfoContainer
import kotlinx.android.synthetic.main.fragment_attendee.view.billingCity
import kotlinx.android.synthetic.main.fragment_attendee.view.billingCompany
+import kotlinx.android.synthetic.main.fragment_attendee.view.billingState
import kotlinx.android.synthetic.main.fragment_attendee.view.taxId
import kotlinx.android.synthetic.main.fragment_attendee.view.billingAddress
import kotlinx.android.synthetic.main.fragment_attendee.view.firstNameLayout
@@ -125,6 +135,8 @@ import java.util.Calendar
import java.util.Currency
import kotlin.collections.ArrayList
+private const val PAYPAL_REQUEST_CODE = 101
+
class AttendeeFragment : Fragment(), ComplexBackPressFragment {
private lateinit var rootView: View
@@ -250,6 +262,7 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
super.onDestroy()
if (this::timer.isInitialized)
timer.cancel()
+ activity?.stopService(Intent(activity, PayPalService::class.java))
}
override fun handleBackPress() {
@@ -328,9 +341,9 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
rootView.ticketsRecycler.isNestedScrollingEnabled = false
rootView.taxLayout.isVisible = safeArgs.taxAmount > 0f
- rootView.taxPrice.text = "${safeArgs.currency}${"%.2f".format(safeArgs.taxAmount)}"
+ rootView.taxPrice.text = "${Currency.getInstance(safeArgs.currency).symbol}${"%.2f".format(safeArgs.taxAmount)}"
rootView.totalAmountLayout.isVisible = safeArgs.amount > 0f
- rootView.totalPrice.text = "${safeArgs.currency}${"%.2f".format(safeArgs.amount)}"
+ rootView.totalPrice.text = "${Currency.getInstance(safeArgs.currency).symbol}${"%.2f".format(safeArgs.amount)}"
rootView.ticketTableDetails.setOnClickListener {
attendeeViewModel.ticketDetailsVisible = !attendeeViewModel.ticketDetailsVisible
@@ -615,6 +628,12 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
if (it && this::card.isInitialized)
sendToken(card)
})
+
+ attendeeViewModel.paypalOrderMade
+ .nonNull()
+ .observe(viewLifecycleOwner, Observer {
+ startPaypalPayment()
+ })
}
private fun setupMonthOptions() {
@@ -683,10 +702,6 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
private fun checkPaymentOptions(): Boolean =
when (attendeeViewModel.selectedPaymentMode) {
- PAYMENT_MODE_PAYPAL -> {
- rootView.attendeeScrollView.longSnackbar(getString(R.string.paypal_payment_not_available))
- false
- }
PAYMENT_MODE_STRIPE -> {
card = Card.create(rootView.cardNumber.text.toString(), attendeeViewModel.monthSelectedPosition,
rootView.year.selectedItem.toString().toInt(), rootView.cvc.text.toString())
@@ -698,13 +713,63 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
true
}
}
- PAYMENT_MODE_CHEQUE, PAYMENT_MODE_ONSITE, PAYMENT_MODE_FREE, PAYMENT_MODE_BANK -> true
+ PAYMENT_MODE_CHEQUE, PAYMENT_MODE_ONSITE, PAYMENT_MODE_FREE, PAYMENT_MODE_BANK, PAYMENT_MODE_PAYPAL -> true
else -> {
rootView.snackbar(getString(R.string.select_payment_option_message))
false
}
}
+ private fun startPaypalPayment() {
+ val paypalEnvironment = if (BuildConfig.DEBUG) PayPalConfiguration.ENVIRONMENT_SANDBOX
+ else PayPalConfiguration.ENVIRONMENT_PRODUCTION
+ val paypalConfig = PayPalConfiguration()
+ .environment(paypalEnvironment)
+ .clientId(BuildConfig.PAYPAL_CLIENT_ID)
+ val paypalIntent = Intent(activity, PaymentActivity::class.java)
+ paypalIntent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, paypalConfig)
+ activity?.startService(paypalIntent)
+
+ val paypalPayment = paypalThingsToBuy(PayPalPayment.PAYMENT_INTENT_SALE)
+ val payeeEmail = attendeeViewModel.event.value?.paypalEmail ?: ""
+ paypalPayment.payeeEmail(payeeEmail)
+ addShippingAddress(paypalPayment)
+ val intent = Intent(activity, PaymentActivity::class.java)
+ intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, paypalConfig)
+ intent.putExtra(PaymentActivity.EXTRA_PAYMENT, paypalPayment)
+ startActivityForResult(intent, PAYPAL_REQUEST_CODE)
+ }
+
+ private fun addShippingAddress(paypalPayment: PayPalPayment) {
+ if (rootView.billingEnabledCheckbox.isChecked) {
+ val shippingAddress = ShippingAddress()
+ .recipientName("${rootView.firstName.text} ${rootView.lastName.text}")
+ .line1(rootView.billingAddress.text.toString())
+ .city(rootView.billingCity.text.toString())
+ .state(rootView.billingState.text.toString())
+ .postalCode(rootView.billingPostalCode.text.toString())
+ .countryCode(getCountryCodes(rootView.countryPicker.selectedItem.toString()))
+ paypalPayment.providedShippingAddress(shippingAddress)
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (requestCode == PAYPAL_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+ val paymentConfirm =
+ data?.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION)
+ if (paymentConfirm != null) {
+ val paymentId = paymentConfirm.proofOfPayment.paymentId
+ attendeeViewModel.sendPaypalConfirm(paymentId)
+ }
+ }
+ }
+
+ private fun paypalThingsToBuy(paymentIntent: String): PayPalPayment =
+ PayPalPayment(BigDecimal(safeArgs.amount.toString()),
+ Currency.getInstance(safeArgs.currency).currencyCode,
+ getString(R.string.tickets_for, attendeeViewModel.event.value?.name), paymentIntent)
+
private fun checkRequiredFields(): Boolean {
val checkBasicInfo = rootView.firstName.checkEmpty(rootView.firstNameLayout) &&
rootView.lastName.checkEmpty(rootView.lastNameLayout) &&
@@ -771,11 +836,12 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
else PAYMENT_MODE_FREE
val company = rootView.billingCompany.text.toString()
val city = rootView.billingCity.text.toString()
+ val state = rootView.billingState.text.toString()
val taxId = rootView.taxId.text.toString()
val address = rootView.billingAddress.text.toString()
val postalCode = rootView.billingPostalCode.text.toString()
attendeeViewModel.createAttendees(attendees, country, company, taxId, address,
- city, postalCode, paymentOption)
+ city, postalCode, state, paymentOption)
} else {
rootView.attendeeScrollView.longSnackbar(getString(R.string.invalid_email_address_message))
}
@@ -805,8 +871,8 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
}
private fun sendToken(card: Card) {
- Stripe(requireContext())
- .createToken(card, BuildConfig.STRIPE_API_KEY, object : TokenCallback {
+ Stripe(requireContext(), BuildConfig.STRIPE_API_KEY)
+ .createToken(card, object : ApiResultCallback {
override fun onSuccess(token: Token) {
val charge = Charge(attendeeViewModel.getId().toInt(), token.id, null)
attendeeViewModel.chargeOrder(charge)
@@ -876,4 +942,11 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
val countryIndex = countryCodes.indexOf(currentCountryCode.toUpperCase())
if (countryIndex != -1) rootView.countryPicker.setSelection(countryIndex)
}
+
+ private fun getCountryCodes(countryName: String): String {
+ val countryCodes = resources.getStringArray(R.array.country_code_arrays)
+ val countryList = resources.getStringArray(R.array.country_arrays)
+ val index = countryList.indexOf(countryName)
+ return countryCodes[index]
+ }
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeId.kt b/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeId.kt
deleted file mode 100644
index 2393543ad2..0000000000
--- a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeId.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.fossasia.openevent.general.attendees
-
-import com.github.jasminb.jsonapi.LongIdHandler
-import com.github.jasminb.jsonapi.annotations.Id
-import com.github.jasminb.jsonapi.annotations.Type
-
-@Type("attendee")
-data class AttendeeId(
- @Id(LongIdHandler::class)
- val id: Long
-)
diff --git a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeIdConverter.kt b/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeIdConverter.kt
deleted file mode 100644
index 02497586fc..0000000000
--- a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeIdConverter.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.fossasia.openevent.general.attendees
-
-import androidx.room.TypeConverter
-
-class AttendeeIdConverter {
-
- @TypeConverter
- fun fromAttendeeId(attendeeId: AttendeeId): Long {
- return attendeeId.id
- }
-
- @TypeConverter
- fun toAttendeeId(id: Long): AttendeeId {
- return AttendeeId(id)
- }
-}
diff --git a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeViewModel.kt b/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeViewModel.kt
index f9a3e49ad9..b4ea404a16 100644
--- a/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeViewModel.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeViewModel.kt
@@ -42,7 +42,7 @@ const val PAYMENT_MODE_PAYPAL = "paypal"
const val PAYMENT_MODE_STRIPE = "stripe"
private const val ERRORS = "errors"
private const val DETAIL = "detail"
-private const val UNVERIFIED_USER = "unverified user"
+private const val UNVERIFIED_USER = "unverified-user"
private const val ORDER_EXPIRY_TIME = 15
class AttendeeViewModel(
@@ -82,6 +82,8 @@ class AttendeeViewModel(
val orderExpiryTime: LiveData = mutableOrderExpiryTime
private val mutableRedirectToProfile = SingleLiveEvent()
val redirectToProfile = mutableRedirectToProfile
+ private val mutablePaypalOrderMade = MutableLiveData()
+ val paypalOrderMade: LiveData = mutablePaypalOrderMade
val attendees = ArrayList()
private val attendeesForOrder = ArrayList()
@@ -93,6 +95,7 @@ class AttendeeViewModel(
private var addressForOrder: String = ""
private var cityForOrder: String = ""
private var postalCodeForOrder: String = ""
+ private var stateForOrder: String = ""
private var createAttendeeIterations = 0
var orderIdentifier: String? = null
@@ -169,7 +172,7 @@ class AttendeeViewModel(
orderIdentifier = it.identifier.toString()
}, {
if (it is HttpException) {
- if (ErrorUtils.getErrorDetails(it).detail?.contains(UNVERIFIED_USER, true) == true) {
+ if (ErrorUtils.getErrorDetails(it).code == UNVERIFIED_USER) {
mutableRedirectToProfile.value = true
}
}
@@ -211,6 +214,7 @@ class AttendeeViewModel(
address: String,
city: String,
postalCode: String,
+ state: String,
paymentMode: String
) {
attendeesForOrder.clear()
@@ -220,6 +224,7 @@ class AttendeeViewModel(
addressForOrder = address
cityForOrder = city
postalCodeForOrder = postalCode
+ stateForOrder = state
paymentModeForOrder = paymentMode
var isAllDetailsFilled = true
createAttendeeIterations = 0
@@ -270,15 +275,15 @@ class AttendeeViewModel(
mutableMessage.value = resource.getString(R.string.order_fail_message)
return
}
- val attendeeList = attendeesForOrder.map { AttendeeId(it.id) }.toList()
val amount: Float = totalAmount.value ?: 0F
if (amount <= 0) {
paymentModeForOrder = PAYMENT_MODE_FREE
}
- order = order.copy(attendees = attendeeList, paymentMode = paymentModeForOrder, amount = amount)
+ order = order.copy(attendees = attendeesForOrder, paymentMode = paymentModeForOrder, amount = amount)
if (billingEnabled) {
order = order.copy(isBillingEnabled = true, company = companyForOrder, taxBusinessInfo = taxIdForOrder,
- address = addressForOrder, city = cityForOrder, zipcode = postalCodeForOrder, country = countryForOrder)
+ address = addressForOrder, city = cityForOrder, zipcode = postalCodeForOrder, country = countryForOrder,
+ state = stateForOrder)
}
compositeDisposable += orderService.placeOrder(order)
.withDefaultSchedulers()
@@ -297,6 +302,11 @@ class AttendeeViewModel(
PAYMENT_MODE_STRIPE -> {
mutableStripeOrderMade.value = true
}
+ PAYMENT_MODE_PAYPAL -> {
+ mutablePendingOrder.value = it
+ mutablePaypalOrderMade.value = true
+ mutableProgress.value = false
+ }
else -> mutableMessage.value = resource.getString(R.string.order_success_message)
}
}, {
@@ -307,6 +317,28 @@ class AttendeeViewModel(
})
}
+ fun sendPaypalConfirm(paymentId: String) {
+ pendingOrder.value?.let { order ->
+ compositeDisposable += orderService.verifyPaypalPayment(order.identifier.toString(), paymentId)
+ .withDefaultSchedulers()
+ .doOnSubscribe {
+ mutableProgress.value = true
+ }.subscribe({
+ if (it.status) {
+ confirmOrder = ConfirmOrder(order.id.toString(), ORDER_STATUS_COMPLETED)
+ confirmOrderStatus(order.identifier.toString(), confirmOrder)
+ } else {
+ mutableMessage.value = it.error
+ mutableProgress.value = false
+ }
+ }, {
+ Timber.e(it, "Error verifying paypal payment")
+ mutableMessage.value = resource.getString(R.string.error_making_paypal_payment_message)
+ mutableProgress.value = false
+ })
+ }
+ }
+
private fun confirmOrderStatus(identifier: String, order: ConfirmOrder) {
compositeDisposable += orderService.confirmOrder(identifier, order)
.withDefaultSchedulers()
@@ -336,12 +368,12 @@ class AttendeeViewModel(
})
}
- private fun deleteAttendees(attendeeIds: List?) {
- attendeeIds?.forEach { attendeeId ->
- compositeDisposable += attendeeService.deleteAttendee(attendeeId.id)
+ private fun deleteAttendees(attendees: List?) {
+ attendees?.forEach { attendee ->
+ compositeDisposable += attendeeService.deleteAttendee(attendee.id)
.withDefaultSchedulers()
.subscribe({
- Timber.d("Deleted attendee $attendeeId.id")
+ Timber.d("Deleted attendee ${attendee.id}")
}, {
Timber.d("Failed to delete attendee $it.id")
})
diff --git a/app/src/main/java/org/fossasia/openevent/general/attendees/ListAttendeeIdConverter.kt b/app/src/main/java/org/fossasia/openevent/general/attendees/ListAttendeeConverter.kt
similarity index 52%
rename from app/src/main/java/org/fossasia/openevent/general/attendees/ListAttendeeIdConverter.kt
rename to app/src/main/java/org/fossasia/openevent/general/attendees/ListAttendeeConverter.kt
index 0f1bbcfaa5..3cb377b51a 100644
--- a/app/src/main/java/org/fossasia/openevent/general/attendees/ListAttendeeIdConverter.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/attendees/ListAttendeeConverter.kt
@@ -5,18 +5,18 @@ import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
-class ListAttendeeIdConverter {
+class ListAttendeeConverter {
@TypeConverter
- fun fromListAttendeeId(attendeeIdList: List): String {
+ fun fromListAttendee(attendees: List): String {
val objectMapper = ObjectMapper()
- return objectMapper.writeValueAsString(attendeeIdList)
+ return objectMapper.writeValueAsString(attendees)
}
@TypeConverter
- fun toListAttendeeId(attendeeList: String): List {
+ fun toListAttendee(attendees: String): List {
val objectMapper = jacksonObjectMapper()
- val mapType = object : TypeReference>() {}
- return objectMapper.readValue(attendeeList, mapType)
+ val mapType = object : TypeReference>() {}
+ return objectMapper.readValue(attendees, mapType)
}
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/auth/EditProfileFragment.kt b/app/src/main/java/org/fossasia/openevent/general/auth/EditProfileFragment.kt
index baf0b84405..42a671e760 100644
--- a/app/src/main/java/org/fossasia/openevent/general/auth/EditProfileFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/auth/EditProfileFragment.kt
@@ -17,7 +17,6 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
-import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.navigation.Navigation.findNavController
@@ -39,16 +38,15 @@ import kotlinx.android.synthetic.main.dialog_edit_profile_image.view.replaceImag
import kotlinx.android.synthetic.main.dialog_edit_profile_image.view.removeImage
import kotlinx.android.synthetic.main.fragment_edit_profile.view.lastName
import kotlinx.android.synthetic.main.fragment_edit_profile.view.profilePhoto
-import kotlinx.android.synthetic.main.fragment_edit_profile.view.progressBar
import kotlinx.android.synthetic.main.fragment_edit_profile.view.profilePhotoFab
-import kotlinx.android.synthetic.main.fragment_edit_profile.view.firstNameLayout
-import kotlinx.android.synthetic.main.fragment_edit_profile.view.lastNameLayout
import org.fossasia.openevent.general.CircleTransform
import org.fossasia.openevent.general.MainActivity
import org.fossasia.openevent.general.R
import org.fossasia.openevent.general.RotateBitmap
import org.fossasia.openevent.general.ComplexBackPressFragment
+import org.fossasia.openevent.general.utils.Utils.show
import org.fossasia.openevent.general.utils.Utils.hideSoftKeyboard
+import org.fossasia.openevent.general.utils.Utils.progressDialog
import org.fossasia.openevent.general.utils.Utils.requireDrawable
import org.fossasia.openevent.general.utils.extensions.nonNull
import org.fossasia.openevent.general.utils.nullToEmpty
@@ -61,7 +59,6 @@ import java.io.IOException
import java.io.FileNotFoundException
import org.fossasia.openevent.general.utils.Utils.setToolbar
import org.fossasia.openevent.general.utils.emptyToNull
-import org.fossasia.openevent.general.utils.setRequired
import org.jetbrains.anko.design.snackbar
class EditProfileFragment : Fragment(), ComplexBackPressFragment {
@@ -109,10 +106,11 @@ class EditProfileFragment : Fragment(), ComplexBackPressFragment {
val currentUser = editProfileViewModel.user.value
if (currentUser == null) profileViewModel.getProfile() else loadUserUI(currentUser)
+ val progress = progressDialog(context)
editProfileViewModel.progress
.nonNull()
.observe(viewLifecycleOwner, Observer {
- rootView.progressBar.isVisible = it
+ progress.show(it)
})
editProfileViewModel.getUpdatedTempFile()
@@ -156,9 +154,6 @@ class EditProfileFragment : Fragment(), ComplexBackPressFragment {
showEditPhotoDialog()
}
- rootView.firstNameLayout.setRequired()
- rootView.lastNameLayout.setRequired()
-
return rootView
}
@@ -187,14 +182,6 @@ class EditProfileFragment : Fragment(), ComplexBackPressFragment {
private fun isValidInput(): Boolean {
var valid = true
- if (rootView.firstName.text.isNullOrBlank()) {
- rootView.firstName.error = getString(R.string.empty_field_error_message)
- valid = false
- }
- if (rootView.lastName.text.isNullOrBlank()) {
- rootView.lastName.error = getString(R.string.empty_field_error_message)
- valid = false
- }
if (!rootView.instagram.text.isNullOrEmpty() && !Patterns.WEB_URL.matcher(rootView.instagram.text).matches()) {
rootView.instagram.error = getString(R.string.invalid_url_message)
valid = false
diff --git a/app/src/main/java/org/fossasia/openevent/general/di/Modules.kt b/app/src/main/java/org/fossasia/openevent/general/di/Modules.kt
index 6ec6dd4cdb..80e70b4097 100644
--- a/app/src/main/java/org/fossasia/openevent/general/di/Modules.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/di/Modules.kt
@@ -16,7 +16,6 @@ import org.fossasia.openevent.general.StartupViewModel
import org.fossasia.openevent.general.about.AboutEventViewModel
import org.fossasia.openevent.general.attendees.Attendee
import org.fossasia.openevent.general.attendees.AttendeeApi
-import org.fossasia.openevent.general.attendees.AttendeeId
import org.fossasia.openevent.general.attendees.AttendeeService
import org.fossasia.openevent.general.attendees.AttendeeViewModel
import org.fossasia.openevent.general.attendees.forms.CustomForm
@@ -226,7 +225,7 @@ val apiModule = module {
factory { TicketService(get(), get(), get()) }
factory { SocialLinksService(get(), get()) }
factory { AttendeeService(get(), get(), get()) }
- factory { OrderService(get(), get(), get()) }
+ factory { OrderService(get(), get(), get(), get(), get()) }
factory { SessionService(get(), get()) }
factory { NotificationService(get(), get()) }
factory { FeedbackService(get(), get()) }
@@ -313,7 +312,7 @@ val networkModule = module {
objectMapper, Event::class.java, User::class.java,
SignUp::class.java, Ticket::class.java, SocialLink::class.java, EventId::class.java,
EventTopic::class.java, Attendee::class.java, TicketId::class.java, Order::class.java,
- AttendeeId::class.java, Charge::class.java, Paypal::class.java, ConfirmOrder::class.java,
+ Charge::class.java, Paypal::class.java, ConfirmOrder::class.java,
CustomForm::class.java, EventLocation::class.java, EventType::class.java,
EventSubTopic::class.java, Feedback::class.java, Speaker::class.java, FavoriteEvent::class.java,
Session::class.java, SessionType::class.java, MicroLocation::class.java, SpeakersCall::class.java,
diff --git a/app/src/main/java/org/fossasia/openevent/general/event/EventDao.kt b/app/src/main/java/org/fossasia/openevent/general/event/EventDao.kt
index e733b396cd..084ed9dbcc 100644
--- a/app/src/main/java/org/fossasia/openevent/general/event/EventDao.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/event/EventDao.kt
@@ -25,6 +25,9 @@ interface EventDao {
@Query("SELECT * from Event WHERE id = :id")
fun getEvent(id: Long): Flowable
+ @Query("SELECT * FROM Event WHERE id = :id")
+ fun getEventObjectById(id: Long): Event
+
@Query("SELECT * FROM event WHERE id = :eventId")
fun getEventById(eventId: Long): Single
diff --git a/app/src/main/java/org/fossasia/openevent/general/event/EventDetailsFragment.kt b/app/src/main/java/org/fossasia/openevent/general/event/EventDetailsFragment.kt
index 32b5cb342b..2e49a5df7c 100644
--- a/app/src/main/java/org/fossasia/openevent/general/event/EventDetailsFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/event/EventDetailsFragment.kt
@@ -87,7 +87,6 @@ import org.fossasia.openevent.general.utils.Utils.progressDialog
import org.fossasia.openevent.general.utils.Utils.show
import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber
-import java.util.Currency
import org.fossasia.openevent.general.utils.Utils.setToolbar
import org.fossasia.openevent.general.utils.extensions.setSharedElementEnterTransition
import org.jetbrains.anko.design.longSnackbar
@@ -683,7 +682,7 @@ class EventDetailsFragment : Fragment() {
}
private fun loadTicketFragment() {
- val currency = Currency.getInstance(currentEvent?.paymentCurrency ?: "USD").symbol
+ val currency = currentEvent?.paymentCurrency ?: "USD"
currentEvent?.let {
findNavController(rootView).navigate(EventDetailsFragmentDirections
.actionEventDetailsToTickets(it.id, currency))
diff --git a/app/src/main/java/org/fossasia/openevent/general/event/EventService.kt b/app/src/main/java/org/fossasia/openevent/general/event/EventService.kt
index 4ad43c1db0..d562d0c6fa 100644
--- a/app/src/main/java/org/fossasia/openevent/general/event/EventService.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/event/EventService.kt
@@ -148,7 +148,7 @@ class EventService(
}
fun removeFavorite(favoriteEvent: FavoriteEvent, event: Event): Completable =
- favoriteEventApi.removeFavorite(favoriteEvent.id).andThen {
+ favoriteEventApi.removeFavorite(event.id).andThen {
event.favorite = false
event.favoriteEventId = null
eventDao.insertEvent(event)
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/ExpiredOrderFragment.kt b/app/src/main/java/org/fossasia/openevent/general/order/ExpiredOrderFragment.kt
index e0d41b5400..21a6285df9 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/ExpiredOrderFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/ExpiredOrderFragment.kt
@@ -1,5 +1,6 @@
package org.fossasia.openevent.general.order
+import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -22,6 +23,7 @@ import kotlinx.android.synthetic.main.fragment_expired_order.view.noTicketsScree
import kotlinx.android.synthetic.main.fragment_expired_order.view.shimmerSearch
import kotlinx.android.synthetic.main.fragment_expired_order.view.filterToolbar
import kotlinx.android.synthetic.main.fragment_expired_order.view.toolbar
+import kotlinx.android.synthetic.main.fragment_expired_order.view.swipeRefresh
import org.fossasia.openevent.general.R
import org.fossasia.openevent.general.utils.Utils.setToolbar
import org.fossasia.openevent.general.utils.extensions.nonNull
@@ -57,7 +59,7 @@ class ExpiredOrderFragment : Fragment() {
showNoInternetScreen(false)
} else {
rootView.shimmerSearch.stopShimmer()
- showNoTicketsScreen(ordersPagedListAdapter.currentList?.isEmpty() ?: true)
+ rootView.swipeRefresh.isRefreshing = false
}
})
@@ -76,20 +78,32 @@ class ExpiredOrderFragment : Fragment() {
showNoTicketsScreen(currentItems.size == 0)
ordersPagedListAdapter.submitList(currentItems)
} else {
- if (isConnected) {
- ordersUnderUserVM.getOrdersAndEventsOfUser(true)
- } else {
- showNoInternetScreen(true)
- }
+ ordersUnderUserVM.getOrdersAndEventsOfUser(true, true)
}
})
+ ordersUnderUserVM.numOfTickets
+ .nonNull()
+ .observe(viewLifecycleOwner, Observer {
+ showNoTicketsScreen(it == 0 && !rootView.shimmerSearch.isVisible)
+ })
+
ordersUnderUserVM.eventAndOrderPaged
.nonNull()
.observe(viewLifecycleOwner, Observer {
ordersPagedListAdapter.submitList(it)
})
+ rootView.swipeRefresh.setColorSchemeColors(Color.BLUE)
+ rootView.swipeRefresh.setOnRefreshListener {
+ if (ordersUnderUserVM.isConnected()) {
+ ordersUnderUserVM.clearOrders()
+ ordersUnderUserVM.getOrdersAndEventsOfUser(showExpired = true, fromDb = false)
+ } else {
+ rootView.swipeRefresh.isRefreshing = false
+ }
+ }
+
return rootView
}
@@ -134,7 +148,7 @@ class ExpiredOrderFragment : Fragment() {
ordersUnderUserVM.clearOrders()
ordersPagedListAdapter.clear()
if (ordersUnderUserVM.isConnected()) {
- ordersUnderUserVM.getOrdersAndEventsOfUser(true)
+ ordersUnderUserVM.getOrdersAndEventsOfUser(true, true)
} else {
showNoInternetScreen(true)
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/Order.kt b/app/src/main/java/org/fossasia/openevent/general/order/Order.kt
index dc8913a78c..4cc17d9f44 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/Order.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/Order.kt
@@ -10,7 +10,7 @@ import com.github.jasminb.jsonapi.annotations.Id
import com.github.jasminb.jsonapi.annotations.Relationship
import com.github.jasminb.jsonapi.annotations.Type
import io.reactivex.annotations.NonNull
-import org.fossasia.openevent.general.attendees.AttendeeId
+import org.fossasia.openevent.general.attendees.Attendee
import org.fossasia.openevent.general.event.EventId
@Type("order")
@@ -28,6 +28,7 @@ data class Order(
val identifier: String? = null,
val orderNotes: String? = null,
val completedAt: String? = null,
+ val state: String? = null,
val city: String? = null,
val address: String? = null,
val createdAt: String? = null,
@@ -39,9 +40,10 @@ data class Order(
val isBillingEnabled: Boolean = false,
val taxBusinessInfo: String? = null,
val company: String? = null,
+ var isExpired: Boolean? = null,
@ColumnInfo(index = true)
@Relationship("event")
var event: EventId? = null,
@Relationship("attendees")
- var attendees: List = emptyList()
+ var attendees: List = emptyList()
)
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderApi.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderApi.kt
index 54750b4f36..0438bfab10 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderApi.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderApi.kt
@@ -1,7 +1,6 @@
package org.fossasia.openevent.general.order
import io.reactivex.Single
-import org.fossasia.openevent.general.attendees.Attendee
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
@@ -24,14 +23,11 @@ interface OrderApi {
"\"placed\",\"pending\"]}]&include=event,attendees&fields[attendees]=id")
fun ordersUnderUser(@Path("userId") userId: Long): Single>
- @GET("/v1/users/{userId}/orders?include=event,attendees&fields[attendees]=id")
+ @GET("/v1/users/{userId}/orders?include=event,attendees")
fun ordersUnderUserPaged(
@Path("userId") userId: Long,
@Query("filter") filter: String,
@Query("page[number]") page: Int,
@Query("page[size]") pageSize: Int = 5
): Single>
-
- @GET("/v1/orders/{orderIdentifier}/attendees")
- fun attendeesUnderOrder(@Path("orderIdentifier") orderIdentifier: String): Single>
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderDao.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderDao.kt
index 2214378142..5579ec1fe3 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderDao.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderDao.kt
@@ -17,6 +17,9 @@ interface OrderDao {
@Query("SELECT * FROM `order`")
fun getAllOrders(): Single>
+ @Query("SELECT * FROM `order` WHERE isExpired = :expired")
+ fun getOrders(expired: Boolean): Single>
+
@Query("DELETE FROM `order`")
fun deleteAllOrders()
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSource.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSource.kt
index 8dc669941d..280dbeb18f 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSource.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSource.kt
@@ -6,6 +6,9 @@ import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.fossasia.openevent.general.R
+import org.fossasia.openevent.general.attendees.ORDER_STATUS_COMPLETED
+import org.fossasia.openevent.general.attendees.ORDER_STATUS_PENDING
+import org.fossasia.openevent.general.attendees.ORDER_STATUS_PLACED
import org.fossasia.openevent.general.common.SingleLiveEvent
import org.fossasia.openevent.general.data.Resource
import org.fossasia.openevent.general.event.Event
@@ -25,12 +28,16 @@ class OrderDataSource(
private val mutableProgress: MutableLiveData,
private val mutableNumOfTickets: MutableLiveData,
private val mutableMessage: SingleLiveEvent,
- private val filter: OrderFilter
+ private val filter: OrderFilter,
+ private val fromDb: Boolean
) : PageKeyedDataSource>() {
private val resource = Resource()
override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback>) {
- createObservable(1, 2, callback, null)
+ if (fromDb)
+ getOrdersFromDb(callback)
+ else
+ createObservable(1, 2, callback, null)
}
override fun loadAfter(params: LoadParams, callback: LoadCallback>) {
@@ -43,6 +50,31 @@ class OrderDataSource(
createObservable(page, page - 1, null, callback)
}
+ private fun getOrdersFromDb(callback: LoadInitialCallback>) {
+ compositeDisposable += orderService.getOrderAndEventSourceFactoryFromDb(showExpired)
+ .withDefaultSchedulers()
+ .subscribe({
+ val filteredList = it.filterNotNull().filter {
+ if (filter.isShowingCompletedOrders) true else it.second.status != ORDER_STATUS_COMPLETED
+ }.filter {
+ if (filter.isShowingPendingOrders) true else it.second.status != ORDER_STATUS_PENDING
+ }.filter {
+ if (filter.isShowingPlacedOrders) true else it.second.status != ORDER_STATUS_PLACED
+ }
+ if (filteredList.isEmpty()) {
+ createObservable(1, 2, callback, null)
+ } else {
+ mutableNumOfTickets.value = filteredList.size
+ callback.onResult(filteredList, null, null)
+ mutableProgress.value = false
+ }
+ }, {
+ mutableMessage.value = resource.getString(R.string.list_events_fail_message)
+ Timber.e(it, "Fail on fetching orders ")
+ mutableProgress.value = false
+ })
+ }
+
private fun createObservable(
requestedPage: Int,
adjacentPage: Int,
@@ -100,13 +132,13 @@ class OrderDataSource(
| 'name':'event',
| 'op':'has',
| 'val': {
- | 'name':'starts-at',
+ | 'name':'ends-at',
| 'op':'$operator',
| 'val':'%${EventUtils.getTimeInISO8601(Date())}%'
| }
| }]
|}]""".trimMargin().replace("'", "\"")
- val ordersList = orderService.getOrdersOfUserPaged(userId, ordersQuery, page)
+ val ordersList = orderService.getOrdersOfUserPaged(userId, ordersQuery, page, showExpired)
return ordersList.flatMap { orders ->
val ids = orders.map { it.event?.id }.distinct()
val eventsQuery = """[{
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSourceFactory.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSourceFactory.kt
index b4999e3446..db481f61f5 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSourceFactory.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderDataSourceFactory.kt
@@ -16,7 +16,8 @@ class OrderDataSourceFactory(
private val mutableNumOfTicket: MutableLiveData,
private val mutableMessage: SingleLiveEvent,
private val userId: Long,
- private val orderFilter: OrderFilter
+ private val orderFilter: OrderFilter,
+ private val fromDb: Boolean
) : DataSource.Factory>() {
override fun create(): DataSource> {
return OrderDataSource(
@@ -28,7 +29,8 @@ class OrderDataSourceFactory(
mutableProgress,
mutableNumOfTicket,
mutableMessage,
- orderFilter
+ orderFilter,
+ fromDb
)
}
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsFragment.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsFragment.kt
index 7d26ba2078..db7f630536 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsFragment.kt
@@ -15,7 +15,6 @@ import android.view.View
import android.view.ViewGroup
import android.view.Menu
import android.view.MenuInflater
-import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
@@ -38,7 +37,6 @@ import org.fossasia.openevent.general.utils.Utils.progressDialog
import org.fossasia.openevent.general.utils.Utils.show
import org.fossasia.openevent.general.utils.extensions.nonNull
import org.koin.androidx.viewmodel.ext.android.viewModel
-import timber.log.Timber
import org.fossasia.openevent.general.utils.Utils.setToolbar
import org.jetbrains.anko.design.longSnackbar
import org.jetbrains.anko.design.snackbar
@@ -60,28 +58,6 @@ class OrderDetailsFragment : Fragment() {
super.onCreate(savedInstanceState)
ordersRecyclerAdapter.setOrderIdentifier(safeArgs.orderIdentifier)
-
- orderDetailsViewModel.event
- .nonNull()
- .observe(this, Observer {
- ordersRecyclerAdapter.setEvent(it)
- Picasso.get()
- .load(it.originalImageUrl)
- .error(R.drawable.header)
- .placeholder(R.drawable.header)
- .into(rootView.backgroundImage)
- })
-
- orderDetailsViewModel.attendees
- .nonNull()
- .observe(this, Observer {
- if (it.isEmpty()) {
- Toast.makeText(context, getString(R.string.error_fetching_attendees), Toast.LENGTH_SHORT).show()
- activity?.onBackPressed()
- }
- ordersRecyclerAdapter.addAll(it)
- Timber.d("Fetched attendees of size %s", ordersRecyclerAdapter.itemCount)
- })
}
override fun onCreateView(
@@ -144,8 +120,40 @@ class OrderDetailsFragment : Fragment() {
rootView.orderDetailCoordinatorLayout.longSnackbar(it)
})
- orderDetailsViewModel.loadEvent(safeArgs.eventId)
- orderDetailsViewModel.loadAttendeeDetails(safeArgs.orderId)
+ orderDetailsViewModel.event
+ .nonNull()
+ .observe(viewLifecycleOwner, Observer {
+ ordersRecyclerAdapter.setEvent(it)
+ Picasso.get()
+ .load(it.originalImageUrl)
+ .error(R.drawable.header)
+ .placeholder(R.drawable.header)
+ .into(rootView.backgroundImage)
+ })
+
+ orderDetailsViewModel.attendees
+ .nonNull()
+ .observe(viewLifecycleOwner, Observer {
+ ordersRecyclerAdapter.addAll(it)
+ })
+
+ val currentEvent = orderDetailsViewModel.event.value
+ if (currentEvent == null) {
+ orderDetailsViewModel.loadEvent(safeArgs.eventId)
+ } else {
+ ordersRecyclerAdapter.setEvent(currentEvent)
+ Picasso.get()
+ .load(currentEvent.originalImageUrl)
+ .error(R.drawable.header)
+ .placeholder(R.drawable.header)
+ .into(rootView.backgroundImage)
+ }
+
+ val currentAttendees = orderDetailsViewModel.attendees.value
+ if (currentAttendees == null)
+ orderDetailsViewModel.loadAttendeeDetails(safeArgs.orderId)
+ else
+ ordersRecyclerAdapter.addAll(currentAttendees)
writePermissionGranted = (ContextCompat.checkSelfPermission(requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewHolder.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewHolder.kt
index fd0826f1a5..14cc92ed07 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewHolder.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewHolder.kt
@@ -5,14 +5,11 @@ import android.content.Intent
import android.net.Uri
import android.provider.CalendarContract
import android.view.View
-import android.view.ViewGroup.LayoutParams.MATCH_PARENT
-import android.widget.FrameLayout
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.item_card_order_details.view.calendar
import kotlinx.android.synthetic.main.item_card_order_details.view.eventDetails
import kotlinx.android.synthetic.main.item_card_order_details.view.map
-import kotlinx.android.synthetic.main.item_card_order_details.view.mainLayout
import kotlinx.android.synthetic.main.item_card_order_details.view.qrCodeView
import kotlinx.android.synthetic.main.item_card_order_details.view.downloadButton
import kotlinx.android.synthetic.main.item_card_order_details.view.checkedInLayout
@@ -57,18 +54,6 @@ class OrderDetailsViewHolder(private val binding: ItemCardOrderDetailsBinding) :
identifier = ticketIdentifier
}
- if (position == 0) {
- val params: FrameLayout.LayoutParams =
- FrameLayout.LayoutParams(resources.getDimension(R.dimen.ticket_width).toInt(), MATCH_PARENT)
- params.leftMargin = resources.getDimension(R.dimen.layout_margin_large).toInt()
- itemView.mainLayout.layoutParams = params
- } else if (position + 1 == count) {
- val params: FrameLayout.LayoutParams =
- FrameLayout.LayoutParams(resources.getDimension(R.dimen.ticket_width).toInt(), MATCH_PARENT)
- params.rightMargin = resources.getDimension(R.dimen.layout_margin_large).toInt()
- itemView.mainLayout.layoutParams = params
- }
-
if (attendee.isCheckedIn != null) {
itemView.checkedInLayout.isVisible = attendee.isCheckedIn
itemView.notCheckedInLayout.isVisible = !attendee.isCheckedIn
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewModel.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewModel.kt
index f7f2176cb9..58ca14f9c6 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewModel.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderDetailsViewModel.kt
@@ -57,7 +57,7 @@ class OrderDetailsViewModel(
compositeDisposable += orderService
.getOrderById(orderId)
.flatMap { order ->
- orderService.getAttendeesUnderOrder(order.identifier ?: "", order.attendees.map { it.id })
+ orderService.getAttendeesUnderOrder(order.attendees.map { it.id })
}
.withDefaultSchedulers()
.doOnSubscribe {
@@ -66,6 +66,7 @@ class OrderDetailsViewModel(
mutableProgress.value = false
}.subscribe({
mutableAttendees.value = it
+ Timber.d("Fetched attendees of size %s", it)
}, {
Timber.e(it, "Error fetching attendee details")
message.value = resource.getString(R.string.error_fetching_attendee_details_message)
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrderService.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrderService.kt
index d27443ebb7..d0bd867f6a 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrderService.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrderService.kt
@@ -3,12 +3,34 @@ package org.fossasia.openevent.general.order
import io.reactivex.Single
import org.fossasia.openevent.general.attendees.Attendee
import org.fossasia.openevent.general.attendees.AttendeeDao
+import org.fossasia.openevent.general.paypal.Paypal
+import org.fossasia.openevent.general.paypal.PaypalApi
+import org.fossasia.openevent.general.paypal.PaypalPaymentResponse
+import org.fossasia.openevent.general.event.Event
+import org.fossasia.openevent.general.event.EventDao
class OrderService(
private val orderApi: OrderApi,
private val orderDao: OrderDao,
- private val attendeeDao: AttendeeDao
+ private val attendeeDao: AttendeeDao,
+ private val paypalApi: PaypalApi,
+ private val eventDao: EventDao
) {
+ fun verifyPaypalPayment(orderIdentifier: String, paymentId: String): Single =
+ paypalApi.verifyPaypalPayment(orderIdentifier, Paypal(paymentId = paymentId))
+
+ fun getOrderAndEventSourceFactoryFromDb(showExpired: Boolean): Single?>> {
+ return orderDao.getOrders(showExpired)
+ .map {
+ it.map { order ->
+ order.event?.id?.let { eventId ->
+ val event = eventDao.getEventObjectById(eventId)
+ Pair(event, order)
+ }
+ }
+ }
+ }
+
fun placeOrder(order: Order): Single {
return orderApi.placeOrder(order)
.map { order ->
@@ -40,10 +62,15 @@ class OrderService(
}
}
- fun getOrdersOfUserPaged(userId: Long, query: String, page: Int): Single> {
+ fun getOrdersOfUserPaged(userId: Long, query: String, page: Int, isExpired: Boolean): Single> {
return orderApi.ordersUnderUserPaged(userId, query, page).map {
- orderDao.insertOrders(it)
- it
+ val updatedOrdersList = it.map {
+ it.isExpired = isExpired
+ it
+ }
+ orderDao.insertOrders(updatedOrdersList)
+ attendeeDao.insertAttendees(updatedOrdersList.map { it.attendees }.flatten())
+ updatedOrdersList
}
}
@@ -51,13 +78,7 @@ class OrderService(
return orderDao.getOrderById(orderId)
}
- fun getAttendeesUnderOrder(orderIdentifier: String, attendeesIds: List): Single> {
- return orderApi.attendeesUnderOrder(orderIdentifier)
- .map {
- attendeeDao.insertAttendees(it)
- it
- }.onErrorResumeNext {
- attendeeDao.getAttendeesWithIds(attendeesIds)
- }
+ fun getAttendeesUnderOrder(attendeesIds: List): Single> {
+ return attendeeDao.getAttendeesWithIds(attendeesIds)
}
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserFragment.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserFragment.kt
index fb600b5886..aabd441697 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserFragment.kt
@@ -1,5 +1,6 @@
package org.fossasia.openevent.general.order
+import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
@@ -23,6 +24,7 @@ import kotlinx.android.synthetic.main.fragment_orders_under_user.view.findMyTick
import kotlinx.android.synthetic.main.fragment_orders_under_user.view.noTicketsScreen
import kotlinx.android.synthetic.main.fragment_orders_under_user.view.ordersRecycler
import kotlinx.android.synthetic.main.fragment_orders_under_user.view.shimmerSearch
+import kotlinx.android.synthetic.main.fragment_orders_under_user.view.swipeRefresh
import kotlinx.android.synthetic.main.fragment_orders_under_user.view.scrollView
import kotlinx.android.synthetic.main.fragment_orders_under_user.view.pastEvent
import kotlinx.android.synthetic.main.fragment_orders_under_user.view.ticketsNumber
@@ -80,11 +82,7 @@ class OrdersUnderUserFragment : Fragment(), BottomIconDoubleClick {
showNoTicketsScreen(currentItems.size == 0)
ordersPagedListAdapter.submitList(currentItems)
} else {
- if (isConnected) {
- ordersUnderUserVM.getOrdersAndEventsOfUser(false)
- } else {
- showNoInternetScreen(true)
- }
+ ordersUnderUserVM.getOrdersAndEventsOfUser(showExpired = false, fromDb = true)
}
})
@@ -92,6 +90,7 @@ class OrdersUnderUserFragment : Fragment(), BottomIconDoubleClick {
.nonNull()
.observe(viewLifecycleOwner, Observer {
rootView.ticketsNumber.text = resources.getQuantityString(R.plurals.numOfOrders, it, it)
+ showNoTicketsScreen(it == 0 && !rootView.shimmerSearch.isVisible)
})
ordersUnderUserVM.showShimmerResults
@@ -103,7 +102,7 @@ class OrdersUnderUserFragment : Fragment(), BottomIconDoubleClick {
showNoInternetScreen(false)
} else {
rootView.shimmerSearch.stopShimmer()
- showNoTicketsScreen(ordersPagedListAdapter.currentList?.isEmpty() ?: true)
+ rootView.swipeRefresh.isRefreshing = false
}
rootView.shimmerSearch.isVisible = it
})
@@ -120,6 +119,16 @@ class OrdersUnderUserFragment : Fragment(), BottomIconDoubleClick {
ordersPagedListAdapter.submitList(it)
})
+ rootView.swipeRefresh.setColorSchemeColors(Color.BLUE)
+ rootView.swipeRefresh.setOnRefreshListener {
+ if (ordersUnderUserVM.isConnected()) {
+ ordersUnderUserVM.clearOrders()
+ ordersUnderUserVM.getOrdersAndEventsOfUser(showExpired = false, fromDb = false)
+ } else {
+ rootView.swipeRefresh.isRefreshing = false
+ }
+ }
+
return rootView
}
@@ -182,7 +191,7 @@ class OrdersUnderUserFragment : Fragment(), BottomIconDoubleClick {
ordersUnderUserVM.clearOrders()
ordersPagedListAdapter.clear()
if (ordersUnderUserVM.isConnected()) {
- ordersUnderUserVM.getOrdersAndEventsOfUser(false)
+ ordersUnderUserVM.getOrdersAndEventsOfUser(showExpired = false, fromDb = false)
} else {
showNoInternetScreen(true)
}
@@ -190,6 +199,7 @@ class OrdersUnderUserFragment : Fragment(), BottomIconDoubleClick {
override fun onDestroyView() {
super.onDestroyView()
+ rootView.swipeRefresh.setOnRefreshListener(null)
ordersPagedListAdapter.setListener(null)
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserViewModel.kt b/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserViewModel.kt
index f9e02bb32c..739dd616e3 100644
--- a/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserViewModel.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/order/OrdersUnderUserViewModel.kt
@@ -43,7 +43,7 @@ class OrdersUnderUserViewModel(
fun isLoggedIn() = authHolder.isLoggedIn()
- fun getOrdersAndEventsOfUser(showExpired: Boolean) {
+ fun getOrdersAndEventsOfUser(showExpired: Boolean, fromDb: Boolean) {
val sourceFactory = OrderDataSourceFactory(
orderService,
@@ -54,7 +54,8 @@ class OrdersUnderUserViewModel(
mutableNumOfTickets,
mutableMessage,
getId(),
- filter
+ filter,
+ fromDb
)
val ordersAndEventsPagedList = RxPagedListBuilder(sourceFactory, config)
diff --git a/app/src/main/java/org/fossasia/openevent/general/paypal/Paypal.kt b/app/src/main/java/org/fossasia/openevent/general/paypal/Paypal.kt
index 6404569514..6cfbb83312 100644
--- a/app/src/main/java/org/fossasia/openevent/general/paypal/Paypal.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/paypal/Paypal.kt
@@ -1,13 +1,14 @@
package org.fossasia.openevent.general.paypal
-import com.github.jasminb.jsonapi.IntegerIdHandler
+import com.fasterxml.jackson.databind.PropertyNamingStrategy
+import com.fasterxml.jackson.databind.annotation.JsonNaming
import com.github.jasminb.jsonapi.annotations.Id
import com.github.jasminb.jsonapi.annotations.Type
-@Type("paypal-payment")
-data class Paypal(
- @Id(IntegerIdHandler::class)
- val id: Int,
- val cancelUrl: String? = null,
- val returnUrl: String? = null
+@Type("order")
+@JsonNaming(PropertyNamingStrategy.KebabCaseStrategy::class)
+class Paypal(
+ @Id
+ val id: Int? = null,
+ val paymentId: String
)
diff --git a/app/src/main/java/org/fossasia/openevent/general/paypal/PaypalApi.kt b/app/src/main/java/org/fossasia/openevent/general/paypal/PaypalApi.kt
index 6513a4d771..1608d536c7 100644
--- a/app/src/main/java/org/fossasia/openevent/general/paypal/PaypalApi.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/paypal/PaypalApi.kt
@@ -1,11 +1,15 @@
package org.fossasia.openevent.general.paypal
+import io.reactivex.Single
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Path
interface PaypalApi {
- @POST("orders/{orderIdentifier}/create-paypal-payment")
- fun createPaypalPayment(@Path("orderIdentifier") orderIdentifier: String, @Body paypal: Paypal)
+ @POST("orders/{orderIdentifier}/verify-mobile-paypal-payment")
+ fun verifyPaypalPayment(
+ @Path("orderIdentifier") orderIdentifier: String,
+ @Body paypal: Paypal
+ ): Single
}
diff --git a/app/src/main/java/org/fossasia/openevent/general/paypal/CreatePaypalPaymentResponse.kt b/app/src/main/java/org/fossasia/openevent/general/paypal/PaypalPaymentResponse.kt
similarity index 74%
rename from app/src/main/java/org/fossasia/openevent/general/paypal/CreatePaypalPaymentResponse.kt
rename to app/src/main/java/org/fossasia/openevent/general/paypal/PaypalPaymentResponse.kt
index 371fed4f4f..e7abd4d5e4 100644
--- a/app/src/main/java/org/fossasia/openevent/general/paypal/CreatePaypalPaymentResponse.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/paypal/PaypalPaymentResponse.kt
@@ -4,8 +4,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.annotation.JsonNaming
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
-data class CreatePaypalPaymentResponse(
+data class PaypalPaymentResponse(
val status: Boolean,
- val paymentId: String,
- val error: String
+ val error: String? = null
)
diff --git a/app/src/main/java/org/fossasia/openevent/general/settings/SettingsFragment.kt b/app/src/main/java/org/fossasia/openevent/general/settings/SettingsFragment.kt
index 0ebe9cff88..0e2214911d 100644
--- a/app/src/main/java/org/fossasia/openevent/general/settings/SettingsFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/settings/SettingsFragment.kt
@@ -46,8 +46,7 @@ import org.fossasia.openevent.general.utils.extensions.nonNull
const val LOCAL_TIMEZONE = "localTimeZone"
class SettingsFragment : PreferenceFragmentCompat(), PreferenceChangeListener {
- private val FORM_LINK: String = "https://docs.google.com/forms/d/e/" +
- "1FAIpQLSd7Y1T1xoXeYaAG_b6Tu1YYK-jZssoC5ltmQbkUX0kmDZaKYw/viewform"
+
private val PRIVACY_LINK: String = "https://eventyay.com/privacy-policy"
private val TERMS_OF_SERVICE_LINK: String = "https://eventyay.com/terms"
private val REFUND_POLICY_LINK: String = "https://eventyay.com/refunds"
@@ -125,11 +124,7 @@ class SettingsFragment : PreferenceFragmentCompat(), PreferenceChangeListener {
startAppPlayStore(activity?.packageName.nullToEmpty())
return true
}
- if (preference?.key == getString(R.string.key_suggestion)) {
- // Links to suggestion form
- Utils.openUrl(requireContext(), FORM_LINK)
- return true
- }
+
if (preference?.key == getString(R.string.key_profile)) {
showLogoutDialog()
return true
diff --git a/app/src/main/java/org/fossasia/openevent/general/ticket/TicketsFragment.kt b/app/src/main/java/org/fossasia/openevent/general/ticket/TicketsFragment.kt
index 7b9cae6a6e..727b76a359 100644
--- a/app/src/main/java/org/fossasia/openevent/general/ticket/TicketsFragment.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/ticket/TicketsFragment.kt
@@ -42,6 +42,8 @@ import org.fossasia.openevent.general.utils.extensions.nonNull
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.fossasia.openevent.general.utils.Utils.setToolbar
import org.jetbrains.anko.design.longSnackbar
+import java.util.Currency
+import kotlin.collections.ArrayList
const val TICKETS_FRAGMENT = "ticketsFragment"
const val APPLY_DISCOUNT_CODE = 1
@@ -58,7 +60,7 @@ class TicketsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- ticketsRecyclerAdapter.setCurrency(safeArgs.currency)
+ ticketsRecyclerAdapter.setCurrency(Currency.getInstance(safeArgs.currency).symbol)
}
override fun onCreateView(
diff --git a/app/src/main/java/org/fossasia/openevent/general/utils/Error.kt b/app/src/main/java/org/fossasia/openevent/general/utils/Error.kt
index e6ce71fb8d..aa7a96bf46 100644
--- a/app/src/main/java/org/fossasia/openevent/general/utils/Error.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/utils/Error.kt
@@ -7,6 +7,7 @@ class Error {
var title: String? = null
var detail: String? = null
var pointer: String? = null
+ var code: String? = null
override fun toString(): String {
diff --git a/app/src/main/java/org/fossasia/openevent/general/utils/ErrorUtils.kt b/app/src/main/java/org/fossasia/openevent/general/utils/ErrorUtils.kt
index 7a7a672052..b946ee8693 100644
--- a/app/src/main/java/org/fossasia/openevent/general/utils/ErrorUtils.kt
+++ b/app/src/main/java/org/fossasia/openevent/general/utils/ErrorUtils.kt
@@ -18,6 +18,7 @@ const val SOURCE = "source"
const val POINTER = "pointer"
const val DETAIL = "detail"
const val TITLE = "title"
+const val CODE = "code"
const val POINTER_LENGTH = 3
@@ -62,6 +63,7 @@ object ErrorUtils {
} else {
error.pointer = pointedField
error.detail = jsonArray.get(DETAIL).toString().replace(".", "")
+ error.code = errorSource.get(CODE).toString()
}
} catch (e: Exception) {
error.detail = jsonArray.get(DETAIL).toString()
@@ -91,6 +93,7 @@ object ErrorUtils {
} else {
error.pointer = pointedField
error.detail = jsonArray.get(DETAIL).toString().replace(".", "")
+ error.code = errorSource.get(CODE).toString()
}
error.title = jsonArray.get(TITLE).toString()
} catch (e: Exception) {
diff --git a/app/src/main/res/layout-land/item_card_order_details.xml b/app/src/main/res/layout-land/item_card_order_details.xml
index da851ee0fc..706bb0c614 100644
--- a/app/src/main/res/layout-land/item_card_order_details.xml
+++ b/app/src/main/res/layout-land/item_card_order_details.xml
@@ -157,6 +157,17 @@
android:background="@drawable/circle_shape"/>
+
+
+
+
+
+
+
-
-
diff --git a/app/src/main/res/layout/fragment_expired_order.xml b/app/src/main/res/layout/fragment_expired_order.xml
index 5c2e9da368..08f067ee89 100644
--- a/app/src/main/res/layout/fragment_expired_order.xml
+++ b/app/src/main/res/layout/fragment_expired_order.xml
@@ -22,6 +22,10 @@
android:background="?selectableItemBackground"
android:src="@drawable/ic_filter" />
+
+
diff --git a/app/src/main/res/layout/fragment_order_details.xml b/app/src/main/res/layout/fragment_order_details.xml
index db62dd8c94..cf249000b6 100644
--- a/app/src/main/res/layout/fragment_order_details.xml
+++ b/app/src/main/res/layout/fragment_order_details.xml
@@ -14,7 +14,7 @@
diff --git a/app/src/main/res/layout/fragment_orders_under_user.xml b/app/src/main/res/layout/fragment_orders_under_user.xml
index ac6c7b7f10..a781aeaf24 100644
--- a/app/src/main/res/layout/fragment_orders_under_user.xml
+++ b/app/src/main/res/layout/fragment_orders_under_user.xml
@@ -4,6 +4,10 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
+
-
+
diff --git a/app/src/main/res/values-bn-rIN/strings.xml b/app/src/main/res/values-bn-rIN/strings.xml
index c863ef7030..dd5387f9fb 100644
--- a/app/src/main/res/values-bn-rIN/strings.xml
+++ b/app/src/main/res/values-bn-rIN/strings.xml
@@ -119,8 +119,6 @@
এবাউট
রেটিং
রেটিং দিন
- পরামর্শ দিন
- পরামর্শ
প্রোফাইল
একাউন্ট
ইভেন্টের সময় অঞ্চল ব্যবহার করুন
diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml
index 29101939aa..1efa06b532 100644
--- a/app/src/main/res/values-hi-rIN/strings.xml
+++ b/app/src/main/res/values-hi-rIN/strings.xml
@@ -118,8 +118,6 @@
अबाउट
रेटिंग
रेट उस
- सुझाव में सुधार
- सुझाव
प्रोफ़ाइल
अकाउंट
ईवेंट के समय-क्षेत्र का उपयोग करें
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 62b4e2fc3e..c42a1fce69 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -90,8 +90,6 @@
Thông tin
đánh giá
Đánh Giá Chúng Tôi
- Gợi Ý Cải Thiện
- gợi ý
thông tin
Tài Khoản
Bảo Mật
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5caea59dbb..8e19cef4a7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -181,9 +181,7 @@
account
Rate Us
Open Event Android
- Suggest Improvement
key_acknowledgements
- suggestion
profile
Account
timeZoneSwitch
@@ -532,5 +530,7 @@
Incorrect old password provided!
Unable to change password!
Password changed successfully!
+ Ticket(s) for %1$s
+ Fail on making Paypal payment
diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml
index 1e00ead312..539a66ef45 100644
--- a/app/src/main/res/xml/settings.xml
+++ b/app/src/main/res/xml/settings.xml
@@ -51,11 +51,6 @@
android:title="@string/rating_settings"
app:iconSpaceReserved="false" />
-
-