Skip to content

Commit

Permalink
feat: mentorship relation list and detail screen (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
isabelcosta authored and r00pal committed Aug 14, 2018
1 parent 6fd4223 commit 878ef43
Show file tree
Hide file tree
Showing 24 changed files with 1,254 additions and 8 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<activity android:name=".view.activities.SignUpActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".view.activities.MainActivity" />
<activity android:name=".view.activities.RequestDetailActivity" />
<activity android:name=".view.activities.MemberProfileActivity" />
</application>

Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/org/systers/mentorship/remote/ApiManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.systers.mentorship.remote
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.systers.mentorship.remote.services.AuthService
import org.systers.mentorship.remote.services.RelationService
import org.systers.mentorship.remote.services.UserService
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
Expand All @@ -15,6 +16,7 @@ class ApiManager {

private lateinit var retrofit: Retrofit
private lateinit var authService: AuthService
private lateinit var relationService: RelationService
private lateinit var userService: UserService

init {
Expand All @@ -27,6 +29,7 @@ class ApiManager {

private fun initServices() {
authService = createService(AuthService::class.java)
relationService = createService(RelationService::class.java)
userService = createService(UserService::class.java)
}

Expand Down Expand Up @@ -54,6 +57,11 @@ class ApiManager {
*/
fun getAuthService(): AuthService = authService

/**
* @return a pointer to an initialised [RelationService]
*/
fun getMentorshipRelationService() = relationService

/**
* @return a pointer to an initialised [UserService]
*/
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/java/org/systers/mentorship/remote/Constants.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.systers.mentorship.remote

/**
* This [Enum] represents all the states of a Mentorship Relation.
* These values are the same used in the backend.
* PENDING - first applied state when a user sends a request
* ACCEPTED - when the receiving user accepts the relation, which will start at the time
* of acceptance
* REJECTED - when the receiving user rejects the relation, no longer available to be accepted
* CANCELLED - when any of the users of a current relation cancel a relation
* COMPLETED - when a current relation passes the end date it becomes completed,
* this happens automatically, does not require action from any user
*/
enum class MentorshipRelationState(val value: Int) {
PENDING(1),
ACCEPTED(2),
REJECTED(3),
CANCELLED(4),
COMPLETED(5)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.systers.mentorship.remote.datamanager

import io.reactivex.Observable
import org.systers.mentorship.remote.ApiManager
import org.systers.mentorship.remote.responses.CustomResponse
import org.systers.mentorship.remote.responses.MentorshipRelationResponse

/**
* This class represents the data manager related to Mentorship Relation API
*/
class RelationDataManager {

private val apiManager: ApiManager = ApiManager()

/**
* This will call a method of RelationService interface to fetch
* all mentorship requests and relations
* @return an Observable of a list of [MentorshipRelationResponse]
*/
fun getAllMentorshipRelationsAndRequests(): Observable<List<MentorshipRelationResponse>> {
return apiManager.getMentorshipRelationService().getAllMentorshipRelations()
}

/**
* This will call a method from RelationService interface to accept a mentorship request
* @param relationId id of the request being accepted
* @return an Observable of [CustomResponse]
*/
fun acceptMentorshipRelation(relationId: Int): Observable<CustomResponse> {
return apiManager.getMentorshipRelationService().acceptMentorshipRelation(relationId)
}

/**
* This will call a method from RelationService interface to reject a mentorship request
* @param relationId id of the request being rejected
* @return an Observable of [CustomResponse]
*/
fun rejectMentorshipRelation(relationId: Int): Observable<CustomResponse> {
return apiManager.getMentorshipRelationService().rejectMentorshipRelation(relationId)
}

/**
* This will call a method from RelationService interface to delete a mentorship request
* @param relationId id of the request being deleted
* @return an Observable of [CustomResponse]
*/
fun deleteMentorshipRelation(relationId: Int): Observable<CustomResponse> {
return apiManager.getMentorshipRelationService().deleteMentorshipRelation(relationId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.systers.mentorship.remote.responses

import android.os.Parcel
import android.os.Parcelable
import com.google.gson.annotations.SerializedName

/**
* This data class represents partial information of user of the system.
* This is used in APIs not directly related with Users, such as in responses
* related to MentorshipRelation
*
* @param id identifier of the mentorship relation
* @param actionUserId id of the user that sent the request for this mentorship relation
* @param sentByMe indication if the current user was the action user
* @param mentor user with mentor role in the relation
* @param mentee user with mentee role in the relation
* @param createdAtTimestamp date of creation unix timestamp
* @param acceptedAtTimestamp date of acceptance unix timestamp
* @param startAtTimestamp start date unix timestamp
* @param endAtTimestamp end date unix timestamp
* @param state state of the relation (@link to MentorshipRelationState)
* @param notes notes related to the mentorship relation
*/
data class MentorshipRelationResponse(
val id: Int,
@SerializedName("action_user_id") val actionUserId: Int,
@SerializedName("sent_by_me") val sentByMe: Boolean,
val mentor: RelationUserResponse,
val mentee: RelationUserResponse,
@SerializedName("creation_date") val createdAtTimestamp: Float,
@SerializedName("accept_date") val acceptedAtTimestamp: Float,
@SerializedName("start_date") val startAtTimestamp: Float,
@SerializedName("end_date") val endAtTimestamp: Float,
val state: Int,
val notes: String
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readInt(),
parcel.readByte() != 0.toByte(),
parcel.readParcelable(RelationUserResponse::class.java.classLoader),
parcel.readParcelable(RelationUserResponse::class.java.classLoader),
parcel.readFloat(),
parcel.readFloat(),
parcel.readFloat(),
parcel.readFloat(),
parcel.readInt(),
parcel.readString())

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeInt(actionUserId)
parcel.writeByte(if (sentByMe) 1 else 0)
parcel.writeParcelable(mentor, flags)
parcel.writeParcelable(mentee, flags)
parcel.writeFloat(createdAtTimestamp)
parcel.writeFloat(acceptedAtTimestamp)
parcel.writeFloat(startAtTimestamp)
parcel.writeFloat(endAtTimestamp)
parcel.writeInt(state)
parcel.writeString(notes)
}

override fun describeContents(): Int {
return 0
}

/**
* Class responsible for generating instances of this Parcelable class from a Parcel
*/
companion object CREATOR : Parcelable.Creator<MentorshipRelationResponse> {
override fun createFromParcel(parcel: Parcel): MentorshipRelationResponse {
return MentorshipRelationResponse(parcel)
}

override fun newArray(size: Int): Array<MentorshipRelationResponse?> {
return arrayOfNulls(size)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.systers.mentorship.remote.responses

import android.os.Parcel
import android.os.Parcelable

/**
* This data class represents partial information of user of the system.
* This is used in APIs not directly related with Users, such as in responses
* related to MentorshipRelation
*
* @param id identifier of the user
* @param name name of the user
*/
data class RelationUserResponse (val id: Int, val name: String) : Parcelable {

constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString())

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(name)
}

override fun describeContents(): Int {
return 0
}

/**
* Class responsible for generating instances of this Parcelable class from a Parcel
*/
companion object CREATOR : Parcelable.Creator<RelationUserResponse> {
override fun createFromParcel(parcel: Parcel): RelationUserResponse {
return RelationUserResponse(parcel)
}

override fun newArray(size: Int): Array<RelationUserResponse?> {
return arrayOfNulls(size)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.systers.mentorship.remote.services

import io.reactivex.Observable
import retrofit2.http.GET
import retrofit2.http.PUT
import retrofit2.http.Path
import org.systers.mentorship.remote.responses.CustomResponse
import org.systers.mentorship.remote.responses.MentorshipRelationResponse
import retrofit2.http.DELETE

/**
* This interface describes the methods related to Mentorship Relation REST API
*/
interface RelationService {

/**
* This function returns all mentorship requests and relations of the current user
* @return an observable instance of a list of [MentorshipRelationResponse]s
*/
@GET("mentorship_relations")
fun getAllMentorshipRelations(): Observable<List<MentorshipRelationResponse>>

/**
* This function performs the acceptance of a mentorship request
* @return an observable instance of [CustomResponse] with a proper error or success message
*/
@PUT("mentorship_relation/{relation_id}/accept")
fun acceptMentorshipRelation(@Path("relation_id") relationId: Int): Observable<CustomResponse>

/**
* This function performs the rejection of a mentorship request
* @return an observable instance of [CustomResponse] with a proper error or success message
*/
@PUT("mentorship_relation/{relation_id}/reject")
fun rejectMentorshipRelation(@Path("relation_id") relationId: Int): Observable<CustomResponse>

/**
* This function performs the deletion of a mentorship request
* @return an observable instance of [CustomResponse] with a proper error or success message
*/
@DELETE("mentorship_relation/{relation_id}")
fun deleteMentorshipRelation(@Path("relation_id") relationId: Int): Observable<CustomResponse>
}
28 changes: 28 additions & 0 deletions app/src/main/java/org/systers/mentorship/utils/DateAndTimeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.systers.mentorship.utils

import java.text.SimpleDateFormat
import java.util.*

const val DATE_FORMAT = "dd MMM yyyy"
const val EXTENDED_DATE_FORMAT = "dd MMMM yyyy"
const val MILLISECONDS_FACTOR = 1000L

/**
* Get [Date] from [unixTimestamp] in [String] format
* @param unixTimestamp time in Unix timestamp format, in seconds
* @param format date string format to use
* @return date in string format
*/
fun convertUnixTimestampIntoStr(unixTimestamp: Float, format: String) : String {

val date = Date(getUnixTimestampInMilliseconds(unixTimestamp))
val sdf = SimpleDateFormat(format)
return sdf.format(date)
}

/**
* Convert Unix timestamp seconds to milliseconds [Long] format
* @param unixTimestamp time in Unix timestamp format, in seconds
* @return unix timestamp in milliseconds
*/
fun getUnixTimestampInMilliseconds(unixTimestamp: Float) : Long = (unixTimestamp * MILLISECONDS_FACTOR).toLong()
14 changes: 14 additions & 0 deletions app/src/main/java/org/systers/mentorship/utils/TextViewUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,17 @@ fun setTextViewStartingWithBoldSpan(textView: TextView, spanText: String, text:
sb.setSpan(style, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
textView.text = sb
}

/**
* @param mainText string containing [boldWord]
* @param boldWord string that should have bold text style
* @return [SpannableStringBuilder] with [boldWord] within [mainText] with Bold text style
*/
fun getTextWithBoldWord(mainText: String, boldWord: String) : SpannableStringBuilder {
val sb = SpannableStringBuilder(mainText)
val start = mainText.indexOf(boldWord)
val end = start + boldWord.length
val style = StyleSpan(Typeface.BOLD)
sb.setSpan(style, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
return sb
}
Loading

0 comments on commit 878ef43

Please sign in to comment.