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

Feature/76 edit user profile #87

Merged
merged 72 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
9d695af
Added layout for profile settings
lzaytseva Mar 17, 2024
676040f
extracted dimension resources
lzaytseva Mar 18, 2024
b1c2b4b
added an empty fragment and a view model
lzaytseva Mar 19, 2024
5a6d53e
added an id to the image view
lzaytseva Mar 19, 2024
4fc697b
added profile pic upload
lzaytseva Mar 19, 2024
bf28dbf
added UserProfileInfo model
lzaytseva Mar 19, 2024
ea69afc
moved ProfileSettingsFragment.kt to presentation/ui
lzaytseva Mar 19, 2024
f2a0edb
added screen state and side effects interfaces
lzaytseva Mar 19, 2024
f6258d8
rearranged files in packages
lzaytseva Mar 21, 2024
757adef
added back navigation to button
lzaytseva Mar 21, 2024
753e16d
updated saveChanges method signature and fixed missing text value
lzaytseva Mar 21, 2024
aefc3fd
added EmptyName side effect to show a message in case user defines on…
lzaytseva Mar 21, 2024
5a4c314
implemented a draft version of input validation
lzaytseva Mar 21, 2024
52c5b9c
added di module for interactor
lzaytseva Mar 22, 2024
bc12a5c
added di module for interactor
lzaytseva Mar 22, 2024
78ce298
added missing Inject annotation
lzaytseva Mar 22, 2024
bf5e5fb
name refactoring
lzaytseva Mar 22, 2024
07a21e5
added edit text backgrounds for success and error input
lzaytseva Mar 22, 2024
caab171
added layout for header
lzaytseva Mar 25, 2024
14a5453
added profile api service, requests and responses dto
lzaytseva Mar 25, 2024
5704d6e
added glide dependency for profile header
lzaytseva Mar 25, 2024
fbc746c
implemented profile header compound view
lzaytseva Mar 25, 2024
e63f2a7
added profile header to analytics and header screens
lzaytseva Mar 25, 2024
6f0469c
added profile settings fragment to nav graph
lzaytseva Mar 25, 2024
baa024d
renamed view
lzaytseva Mar 25, 2024
ba129a7
added header for settings screen
lzaytseva Mar 25, 2024
f121574
removed period button from header
lzaytseva Mar 25, 2024
29e3af7
added navigation to profile settings but it doesnt work, idk why
lzaytseva Mar 25, 2024
a07f456
removed unused import
lzaytseva Mar 25, 2024
a632352
fixed validation
lzaytseva Mar 28, 2024
4d82cd5
removed unused imports
lzaytseva Mar 28, 2024
c33f31d
added draft implementation of data source without handling exceptions
lzaytseva Mar 28, 2024
768a9eb
removed unused import
lzaytseva Mar 28, 2024
b121e6c
fixed destination name
lzaytseva Mar 28, 2024
47053d9
implemented draft repository
lzaytseva Mar 28, 2024
31809ca
implemented ProfileInfoInteractor, fixed some errors and methods sign…
lzaytseva Mar 28, 2024
6dcdfda
renamed field
lzaytseva Mar 28, 2024
eb03b99
added mappers for dto and errors
lzaytseva Mar 28, 2024
3f6eb63
removed unused import directives
lzaytseva Mar 28, 2024
1322a5c
fixed wrong field name
lzaytseva Mar 28, 2024
323fd1e
fixed a bug
lzaytseva Mar 28, 2024
a381609
reverted api service to initial state
lzaytseva Mar 29, 2024
a33f6c3
removed unused imports
lzaytseva Mar 29, 2024
3a55dfd
rearranged files
lzaytseva Apr 7, 2024
5a65de0
implemented saving profile info to storage
lzaytseva Apr 7, 2024
07ea3f6
added annotations
lzaytseva Apr 7, 2024
a2e5c1d
added custom glide module for unsafe okhttp client
lzaytseva Apr 7, 2024
ff5485f
fixed bug: profile info wasn't saved to storage after loading
lzaytseva Apr 7, 2024
ae162ed
Merge branch 'dev' into feature/76-edit-user-profile
lzaytseva Apr 7, 2024
424964b
added error popups
lzaytseva Apr 7, 2024
bbb7027
implemented uploading image but getting: .NetworkException$InternalSe…
lzaytseva Apr 8, 2024
bc728dd
fixed error navigating to profile settings fragment
lzaytseva Apr 8, 2024
9ce63bb
added todo comment
lzaytseva Apr 8, 2024
0f78bea
handled getting empty profile
lzaytseva Apr 8, 2024
b9a794d
fixed error with glide module
lzaytseva Apr 10, 2024
6f9b2b4
added comment
lzaytseva Apr 15, 2024
cdbba64
added debounce to save btn
lzaytseva Apr 15, 2024
61e8a50
removed imports
lzaytseva Apr 15, 2024
2b56f71
fixed empty profile check
lzaytseva Apr 24, 2024
3a11b7b
fixed dependency name
lzaytseva Apr 24, 2024
80675d9
fixed var to val
lzaytseva Apr 24, 2024
5c71938
fixed empty avatar url check
lzaytseva Apr 24, 2024
f42d1b5
removed content type headers
lzaytseva Apr 24, 2024
16278f0
moved hardcoded string to resources
lzaytseva Apr 24, 2024
f33bd0f
added setAvatarPlaceholder method for setting placeholder if url come…
lzaytseva Apr 24, 2024
74020b4
removed unused things
lzaytseva Apr 24, 2024
179f4e7
changed the way profile information is stored, now is stored only dur…
lzaytseva Apr 24, 2024
92747eb
Merge branch 'dev' into feature/76-edit-user-profile
lzaytseva Apr 24, 2024
c17bdbf
Merge branch 'dev' into feature/76-edit-user-profile
lzaytseva May 12, 2024
18f04d6
removed unused style
lzaytseva May 12, 2024
c116c14
implemented updating profile pic url in view model
lzaytseva May 12, 2024
17f1162
Merge branch 'dev' into feature/76-edit-user-profile
artwist-polyakov May 20, 2024
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
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
Loading