Skip to content

Commit a163c69

Browse files
Merge branch 'development' into iss1344
2 parents 95b2b4f + a79807c commit a163c69

36 files changed

+1174
-373
lines changed

app/build.gradle

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ android {
6666
packagingOptions {
6767
pickFirst 'kotlin/**'
6868
}
69+
lintOptions {
70+
disable 'MissingTranslation'
71+
}
72+
androidExtensions {
73+
experimental = true
74+
}
6975
}
7076

7177
spotless {
@@ -155,6 +161,12 @@ dependencies {
155161
implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0'
156162
implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0'
157163

164+
// Stetho
165+
debugImplementation 'com.facebook.stetho:stetho:1.5.1'
166+
debugImplementation 'com.facebook.stetho:stetho-okhttp3:1.5.1'
167+
releaseImplementation 'com.github.iamareebjamal:stetho-noop:1.2.1'
168+
testImplementation 'com.github.iamareebjamal:stetho-noop:1.2.1'
169+
158170
testImplementation 'junit:junit:4.12'
159171
testImplementation "io.mockk:mockk:1.9.2"
160172
testImplementation 'org.threeten:threetenbp:1.3.8'

app/src/main/java/org/fossasia/openevent/general/OpenEventGeneral.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package org.fossasia.openevent.general
22

33
import android.content.Context
44
import androidx.multidex.MultiDexApplication
5+
import com.facebook.stetho.Stetho
56
import com.jakewharton.threetenabp.AndroidThreeTen
67
import org.fossasia.openevent.general.di.apiModule
78
import org.fossasia.openevent.general.di.commonModule
89
import org.fossasia.openevent.general.di.databaseModule
910
import org.fossasia.openevent.general.di.flavorSpecificModule
11+
import org.fossasia.openevent.general.di.fragmentsModule
1012
import org.fossasia.openevent.general.di.networkModule
1113
import org.fossasia.openevent.general.di.viewModelModule
1214
import org.koin.android.ext.android.startKoin
@@ -24,9 +26,19 @@ class OpenEventGeneral : MultiDexApplication() {
2426
super.onCreate()
2527
appContext = applicationContext
2628
startKoin(this, listOf(
27-
commonModule, apiModule, viewModelModule, networkModule, databaseModule, flavorSpecificModule
29+
commonModule,
30+
apiModule,
31+
viewModelModule,
32+
networkModule,
33+
databaseModule,
34+
flavorSpecificModule,
35+
fragmentsModule
2836
))
2937
Timber.plant(Timber.DebugTree())
3038
AndroidThreeTen.init(applicationContext)
39+
40+
if (BuildConfig.DEBUG) {
41+
Stetho.initializeWithDefaults(this)
42+
}
3143
}
3244
}

app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeFragment.kt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.fossasia.openevent.general.attendees
22

33
import android.app.AlertDialog
4+
import android.content.Context
45
import android.content.pm.PackageManager
56
import android.os.Bundle
7+
import android.telephony.TelephonyManager
68
import android.text.Editable
79
import android.text.Spannable
810
import android.text.SpannableStringBuilder
@@ -32,7 +34,6 @@ import com.stripe.android.TokenCallback
3234
import com.stripe.android.model.Card
3335
import com.stripe.android.model.Token
3436
import kotlinx.android.synthetic.main.fragment_attendee.cardNumber
35-
import kotlinx.android.synthetic.main.fragment_attendee.country
3637
import kotlinx.android.synthetic.main.fragment_attendee.cvc
3738
import kotlinx.android.synthetic.main.fragment_attendee.email
3839
import kotlinx.android.synthetic.main.fragment_attendee.firstName
@@ -45,7 +46,6 @@ import kotlinx.android.synthetic.main.fragment_attendee.view.amount
4546
import kotlinx.android.synthetic.main.fragment_attendee.view.attendeeInformation
4647
import kotlinx.android.synthetic.main.fragment_attendee.view.attendeeRecycler
4748
import kotlinx.android.synthetic.main.fragment_attendee.view.cardSelector
48-
import kotlinx.android.synthetic.main.fragment_attendee.view.countryArea
4949
import kotlinx.android.synthetic.main.fragment_attendee.view.eventName
5050
import kotlinx.android.synthetic.main.fragment_attendee.view.month
5151
import kotlinx.android.synthetic.main.fragment_attendee.view.monthText
@@ -65,6 +65,8 @@ import kotlinx.android.synthetic.main.fragment_attendee.view.year
6565
import kotlinx.android.synthetic.main.fragment_attendee.view.yearText
6666
import kotlinx.android.synthetic.main.fragment_attendee.view.cardNumber
6767
import kotlinx.android.synthetic.main.fragment_attendee.view.acceptCheckbox
68+
import kotlinx.android.synthetic.main.fragment_attendee.view.countryPicker
69+
import kotlinx.android.synthetic.main.fragment_attendee.view.countryPickerContainer
6870
import org.fossasia.openevent.general.R
6971
import org.fossasia.openevent.general.attendees.forms.CustomForm
7072
import org.fossasia.openevent.general.event.Event
@@ -216,6 +218,14 @@ class AttendeeFragment : Fragment() {
216218

217219
attendeeViewModel.initializeSpinner()
218220

221+
ArrayAdapter.createFromResource(
222+
requireContext(), R.array.country_arrays,
223+
android.R.layout.simple_spinner_dropdown_item
224+
).also { adapter ->
225+
rootView.countryPicker.adapter = adapter
226+
autoSetCurrentCountry()
227+
}
228+
219229
rootView.cardNumber.addTextChangedListener(object : TextWatcher {
220230
override fun afterTextChanged(s: Editable?) {
221231
}
@@ -375,7 +385,7 @@ class AttendeeFragment : Fragment() {
375385
.nonNull()
376386
.observe(this, Observer {
377387
if (singleTicket) {
378-
rootView.countryArea.visibility = if (it) View.VISIBLE else View.GONE
388+
rootView.countryPickerContainer.visibility = if (it) View.VISIBLE else View.GONE
379389
}
380390
})
381391

@@ -452,7 +462,7 @@ class AttendeeFragment : Fragment() {
452462
}
453463

454464
if (attendeeViewModel.areAttendeeEmailsValid(attendees)) {
455-
val country = if (country.text.isEmpty()) country.text.toString() else null
465+
val country = rootView.countryPicker.selectedItem.toString()
456466
attendeeViewModel.createAttendees(attendees, country, paymentOptions[selectedPaymentOption])
457467

458468
attendeeViewModel.isAttendeeCreated.observe(this, Observer { isAttendeeCreated ->
@@ -492,7 +502,7 @@ class AttendeeFragment : Fragment() {
492502

493503
private fun sendToken() {
494504
val card = Card(cardNumber.text.toString(), expiryMonth, expiryYear.toInt(), cvc.text.toString())
495-
card.addressCountry = country.text.toString()
505+
card.addressCountry = rootView.countryPicker.selectedItem.toString()
496506
card.addressZip = postalCode.text.toString()
497507

498508
if (card.brand != null && card.brand != "Unknown")
@@ -578,4 +588,13 @@ class AttendeeFragment : Fragment() {
578588
val index = identifierList.indexOf(identifier)
579589
return if (index == -1) "" else index.let { editTextList[it] }.text.toString()
580590
}
591+
592+
private fun autoSetCurrentCountry() {
593+
val telephonyManager: TelephonyManager = activity?.getSystemService(Context.TELEPHONY_SERVICE)
594+
as TelephonyManager
595+
val currentCountryCode = telephonyManager.networkCountryIso
596+
val countryCodes = resources.getStringArray(R.array.country_code_arrays)
597+
val countryIndex = countryCodes.indexOf(currentCountryCode.toUpperCase())
598+
if (countryIndex != -1) rootView.countryPicker.setSelection(countryIndex)
599+
}
581600
}

app/src/main/java/org/fossasia/openevent/general/auth/EditProfileFragment.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import android.content.Intent
77
import android.content.pm.PackageManager
88
import android.graphics.Bitmap
99
import android.graphics.BitmapFactory
10+
import android.net.Uri
1011
import android.os.Bundle
1112
import android.util.Base64
1213
import android.view.LayoutInflater
@@ -71,7 +72,7 @@ class EditProfileFragment : Fragment() {
7172
if (rootView.lastName.text.isBlank()) {
7273
rootView.lastName.setText(userLastName)
7374
}
74-
if (!imageUrl.isEmpty()) {
75+
if (!imageUrl.isEmpty() && !avatarUpdated) {
7576
val drawable = requireDrawable(requireContext(), R.drawable.ic_account_circle_grey)
7677
Picasso.get()
7778
.load(imageUrl)
@@ -80,6 +81,16 @@ class EditProfileFragment : Fragment() {
8081
.into(rootView.profilePhoto)
8182
}
8283
})
84+
profileViewModel.avatarPicked.observe(this, Observer {
85+
if (it != null) {
86+
Picasso.get()
87+
.load(Uri.parse(it))
88+
.placeholder(requireDrawable(requireContext(), R.drawable.ic_account_circle_grey))
89+
.transform(CircleTransform())
90+
.into(rootView.profilePhoto)
91+
this.avatarUpdated = true
92+
}
93+
})
8394
profileViewModel.fetchProfile()
8495

8596
editProfileViewModel.progress
@@ -136,6 +147,7 @@ class EditProfileFragment : Fragment() {
136147
.transform(CircleTransform())
137148
.into(rootView.profilePhoto)
138149
avatarUpdated = true
150+
profileViewModel.avatarPicked.value = imageUri.toString()
139151
}
140152
}
141153

app/src/main/java/org/fossasia/openevent/general/auth/ProfileViewModel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class ProfileViewModel(private val authService: AuthService) : ViewModel() {
1919
val user: LiveData<User> = mutableUser
2020
private val mutableError = SingleLiveEvent<String>()
2121
val error: LiveData<String> = mutableError
22+
val avatarPicked = MutableLiveData<String>()
2223

2324
fun isLoggedIn() = authService.isLoggedIn()
2425

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.fossasia.openevent.general.common
2+
3+
import androidx.recyclerview.widget.DiffUtil
4+
import org.fossasia.openevent.general.event.Event
5+
6+
/**
7+
* The DiffUtil ItemCallback class for the [Event] model class.
8+
* This enables proper diffing of items in Recycler Views using [DiffUtil]
9+
*/
10+
class EventsDiffCallback : DiffUtil.ItemCallback<Event>() {
11+
12+
override fun areItemsTheSame(oldItem: Event, newItem: Event): Boolean {
13+
return oldItem.id == newItem.id
14+
}
15+
16+
override fun areContentsTheSame(oldItem: Event, newItem: Event): Boolean {
17+
return oldItem == newItem
18+
}
19+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.fossasia.openevent.general.common
2+
3+
import org.fossasia.openevent.general.event.Event
4+
5+
/**
6+
* The callback interface for Event item clicks
7+
*/
8+
interface EventClickListener {
9+
/**
10+
* The function to be invoked when an event item is clicked
11+
*
12+
* @param eventID The ID of the clicked event
13+
*/
14+
fun onClick(eventID: Long)
15+
}
16+
17+
/**
18+
* The callback interface for Favorite FAB clicks
19+
*/
20+
interface FavoriteFabClickListener {
21+
/**
22+
* The function to be invoked when the fab is clicked
23+
*
24+
* @param event The event object for which the fab was clicked
25+
* @param itemPosition The position of the event object in the adapter
26+
*/
27+
fun onClick(event: Event, itemPosition: Int)
28+
}
29+
30+
/**
31+
* The callback interface for Share FAB clicks
32+
*/
33+
interface ShareFabClickListener {
34+
/**
35+
* The function to be invoked when the fab is clicked
36+
*
37+
* @param event The event object for which the fab was clicked
38+
*/
39+
fun onClick(event: Event)
40+
}

app/src/main/java/org/fossasia/openevent/general/di/Modules.kt

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.fossasia.openevent.general.di
22

33
import androidx.room.Room
4+
import com.facebook.stetho.okhttp3.StethoInterceptor
45
import com.fasterxml.jackson.databind.DeserializationFeature
56
import com.fasterxml.jackson.databind.ObjectMapper
67
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
@@ -33,11 +34,15 @@ import org.fossasia.openevent.general.event.Event
3334
import org.fossasia.openevent.general.event.EventApi
3435
import org.fossasia.openevent.general.event.EventDetailsViewModel
3536
import org.fossasia.openevent.general.event.EventId
37+
import org.fossasia.openevent.general.event.EventLayoutType
3638
import org.fossasia.openevent.general.event.EventService
39+
import org.fossasia.openevent.general.common.EventsDiffCallback
40+
import org.fossasia.openevent.general.event.EventsListAdapter
3741
import org.fossasia.openevent.general.event.EventsViewModel
3842
import org.fossasia.openevent.general.event.topic.EventTopic
3943
import org.fossasia.openevent.general.event.topic.EventTopicApi
4044
import org.fossasia.openevent.general.event.topic.SimilarEventsViewModel
45+
import org.fossasia.openevent.general.favorite.FavoriteEventsRecyclerAdapter
4146
import org.fossasia.openevent.general.favorite.FavoriteEventsViewModel
4247
import org.fossasia.openevent.general.order.Charge
4348
import org.fossasia.openevent.general.order.ConfirmOrder
@@ -164,40 +169,41 @@ val networkModule = module {
164169
val readTimeout = 15 // 15s
165170

166171
OkHttpClient().newBuilder()
167-
.connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
168-
.readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
169-
.addInterceptor(
170-
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
171-
)
172-
.addInterceptor(get())
173-
.build()
172+
.connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS)
173+
.readTimeout(readTimeout.toLong(), TimeUnit.SECONDS)
174+
.addInterceptor(
175+
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
176+
)
177+
.addInterceptor(get())
178+
.addNetworkInterceptor(StethoInterceptor())
179+
.build()
174180
}
175181

176182
single {
177183
val baseUrl = BuildConfig.DEFAULT_BASE_URL
178184
val objectMapper: ObjectMapper = get()
179185

180186
Retrofit.Builder()
181-
.client(get())
182-
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
183-
.addConverterFactory(JSONAPIConverterFactory(objectMapper, Event::class.java, User::class.java,
184-
SignUp::class.java, Ticket::class.java, SocialLink::class.java, EventId::class.java,
185-
EventTopic::class.java, Attendee::class.java, TicketId::class.java, Order::class.java,
186-
AttendeeId::class.java, Charge::class.java, Paypal::class.java, ConfirmOrder::class.java,
187-
CustomForm::class.java))
188-
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
189-
.baseUrl(baseUrl)
190-
.build()
187+
.client(get())
188+
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
189+
.addConverterFactory(JSONAPIConverterFactory(objectMapper, Event::class.java, User::class.java,
190+
SignUp::class.java, Ticket::class.java, SocialLink::class.java, EventId::class.java,
191+
EventTopic::class.java, Attendee::class.java, TicketId::class.java, Order::class.java,
192+
AttendeeId::class.java, Charge::class.java, Paypal::class.java, ConfirmOrder::class.java,
193+
CustomForm::class.java))
194+
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
195+
.baseUrl(baseUrl)
196+
.build()
191197
}
192198
}
193199

194200
val databaseModule = module {
195201

196202
single {
197203
Room.databaseBuilder(androidApplication(),
198-
OpenEventDatabase::class.java, "open_event_database")
199-
.fallbackToDestructiveMigration()
200-
.build()
204+
OpenEventDatabase::class.java, "open_event_database")
205+
.fallbackToDestructiveMigration()
206+
.build()
201207
}
202208

203209
factory {
@@ -235,3 +241,24 @@ val databaseModule = module {
235241
database.orderDao()
236242
}
237243
}
244+
245+
val fragmentsModule = module {
246+
247+
factory { EventsDiffCallback() }
248+
249+
scope(Scopes.EVENTS_FRAGMENT.toString()) {
250+
EventsListAdapter(EventLayoutType.EVENTS, get())
251+
}
252+
253+
scope(Scopes.SIMILAR_EVENTS_FRAGMENT.toString()) {
254+
EventsListAdapter(EventLayoutType.SIMILAR_EVENTS, get())
255+
}
256+
257+
scope(Scopes.FAVORITE_FRAGMENT.toString()) {
258+
FavoriteEventsRecyclerAdapter(get())
259+
}
260+
261+
scope(Scopes.SEARCH_RESULTS_FRAGMENT.toString()) {
262+
FavoriteEventsRecyclerAdapter(get())
263+
}
264+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.fossasia.openevent.general.di
2+
3+
/**
4+
* Enum class to collect all possible Fragment scopes for Koin DI
5+
* in one place. This list is expected to grow as Scopes are used in more
6+
* fragments.
7+
*/
8+
enum class Scopes {
9+
EVENTS_FRAGMENT,
10+
SIMILAR_EVENTS_FRAGMENT,
11+
FAVORITE_FRAGMENT,
12+
SEARCH_RESULTS_FRAGMENT
13+
}

0 commit comments

Comments
 (0)