Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dependencies {
implementation 'androidx.credentials:credentials-play-services-auth:1.6.0'
implementation 'com.google.android.libraries.identity.googleid:googleid:1.2.0'
implementation 'com.squareup.okhttp3:okhttp:5.5.0'
implementation 'com.squareup.okhttp3:okhttp-coroutines:5.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0'
implementation 'com.google.code.gson:gson:2.14.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.cornellappdev.coursegrab

import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand All @@ -14,17 +15,10 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.cornellappdev.coursegrab.databinding.ActivityCourseDetailsBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.models.SearchResult
import com.cornellappdev.coursegrab.networking.Endpoint
import com.cornellappdev.coursegrab.networking.Request
import com.cornellappdev.coursegrab.networking.addTracking
import com.cornellappdev.coursegrab.networking.removeTracking
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import com.cornellappdev.coursegrab.networking.CourseGrabRepository
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class CourseDetailsActivity : AppCompatActivity() {
private lateinit var binding: ActivityCourseDetailsBinding
Expand All @@ -33,8 +27,8 @@ class CourseDetailsActivity : AppCompatActivity() {
private lateinit var sectionsViewAdapter: RecyclerView.Adapter<*>
private lateinit var sectionsViewManager: RecyclerView.LayoutManager

private val preferencesHelper: PreferencesHelper by lazy {
PreferencesHelper(this)
private val repository: CourseGrabRepository by lazy {
CourseGrabRepository(PreferencesHelper(this))
}

override fun onCreate(savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -63,45 +57,28 @@ class CourseDetailsActivity : AppCompatActivity() {
}

fun addCourse(courseId: Int, context: Context) {
val addTracking = Endpoint.addTracking(preferencesHelper.sessionToken.toString(), courseId)

lifecycleScope.launch {
val typeToken = object : TypeToken<ApiResponse<Course>>() {}.type
val response = withContext(Dispatchers.IO) {
Request.makeRequest<ApiResponse<Course>>(
addTracking.okHttpRequest(),
typeToken
)
}

if (!response!!.success)
repository.addTracking(courseId).onFailure { error ->
Log.e(TAG, "Failed to track course $courseId", error)
Toast.makeText(
context,
response.data.errors!![0],
error.message ?: "Couldn't track that course.",
Toast.LENGTH_SHORT
).show()
}
}
}

fun removeCourse(courseId: Int, context: Context) {
val removeTracking =
Endpoint.removeTracking(preferencesHelper.sessionToken.toString(), courseId)

lifecycleScope.launch {
val typeToken = object : TypeToken<ApiResponse<Course>>() {}.type
val response = withContext(Dispatchers.IO) {
Request.makeRequest<ApiResponse<Course>>(
removeTracking.okHttpRequest(),
typeToken
)
}

if (!response!!.success)
repository.removeTracking(courseId).onFailure { error ->
Log.e(TAG, "Failed to untrack course $courseId", error)
Toast.makeText(
context,
response.data.errors!![0],
error.message ?: "Couldn't remove that course.",
Toast.LENGTH_SHORT
).show()
}
}
}

Expand Down Expand Up @@ -176,4 +153,8 @@ class CourseDetailsActivity : AppCompatActivity() {
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = availableCourses.size
}

companion object {
private const val TAG = "CourseDetailsActivity"
}
}
99 changes: 19 additions & 80 deletions app/src/main/java/com/cornellappdev/coursegrab/LoginActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,15 @@ import androidx.credentials.exceptions.GetCredentialException
import androidx.credentials.exceptions.NoCredentialException
import androidx.lifecycle.lifecycleScope
import com.cornellappdev.coursegrab.databinding.ActivityLoginBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.models.UserSession
import com.cornellappdev.coursegrab.networking.Endpoint
import com.cornellappdev.coursegrab.networking.Request
import com.cornellappdev.coursegrab.networking.deviceToken
import com.cornellappdev.coursegrab.networking.initializeSession
import com.cornellappdev.coursegrab.networking.setNotification
import com.cornellappdev.coursegrab.networking.updateSession
import com.cornellappdev.coursegrab.networking.CourseGrabRepository
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
Expand All @@ -52,6 +41,10 @@ class LoginActivity : AppCompatActivity() {
PreferencesHelper(this)
}

private val repository: CourseGrabRepository by lazy {
CourseGrabRepository(preferencesHelper)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
Expand All @@ -63,25 +56,10 @@ class LoginActivity : AppCompatActivity() {
} else {
val updateToken = preferencesHelper.updateToken
if (!updateToken.isNullOrBlank()) {
val updateSession = Endpoint.updateSession(updateToken)

lifecycleScope.launch {
val userSession = try {
val typeToken = object : TypeToken<ApiResponse<UserSession>>() {}.type
withContext(Dispatchers.IO) {
Request.makeRequest<ApiResponse<UserSession>>(
updateSession.okHttpRequest(),
typeToken
)
}?.data
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Log.d(TAG, "Could not resume previous session", e)
null
}

if (userSession != null) verifySession(userSession)
repository.updateSession(updateToken)
.onSuccess { verifySession(it) }
.onFailure { Log.d(TAG, "Could not resume previous session", it) }
}
}
}
Expand Down Expand Up @@ -191,30 +169,13 @@ class LoginActivity : AppCompatActivity() {
return
}

val initializeSession = Endpoint.initializeSession(googleCredential.idToken, null)

lifecycleScope.launch {
val userSession = try {
val typeToken = object : TypeToken<ApiResponse<UserSession>>() {}.type
withContext(Dispatchers.IO) {
Request.makeRequest<ApiResponse<UserSession>>(
initializeSession.okHttpRequest(),
typeToken
)
}?.data
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Log.e(TAG, "Failed to initialize session", e)
null
}

if (userSession == null) {
showLoginError("Sign-in failed. Please try again.")
return@launch
}

verifySession(userSession)
repository.initializeSession(googleCredential.idToken, null)
.onSuccess { verifySession(it) }
.onFailure { error ->
Log.e(TAG, "Failed to initialize session", error)
showLoginError("Sign-in failed. Please try again.")
}
}
}

Expand All @@ -238,22 +199,10 @@ class LoginActivity : AppCompatActivity() {
}

private fun sendRegistrationToServer(token: String?) {
val sendDeviceToken = Endpoint.deviceToken(
preferencesHelper.sessionToken.toString(),
token.toString()
)

lifecycleScope.launch {
val typeToken = object : TypeToken<ApiResponse<Course>>() {}.type
val response = withContext(Dispatchers.IO) {
Request.makeRequest<ApiResponse<Course>>(
sendDeviceToken.okHttpRequest(),
typeToken
)
}

if (response!!.success)
Log.d("NotificationService", "sendRegistrationTokenToServer($token)")
repository.sendDeviceToken(token.toString())
.onSuccess { Log.d(TAG, "sendRegistrationTokenToServer($token)") }
.onFailure { Log.w(TAG, "Failed to register device token", it) }
}
}

Expand All @@ -279,19 +228,9 @@ class LoginActivity : AppCompatActivity() {
}

private fun setNotificationsStatus(enabled: Boolean) {
val setNotifs = Endpoint.setNotification(
accessToken = preferencesHelper.sessionToken.toString(),
notifSetting = if (enabled) "ANDROID" else "NONE"
)

lifecycleScope.launch {
val typeToken = object : TypeToken<ApiResponse<Course>>() {}.type
withContext(Dispatchers.IO) {
Request.makeRequest<ApiResponse<Course>>(
setNotifs.okHttpRequest(),
typeToken
)
}
repository.setNotifications(enabled)
.onFailure { Log.w(TAG, "Failed to update notifications", it) }
}
}

Expand Down
Loading