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

Prepare for adding custom workout #27

Merged
merged 1 commit into from
Jun 9, 2024
Merged
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
6 changes: 6 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ dependencies {
// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
// Paging
implementation("androidx.paging:paging-runtime:3.1.1")

// LiveData and ViewModel
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
Expand All @@ -63,6 +67,8 @@ dependencies {
implementation("com.tbuonomo:dotsindicator:5.0")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.activity:activity:1.9.0")
// Image fetch
implementation("com.github.bumptech.glide:glide:4.16.0")


testImplementation("junit:junit:4.13.2")
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/com/modarb/android/network/ApiService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.modarb.android.network
import com.modarb.android.network.models.BaseResponse
import com.modarb.android.ui.home.ui.home.domain.models.HomePageResponse
import com.modarb.android.ui.home.ui.plan.domain.models.PlanPageResponse
import com.modarb.android.ui.home.ui.plan.domain.models.allExercises.ExercisesResponse
import com.modarb.android.ui.home.ui.plan.domain.models.customworkout.CustomWorkoutResponse
import com.modarb.android.ui.onboarding.models.LoginResponse
import com.modarb.android.ui.onboarding.models.RequestModels.LoginRequest
Expand All @@ -14,6 +15,7 @@ import retrofit2.http.Header
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query

interface ApiService {
@POST("/api/v1/user/auth/login")
Expand Down Expand Up @@ -55,5 +57,22 @@ interface ApiService {
): Response<CustomWorkoutResponse>


// Exercises Selection APIs
@GET("api/v1/user/exercises/")
suspend fun getExercises(
@Header("Authorization") token: String,
@Query("filterName") filter: String,
@Query("skip") skip: Int,
@Query("limit") limit: Int
): Response<ExercisesResponse>

@GET("api/v1/user/exercises/search")
suspend fun getExercisesSearch(
@Header("Authorization") token: String,
@Query("searchTerm") search: String,
@Query("filter") filter: String
): Response<ExercisesResponse>


}

23 changes: 18 additions & 5 deletions app/src/main/java/com/modarb/android/network/RetrofitService.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.modarb.android.network

import com.google.gson.Gson
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory


object RetrofitService {

private var BASE_URL = "http://10.0.2.2:4000/"
private var BASE_URL = "https://moahmedwafy-modarb-be.hf.space/"
inline fun <reified T> handleRequest(
response: Response<T>, onSuccess: (T) -> Unit, onError: (T?) -> Unit
) {
Expand Down Expand Up @@ -39,11 +42,21 @@ object RetrofitService {
}

fun createService(): ApiService {
if (!NetworkHelper.isEmulator()) {
BASE_URL = "http://192.168.1.9:4000/"
}
// if (!NetworkHelper.isEmulator()) {
// BASE_URL = "http://192.168.1.9:4000/"
// }

val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)


// Create an OkHttpClient and attach the logging interceptor
val client: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(logging)
.build()

try {
return Retrofit.Builder().baseUrl(BASE_URL)
return Retrofit.Builder().baseUrl(BASE_URL).client(client)
.addConverterFactory(GsonConverterFactory.create()).build()
.create(ApiService::class.java)
} catch (e: Exception) {
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/java/com/modarb/android/ui/helpers/ViewUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.modarb.android.ui.helpers

import android.content.Context
import android.widget.ImageView
import com.bumptech.glide.Glide

object ViewUtils {


fun loadImage(context: Context, imageUrl: String, imageView: ImageView) {
Glide.with(context).asBitmap().load(imageUrl).into(imageView)
}


}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.modarb.android.ui.home.helpers
package com.modarb.android.ui.helpers

import com.modarb.android.ui.home.ui.plan.domain.models.Day
import com.modarb.android.ui.home.ui.plan.domain.models.Exercise
import com.modarb.android.ui.home.ui.plan.domain.models.Week
import com.modarb.android.ui.home.ui.plan.domain.models.allExercises.Data

object WorkoutData {

Expand All @@ -12,7 +13,7 @@ object WorkoutData {
lateinit var weekList: List<Week>
lateinit var selectedExercise: Exercise
var selectedExerciseNumber: Int = 1

var selectedCustomExercisesList: MutableList<Data> = mutableListOf()

fun getWeekDaysCount(): Int {
return weekList[currentWeekPosition].days.size
Expand Down Expand Up @@ -66,6 +67,28 @@ object WorkoutData {
}


fun getBodyParts(): Array<String> {
return arrayOf(
"All",
"waist",
"upper legs",
"upper arms",
"lower legs",
"chest",
"lower arms",
"back",
"neck",
"shoulders",
"cardio"
)
}

fun getSelectedCustomExercises(): List<Data> {
return selectedCustomExercisesList
}



// TODO handle getting reps after fixing the api
// fun getTotalExerciseReps(exercise: List<com.modarb.android.ui.home.ui.plan.domain.models.customworkout.Exercise>): String {
// var totalReps = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import com.modarb.android.R
import com.modarb.android.databinding.FragmentHomeBinding
import com.modarb.android.network.ApiResult
import com.modarb.android.network.NetworkHelper
import com.modarb.android.ui.helpers.WorkoutData
import com.modarb.android.ui.home.HomeActivity
import com.modarb.android.ui.home.helpers.WorkoutData
import com.modarb.android.ui.home.ui.home.domain.models.HomePageResponse
import com.modarb.android.ui.home.ui.home.presentation.HomeViewModel
import com.modarb.android.ui.home.ui.plan.domain.models.PlanPageResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.modarb.android.ui.home.ui.plan

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.modarb.android.network.ApiService
import com.modarb.android.ui.home.ui.plan.domain.models.allExercises.Data

class ExercisesPagingSource(
private val apiService: ApiService,
private val token: String,
private val filter: String,
) : PagingSource<Int, Data>() {

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Data> {
val page = params.key ?: 0
try {
val response = apiService.getExercises(token, filter, page, params.loadSize)
return LoadResult.Page(
data = response.body()!!.data,
prevKey = if (page == 0) null else page - 1,
nextKey = if (response.body()!!.data.isEmpty()) null else page + 1
)
} catch (e: Exception) {
return LoadResult.Error(e)
}
}


override fun getRefreshKey(state: PagingState<Int, Data>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.modarb.android.ui.home.ui.plan

interface LoadingStateListener {
fun onLoadingStarted()
fun onLoadingFinished()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.modarb.android.databinding.ItemCustomworkoutTemplateBinding
import com.modarb.android.network.NetworkHelper
import com.modarb.android.ui.home.helpers.WorkoutData
import com.modarb.android.ui.helpers.WorkoutData
import com.modarb.android.ui.home.ui.plan.domain.models.customworkout.Data

class CustomWorkoutTemplateAdapter(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,62 +1,107 @@
package com.modarb.android.ui.home.ui.plan.adapters

import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import androidx.paging.PagingData
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.modarb.android.databinding.ItemExerciseSelectionDetailsBinding
import com.modarb.android.ui.workout.domain.models.WorkoutModel
import com.modarb.android.ui.home.ui.plan.domain.models.allExercises.Data

class ExercisesAddAdapter(private val itemList: List<WorkoutModel>) :
RecyclerView.Adapter<ExercisesAddAdapter.ViewHolder>() {
class ExercisesAddAdapter(private var context: Context, private val isAdd: Boolean) :
PagingDataAdapter<Data, ExercisesAddAdapter.ViewHolder>(DIFF_CALLBACK) {

private val selectedItems = mutableListOf<Int>()
private var selectedItems: HashMap<String, Data> = HashMap()

inner class ViewHolder(private val binding: ItemExerciseSelectionDetailsBinding) :
RecyclerView.ViewHolder(binding.root) {

fun bind(item: WorkoutModel) {
val isSelected = selectedItems.contains(item.id)
binding.root.isActivated = isSelected
binding.overlay.visibility = if (isSelected) ViewGroup.VISIBLE else ViewGroup.INVISIBLE
binding.checkMark.visibility =
if (isSelected) ViewGroup.VISIBLE else ViewGroup.INVISIBLE
fun bind(item: Data?) {
item?.let { data ->
// TODO uncomment this
//ViewUtils.loadImage(context,data.coverImage,binding.exerciseImage)

binding.exerciseTitle.text = data.name
binding.exerciseDesc.text = data.benefits

if (isAdd) {
val isSelected = selectedItems.contains(data.id)
binding.root.isActivated = isSelected
binding.overlay.visibility =
if (isSelected) ViewGroup.VISIBLE else ViewGroup.INVISIBLE
binding.checkMark.visibility =
if (isSelected) ViewGroup.VISIBLE else ViewGroup.INVISIBLE

binding.root.setOnClickListener {
toggleSelection(data.id, adapterPosition)
}
}

binding.root.setOnClickListener {
toggleSelection(item.id, adapterPosition)
Log.d("selected", getSelectedItems().toString())
}
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemExerciseSelectionDetailsBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(binding)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = itemList[position]
holder.bind(item)
holder.bind(getItem(position))
}

override fun getItemCount(): Int {
return itemList.size
}

private fun toggleSelection(itemId: Int, position: Int) {
private fun toggleSelection(itemId: String, position: Int) {
if (selectedItems.contains(itemId)) {
selectedItems.remove(itemId)

} else {
selectedItems.add(itemId)
selectedItems[itemId] = getItem(position)!!
}
getSelectedItems()
notifyItemChanged(position)
}

fun getSelectedItems(): List<Int> {
return selectedItems.toList()
private fun getSelectedItems() {
Log.d("selectedItems", selectedItems.toString())
}

fun updateData(lifecycleOwner: LifecycleOwner, newData: List<Data>) {
submitData(lifecycleOwner.lifecycle, PagingData.from(newData))
}

fun clearData(lifecycleOwner: LifecycleOwner) {
submitData(lifecycleOwner.lifecycle, PagingData.empty())
}

fun clearSelectedData() {
selectedItems.clear()
notifyDataSetChanged()
}

fun getSelectedData(): List<Data> {
val selectedDataList = mutableListOf<Data>()

for ((_, value) in selectedItems) {
selectedDataList.add(value)
}

return selectedDataList
}


companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Data>() {
override fun areItemsTheSame(oldItem: Data, newItem: Data): Boolean {
return oldItem.id == newItem.id
}

override fun areContentsTheSame(oldItem: Data, newItem: Data): Boolean {
return oldItem == newItem
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.modarb.android.R
import com.modarb.android.databinding.CustomWorkoutViewBinding
import com.modarb.android.databinding.MyPlanViewBinding
import com.modarb.android.ui.home.helpers.WorkoutData
import com.modarb.android.ui.helpers.WorkoutData
import com.modarb.android.ui.home.ui.plan.domain.models.Data
import com.modarb.android.ui.home.ui.plan.domain.models.PlanPageResponse
import com.modarb.android.ui.home.ui.plan.domain.models.customworkout.CustomWorkoutResponse
Expand Down
Loading
Loading