Skip to content

Commit

Permalink
Merge pull request #87 from CashAdv/feature/76-edit-user-profile
Browse files Browse the repository at this point in the history
Feature/76 edit user profile
  • Loading branch information
artwist-polyakov authored May 20, 2024
2 parents b73a9e7 + 17f1162 commit 55dcc83
Show file tree
Hide file tree
Showing 59 changed files with 2,080 additions and 20 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ dependencies {

// Glide
implementation(libs.glide)
annotationProcessor(libs.compiler)
implementation(libs.glide.okhttp3)
kapt(libs.glide.compiler)

// Timber
implementation(libs.timber)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package app.cashadvisor.analytics.presentation.ui

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import app.cashadvisor.R
import app.cashadvisor.databinding.FragmentAnalyticsBinding
Expand Down Expand Up @@ -33,6 +33,10 @@ class AnalyticsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.profileHeader.setOnClickListener {
findNavController().navigate(R.id.action_analyticsFragment_to_profileSettingsFragment)
}

binding.btnAddBank.setOnClickListener {
findNavController().navigate(R.id.action_analyticsFragment_to_addBankSelectionFragment)
}
Expand All @@ -59,7 +63,7 @@ class AnalyticsFragment : Fragment() {
}

rbIncome.isChecked && rbFact.isChecked -> {
findNavController().navigate(addIncome)
findNavController().navigate(addIncome)
}

rbExpense.isChecked && rbPlan.isChecked -> {
Expand All @@ -71,7 +75,7 @@ class AnalyticsFragment : Fragment() {
}

rbSaving.isChecked && rbPlan.isChecked -> {
findNavController().navigate(planSaving)
findNavController().navigate(planSaving)
}

rbSaving.isChecked && rbFact.isChecked -> {
Expand All @@ -83,8 +87,6 @@ class AnalyticsFragment : Fragment() {
}




}

override fun onDestroyView() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import app.cashadvisor.BuildConfig
import app.cashadvisor.common.data.ErrorInterceptor
import app.cashadvisor.common.data.api.NetworkConnectionProvider
import app.cashadvisor.common.data.impl.NetworkConnectionProviderImpl
import app.cashadvisor.profile.presentation.ui.UnsafeOkHttpGlideModule
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import dagger.Module
import dagger.Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import app.cashadvisor.common.utill.exceptions.LoginException
import app.cashadvisor.common.utill.exceptions.NetworkException
import app.cashadvisor.common.utill.exceptions.RegisterException
import app.cashadvisor.common.utill.extensions.logNetworkError
import app.cashadvisor.profile.data.mapper.UserProfileException
import java.net.ConnectException

abstract class BaseExceptionToErrorMapper {
Expand All @@ -15,7 +16,7 @@ abstract class BaseExceptionToErrorMapper {

fun handleException(exception: Exception): ErrorEntity {
return when (exception) {
is ConnectException, is NetworkException, is LoginException.NoConnection, is RegisterException.NoConnection -> {
is ConnectException, is NetworkException, is LoginException.NoConnection, is RegisterException.NoConnection, is UserProfileException.NoConnection -> {
logNetworkError(exception.message)
handleNetworkError(exception)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ sealed class ErrorEntity(open val message: String) {
RegisterConfirmationWithCode(message)
}

sealed class Profile(override val message: String) : ErrorEntity(message) {
data class InvalidContent(override val message: String) : Profile(message)
data class UserNotAuthorized(override val message: String) : Profile(message)
data class FailedToGetData(override val message: String) :
Profile(message)

data class FailedToSaveData(override val message: String) :
Profile(message)

data class EmptyProfile(override val message: String = BLANC_ERROR) : Profile(message)
}

companion object {
const val BLANC_ERROR = ""
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package app.cashadvisor.profile.data.api

import app.cashadvisor.profile.data.dto.request.UpdateUserNameRequest
import app.cashadvisor.profile.data.dto.response.ConfirmUpdateNameResponse
import app.cashadvisor.profile.data.dto.response.ConfirmUpdatePicResponse
import app.cashadvisor.profile.data.dto.response.ProfileInfoResponse
import okhttp3.MultipartBody
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Multipart
import retrofit2.http.PUT
import retrofit2.http.Part

interface ProfileInfoApiService {

@GET("profile/info/get")
suspend fun getUserInfo(
@Header("Authorization") accessToken: String
): ProfileInfoResponse

@PUT("profile/name/put")
suspend fun updateUserName(
@Header("Authorization") accessToken: String,
@Body updateUserNameRequest: UpdateUserNameRequest
): ConfirmUpdateNameResponse

@Multipart
@PUT("profile/image/put")
suspend fun updateProfilePic(
@Header("Authorization") accessToken: String,
@Part part: MultipartBody.Part
): ConfirmUpdatePicResponse

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package app.cashadvisor.profile.data.api

import app.cashadvisor.profile.data.dto.request.UpdateProfilePicRequest
import app.cashadvisor.profile.data.dto.request.UpdateUserNameRequest
import app.cashadvisor.profile.data.dto.response.ConfirmUpdateNameResponse
import app.cashadvisor.profile.data.dto.response.ConfirmUpdatePicResponse
import app.cashadvisor.profile.data.dto.response.ProfileInfoResponse

interface ProfileInfoRemoteDataSource {

suspend fun getUserInfo(accessToken: String): ProfileInfoResponse

suspend fun updateUserName(
dto: UpdateUserNameRequest,
accessToken: String
): ConfirmUpdateNameResponse

suspend fun updateProfilePic(
dto: UpdateProfilePicRequest,
accessToken: String
): ConfirmUpdatePicResponse

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.cashadvisor.profile.data.api

import app.cashadvisor.profile.data.dto.UserInfoDto

interface ProfileInfoStorage {

suspend fun getProfileInfo(): UserInfoDto?

suspend fun saveProfileInfo(userInfoDto: UserInfoDto)

suspend fun updateUserName(name: String, surname: String)

suspend fun updateProfilePic(picUrl: String)
}
12 changes: 12 additions & 0 deletions app/src/main/java/app/cashadvisor/profile/data/dto/UserInfoDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.cashadvisor.profile.data.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class UserInfoDto(
val surname: String,
val name: String,
@SerialName("user_id") val id: String,
@SerialName("avatar_url") val profilePicUrl: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app.cashadvisor.profile.data.dto.request

import java.io.File

data class UpdateProfilePicRequest(
val profilePic: File
)

//data class UpdateProfilePicRequest(
// val profilePicInputStream: InputStream
//)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package app.cashadvisor.profile.data.dto.request

import kotlinx.serialization.Serializable

@Serializable
data class UpdateUserNameRequest(
val name: String,
val surname: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package app.cashadvisor.profile.data.dto.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ConfirmUpdateNameResponse(
val message: String,
@SerialName("status_code") val statusCode: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app.cashadvisor.profile.data.dto.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ConfirmUpdatePicResponse(
val message: String,
@SerialName("status_code") val statusCode: Int,
@SerialName("avatar_url") val profilePicUrl: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.cashadvisor.profile.data.dto.response

import app.cashadvisor.profile.data.dto.UserInfoDto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ProfileInfoResponse(
@SerialName("status_code") val statusCode: Int,
val message: String,
@SerialName("profile") val userInfo: UserInfoDto?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package app.cashadvisor.profile.data.impl

import app.cashadvisor.common.utill.exceptions.NetworkException
import app.cashadvisor.profile.data.api.ProfileInfoApiService
import app.cashadvisor.profile.data.api.ProfileInfoRemoteDataSource
import app.cashadvisor.profile.data.dto.request.UpdateProfilePicRequest
import app.cashadvisor.profile.data.dto.request.UpdateUserNameRequest
import app.cashadvisor.profile.data.dto.response.ConfirmUpdateNameResponse
import app.cashadvisor.profile.data.dto.response.ConfirmUpdatePicResponse
import app.cashadvisor.profile.data.dto.response.ProfileInfoResponse
import app.cashadvisor.profile.data.mapper.NetworkToProfileExceptionMapper
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import javax.inject.Inject


class ProfileInfoRemoteDataSourceImpl @Inject constructor(
private val profileInfoApiService: ProfileInfoApiService,
private val networkToProfileExceptionMapper: NetworkToProfileExceptionMapper
) : ProfileInfoRemoteDataSource {
override suspend fun getUserInfo(accessToken: String): ProfileInfoResponse {
return try {
val response = profileInfoApiService.getUserInfo(accessToken = accessToken)
response
} catch (exception: NetworkException) {
throw networkToProfileExceptionMapper.handleExceptionGettingProfile(exception)
}
}

override suspend fun updateUserName(
dto: UpdateUserNameRequest,
accessToken: String
): ConfirmUpdateNameResponse {
return try {
profileInfoApiService.updateUserName(
updateUserNameRequest = dto,
accessToken = accessToken
)
} catch (exception: NetworkException) {
throw networkToProfileExceptionMapper.handleExceptionUpdatingProfile(exception)
}
}

override suspend fun updateProfilePic(
dto: UpdateProfilePicRequest,
accessToken: String
): ConfirmUpdatePicResponse {
val requestFile = dto.profilePic.asRequestBody("image/*".toMediaTypeOrNull())
val part = MultipartBody.Part.createFormData("image", dto.profilePic.name, requestFile)

return try {
profileInfoApiService.updateProfilePic(accessToken, part)
} catch (exception: NetworkException) {
throw networkToProfileExceptionMapper.handleExceptionUpdatingProfile(exception)
}
}

}
Loading

0 comments on commit 55dcc83

Please sign in to comment.