Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profile to mvvm #83

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import java.util.Map;

import io.reactivex.Flowable;
import io.reactivex.Observable;

interface ContactsDataSource {

Flowable<Map.Entry<String, User>> getContactsForUser(String userId);
Observable<Map.Entry<String, User>> getContactsForUser(String userId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.bookyrself.bookyrself.data.serverModels.User.User
import com.bookyrself.bookyrself.services.FirebaseService
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.util.*
Expand All @@ -24,13 +24,13 @@ class ContactsRepoRxJava : ContactsDataSource {
cacheIsDirty = true
}

if (FirebaseAuth.getInstance().uid != null) {
FirebaseAuth.getInstance().uid?.let {
this.db = FirebaseDatabase.getInstance().reference
.child("users")
.child(FirebaseAuth.getInstance().uid!!)
.child("contacts")
.child("users")
.child(it)
.child("contacts")

this.db!!.addChildEventListener(object : ChildEventListener {
this.db?.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(dataSnapshot: DataSnapshot, s: String?) {
cacheIsDirty = true
Log.e("Contacts Repo: ", "Child added")
Expand Down Expand Up @@ -62,33 +62,34 @@ class ContactsRepoRxJava : ContactsDataSource {
/**
* Methods
*/
override fun getContactsForUser(userId: String): Flowable<Map.Entry<String, User>> {
override fun getContactsForUser(userId: String): Observable<Map.Entry<String, User>> {

if (cacheIsDirty!!) {
// Cache is dirty, get from network
return FirebaseService.instance
.getUserContacts(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map { it.entries }
.firstOrError()
.toFlowable()
.flatMapIterable { entries -> entries }
.flatMap { entry ->
FirebaseService.instance
.getUserDetails(entry.key)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map {
contactsMap[entry.key] = it
cacheIsDirty = false
AbstractMap.SimpleEntry<String, User>(entry.key, it)
}
}
.getUserContacts(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map { it.entries }
.firstOrError()
.flattenAsObservable { it }
.flatMap { entry ->
FirebaseService.instance
// Get each contacts user info
.getUserDetails(entry.key)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map {
// add the contact to our user's contacts repository
contactsMap[entry.key] = it
cacheIsDirty = false
AbstractMap.SimpleEntry<String, User>(entry.key, it)
}
}
} else {
// Cache is clean, get local copy
return Flowable.fromIterable(contactsMap.entries)
.map { AbstractMap.SimpleEntry<String, User>(it.key, it.value) }
return Observable.fromIterable(contactsMap.entries)
.map { AbstractMap.SimpleEntry<String, User>(it.key, it.value) }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class EventsRepository private constructor(context: Context) {
.child(FirebaseAuth.getInstance().uid!!)
.child("events")

this.db!!.addChildEventListener(object : ChildEventListener {
this.db?.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(dataSnapshot: DataSnapshot, s: String?) {
cacheIsDirty = true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,66 @@
package com.bookyrself.bookyrself.data.profile

import android.content.Context
import com.bookyrself.bookyrself.data.SingletonHolder
import com.bookyrself.bookyrself.data.profile.ProfileRepoResponse.Success
import com.bookyrself.bookyrself.data.profile.ProfileRepoResponse.Failure
import com.bookyrself.bookyrself.data.serverModels.User.User
import com.bookyrself.bookyrself.services.FirebaseService
import com.bookyrself.bookyrself.services.FirebaseServiceCoroutines
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers

class ProfileRepo {
class ProfileRepo private constructor(context: Context) {

private var db: DatabaseReference? = null
private var cacheIsDirty: Boolean = true
private var user: User? = null

init {
if (FirebaseAuth.getInstance().uid != null) {

val userId = FirebaseAuth.getInstance().uid
companion object : SingletonHolder<ProfileRepo, Context>(::ProfileRepo)

init {
FirebaseAuth.getInstance().uid?.let { userId ->
this.db = FirebaseDatabase.getInstance().reference
.child("users")
.child(userId!!)
.child("users")
.child(userId)

this.db!!.addChildEventListener(object : ChildEventListener {
this.db?.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(dataSnapshot: DataSnapshot, s: String?) {
// Update repos observable to fetch new data
getProfileInfo(userId)
cacheIsDirty = true
}

override fun onChildChanged(dataSnapshot: DataSnapshot, s: String?) {
getProfileInfo(userId)
cacheIsDirty = true
}

override fun onChildRemoved(dataSnapshot: DataSnapshot) {
getProfileInfo(userId)
cacheIsDirty = true
}

override fun onChildMoved(dataSnapshot: DataSnapshot, s: String?) {
getProfileInfo(userId)
cacheIsDirty = true
}

override fun onCancelled(databaseError: DatabaseError) {
getProfileInfo(userId)
cacheIsDirty = true
}
})
}
}


fun getProfileInfo(userId: String): Flowable<User> {
return FirebaseService.instance
.getUserDetails(userId)
.firstOrError()
.toFlowable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
suspend fun getProfileInfo(userId: String): ProfileRepoResponse {
return if (cacheIsDirty) {
val profileResponse = FirebaseServiceCoroutines.instance.getUserDetails(userId)
if (profileResponse.isSuccessful) {
user = profileResponse.body()
Success(user = profileResponse.body())
} else {
Failure(errorMessage = profileResponse.message())
}
} else {
Success(user)
}
}

suspend fun updateProfileInfo(userId: String, user: User): ProfileRepoResponse {
Expand All @@ -65,9 +71,10 @@ class ProfileRepo {
ProfileRepoResponse.Failure(response.message())
}
}
}

sealed class ProfileRepoResponse {
class Success(val user: User?) : ProfileRepoResponse()
class Failure(val errorMessage: String) : ProfileRepoResponse()
}

sealed class ProfileRepoResponse {
class Success(val user: User?) : ProfileRepoResponse()
class Failure(val errorMessage: String) : ProfileRepoResponse()
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.bookyrself.bookyrself.data.serverModels.EventDetail.Host
import com.bookyrself.bookyrself.data.serverModels.User.EventInviteInfo
import com.bookyrself.bookyrself.data.serverModels.User.User
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.Single
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
Expand Down Expand Up @@ -38,7 +40,7 @@ object FirebaseService {
interface FirebaseApi {

@GET("/users/{id}.json")
fun getUserDetails(@Path("id") userId: String): Flowable<User>
fun getUserDetails(@Path("id") userId: String): Observable<User>

@GET("/users/{id}/events.json")
fun getUsersEventInvites(@Path("id") userId: String): Flowable<HashMap<String, EventInviteInfo>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ class EventsFragmentViewModel(application: Application) : BaseViewModel(applicat
var eventDetails = MutableLiveData<HashMap<EventDetail, String>>()

override fun load() {
val userId = FirebaseAuth.getInstance().uid
if (userId != null) {
FirebaseAuth.getInstance().uid?.let {
CoroutineScope(Dispatchers.IO).launch {
when (val response =
EventsRepository
.getInstance(getApplication())
.getAllEventsForUser(userId)) {
.getAllEventsForUser(it)) {
is Success -> {
eventDetails.postValue(response.events)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,43 @@ package com.bookyrself.bookyrself.viewmodels

import android.app.Application
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.bookyrself.bookyrself.data.profile.ProfileRepo
import com.bookyrself.bookyrself.data.profile.ProfileRepoResponse.Failure
import com.bookyrself.bookyrself.data.profile.ProfileRepoResponse.Success
import com.bookyrself.bookyrself.data.serverModels.EventDetail.EventDetail
import com.bookyrself.bookyrself.data.serverModels.User.User
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch


class ProfileFragmentViewModel(application: Application) : BaseViewModel(application) {

var user = MutableLiveData<User>()
var events = MutableLiveData<HashMap<EventDetail, String>>()

override fun load() {
FirebaseAuth.getInstance().uid?.let {
CoroutineScope(Dispatchers.IO).launch {
when (val response = ProfileRepo.getInstance(getApplication()).getProfileInfo(it)) {
is Success -> {
user.postValue(response.user)
}
is Failure -> {
errorMessage.postValue(response.errorMessage)
}
}
}
}
}

class ProfileFragmentViewModelFactory(private val application: Application) :
ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ProfileFragmentViewModel(application) as T
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
private const val PROFILE_FRAGMENT_INDEX = 4

private var CONTACTS_REPO: ContactsRepoRxJava? = null
private var PROFILE_REPO: ProfileRepo? = null

//TODO: Fix all these !! and find a better way to serve up these repos
val contactsRepo: ContactsRepoRxJava
Expand All @@ -79,13 +78,5 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
}
return CONTACTS_REPO!!
}

val profileRepo: ProfileRepo
get() {
if (PROFILE_REPO == null) {
PROFILE_REPO = ProfileRepo()
}
return PROFILE_REPO!!
}
}
}
Loading