From 23693c490ddb70c059418d3cfb72580a680c1ea1 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Mon, 10 Jun 2024 08:50:38 +0300 Subject: [PATCH 01/40] connect with api for chips --- app/src/main/AndroidManifest.xml | 1 + .../data/impl/ChipsProfileRepoImpl.kt | 147 ++++++++++++++++++ .../data/impl/ProfileInfoRepoImpl.kt | 92 +++++------ .../data/network/NewsResponse.kt | 6 + .../profiledetails/data/network/ProfileApi.kt | 29 ++++ .../data/network/ProjectResponse.kt | 6 + .../profiledetails/data/network/Request.kt | 11 ++ .../data/network/RetrofitClient.kt | 65 ++++++++ .../profiledetails/di/ProfileModule.kt | 10 ++ .../profiledetails/domain/ChipsProfileRepo.kt | 14 ++ .../profiledetails/domain/models/Project.kt | 22 +++ .../presentation/ChipsScreenState.kt | 16 ++ .../android/network/data/ApiConstants.kt | 6 +- .../android/network/data/AuthInterceptor.kt | 25 +++ .../android/network/data/NetworkClient.kt | 5 + .../android/network/data/NetworkModule.kt | 1 + 16 files changed, 402 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt create mode 100644 app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt create mode 100644 app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0fec3174..057f84d7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + >> = flow { + val response = network.doRequest(Request.GetAll(authorId)) + + if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val list: List = response.results.map { + News( + it.id, + it.type, + it.author, + it.projectId, + it.coverUrl, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount + ) + } + emit(Resource.Success(list)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } + + override suspend fun getProjects(userId: String): Flow>> = flow { + val response = network.doRequest(Request.GetProjects(userId)) + + if (response is ProjectResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val projectList: List = response.results.map { + Project( + it.id, + it.name, + it.shortDescription, + it.description, + it.logoFilePath, + it.publicationsCount, + it.area, + it.financingStage, + it.deadline, + it.siteUrls, + it.documentUrls, + it.projectAttachments + ) + } + emit(Resource.Success(projectList)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } + + override suspend fun getIdeas(type: String, userId: String): Flow>> = flow { + val response = network.doRequest(Request.GetIdeas(type, userId)) + + if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val ideaList: List = response.results.map { + News( + it.id, + it.type, + it.author, + it.projectId, + it.coverUrl, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount + ) + } + emit(Resource.Success(ideaList)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } + + override suspend fun getLikes(lastId: String, pageSize: Int): Flow>> = + flow { + val response = network.doRequest(Request.GetLikes(lastId, pageSize)) + + if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val likesList: List = response.results.map { + News( + it.id, + it.type, + it.author, + it.projectId, + it.coverUrl, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount + ) + } + emit(Resource.Success(likesList)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } + + override suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> = + flow { + val response = network.doRequest(Request.GetFavorites(lastId, pageSize)) + + if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val favList: List = response.results.map { + News( + it.id, + it.type, + it.author, + it.projectId, + it.coverUrl, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount + ) + } + emit(Resource.Success(favList)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } + + private fun getErrorType(code: Int): ErrorType = when (code) { + ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION + ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST + ApiConstants.CAPTCHA_REQUIRED -> ErrorType.CAPTCHA_REQUIRED + ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND + else -> ErrorType.UNEXPECTED + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index 0622396c..8343d1a5 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -3,13 +3,14 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl import com.innoprog.android.db.RoomDB import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileCompanyEntity import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileEntity -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileApi import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse +import com.innoprog.android.feature.profile.profiledetails.data.network.Request import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.network.data.ApiConstants +import com.innoprog.android.network.data.NetworkClient import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow @@ -17,68 +18,45 @@ import kotlinx.coroutines.flow.flow import javax.inject.Inject class ProfileInfoRepoImpl @Inject constructor( - private val network: ProfileApi, + private val network: NetworkClient, private val roomDB: RoomDB - ) : ProfileInfoRepo { override suspend fun loadProfile(): Flow> = flow { - val response = network.loadProfile() - roomDB.profileDao().saveProfile( - ProfileEntity( - userId = response.userId, - name = response.name, - about = response.about, - communicationChannels = response.communicationChannels, - authorities = response.authorities - ) - ) - when (response.resultCode) { - ApiConstants.NO_INTERNET_CONNECTION_CODE -> { - emit(Resource.Error(ErrorType.NO_CONNECTION)) - } + val apiResponse = + network.doRequest(Request.GetProfile) - ApiConstants.SUCCESS_CODE -> { - with(response as ProfileResponse) { - val result = mapToProfile(this) - emit(Resource.Success(result)) - } - } - - else -> { - emit(Resource.Error(ErrorType.BAD_REQUEST)) - } - } + if (apiResponse is ProfileResponse && apiResponse.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(mapToProfile(apiResponse))) + roomDB.profileDao().saveProfile( + ProfileEntity( + userId = apiResponse.userId, + name = apiResponse.name, + about = apiResponse.about, + communicationChannels = apiResponse.communicationChannels, + authorities = apiResponse.authorities + ) + ) + } else + emit(Resource.Error(getErrorType(apiResponse.resultCode))) } override suspend fun loadProfileCompany(): Flow> = flow { - val response = network.loadProfileCompany() - roomDB.profileCompanyDao().saveProfileCompany( - ProfileCompanyEntity( - id = response.id, - userId = response.userId, - name = response.name, - url = response.url, - role = response.role + val response = network.doRequest(Request.GetProfileCompany) + if (response is ProfileCompanyResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(mapToProfileCompany(response))) + roomDB.profileCompanyDao().saveProfileCompany( + ProfileCompanyEntity( + id = response.id, + userId = response.userId, + name = response.name, + url = response.url, + role = response.role + ) ) - ) - when (response.resultCode) { - ApiConstants.NO_INTERNET_CONNECTION_CODE -> { - emit(Resource.Error(ErrorType.NO_CONNECTION)) - } - - ApiConstants.SUCCESS_CODE -> { - with(response as ProfileCompanyResponse) { - val result = mapToProfileCompany(this) - emit(Resource.Success(result)) - } - } - - else -> { - emit(Resource.Error(ErrorType.BAD_REQUEST)) - } - } + } else + emit(Resource.Error(getErrorType(response.resultCode))) } private fun mapToProfile(response: ProfileResponse): Profile { @@ -100,4 +78,12 @@ class ProfileInfoRepoImpl @Inject constructor( response.role ) } + + private fun getErrorType(code: Int): ErrorType = when (code) { + ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION + ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST + ApiConstants.CAPTCHA_REQUIRED -> ErrorType.CAPTCHA_REQUIRED + ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND + else -> ErrorType.UNEXPECTED + } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt new file mode 100644 index 00000000..d7e71ecb --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt @@ -0,0 +1,6 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.network.data.Response + +class NewsResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index 2fe0d05b..d6ceb23b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,6 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import retrofit2.http.GET +import retrofit2.http.Query interface ProfileApi { @@ -9,4 +10,32 @@ interface ProfileApi { @GET("/v1/profile/company") suspend fun loadProfileCompany(): ProfileCompanyResponse + + @GET("/v1/feed") + suspend fun getAll( + @Query("authorId") authorId: String + ): NewsResponse + + @GET("/v1/projects") + suspend fun getProjects( + @Query("authorId") authorId: String + ): ProjectResponse + + @GET("/v1/feed") + suspend fun getIdeas( + @Query("type") type: String, + @Query("authorId") authorId: String + ): NewsResponse + + @GET("/v1/feed/likes") + suspend fun getLikes( + @Query("lastId") lastId: String, + @Query("pageSize") pageSize: Int + ): NewsResponse + + @GET("/v1/feed/favorites") + suspend fun getFavorites( + @Query("lastId") lastId: String, + @Query("pageSize") pageSize: Int + ): NewsResponse } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt new file mode 100644 index 00000000..f49cc757 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt @@ -0,0 +1,6 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +import com.innoprog.android.feature.profile.profiledetails.domain.models.Project +import com.innoprog.android.network.data.Response + +data class ProjectResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt new file mode 100644 index 00000000..745d23f9 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt @@ -0,0 +1,11 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +sealed interface Request { + data object GetProfile : Request + data object GetProfileCompany : Request + data class GetAll(val authorId: String) : Request + data class GetProjects(val authorId: String) : Request + data class GetIdeas(val type: String, val authorId: String) : Request + data class GetLikes(val lastId: String, val pageSize: Int) : Request + data class GetFavorites(val lastId: String, val pageSize: Int) : Request +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt new file mode 100644 index 00000000..49aad7ff --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt @@ -0,0 +1,65 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +import com.innoprog.android.network.data.ApiConstants +import com.innoprog.android.network.data.NetworkClient +import com.innoprog.android.network.data.Response +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import retrofit2.HttpException +import javax.inject.Inject + +class RetrofitClient @Inject constructor( + private val service: ProfileApi +) : NetworkClient { + + override suspend fun doRequest(dto: Any): Response { + + var response = Response() + return withContext(Dispatchers.IO) { + try { + response = when (dto) { + is Request.GetProfile -> { + service.loadProfile() + } + + is Request.GetProfileCompany -> { + service.loadProfileCompany() + } + + is Request.GetAll -> { + service.getAll(authorId = dto.authorId) + } + + is Request.GetProjects -> { + service.getProjects(authorId = dto.authorId) + } + + is Request.GetIdeas -> { + service.getIdeas(type = IDEA, authorId = dto.authorId) + } + + is Request.GetLikes -> { + service.getLikes(lastId = dto.lastId, pageSize = PAGE_SIZE) + } + + is Request.GetFavorites -> { + service.getFavorites(lastId = dto.lastId, pageSize = PAGE_SIZE) + } + + else -> { + throw IllegalArgumentException("Unsupported request type") + } + } + response.apply { resultCode = ApiConstants.SUCCESS_CODE } + } catch (exception: HttpException) { + response.apply { resultCode = exception.code() } + } + } + } + + companion object { + + private const val IDEA = "IDEA" + private const val PAGE_SIZE = 50 + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt index 1e3f01d1..22e82f54 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt @@ -2,14 +2,18 @@ package com.innoprog.android.feature.profile.profiledetails.di import androidx.lifecycle.ViewModel import com.innoprog.android.di.ViewModelKey +import com.innoprog.android.feature.profile.profiledetails.data.impl.ChipsProfileRepoImpl import com.innoprog.android.feature.profile.profiledetails.data.impl.ProfileInfoRepoImpl import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileApi +import com.innoprog.android.feature.profile.profiledetails.data.network.RetrofitClient +import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo import com.innoprog.android.feature.profile.profiledetails.domain.impl.GetProfileCompanyUseCaseImpl import com.innoprog.android.feature.profile.profiledetails.domain.impl.GetProfileUseCaseImpl import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileViewModel +import com.innoprog.android.network.data.NetworkClient import dagger.Binds import dagger.Module import dagger.Provides @@ -35,6 +39,12 @@ interface ProfileModule { @Binds fun bindGetProfileCompanyUseCase(impl: GetProfileCompanyUseCaseImpl): GetProfileCompanyUseCase + @Binds + fun bindNetworkClient(impl: RetrofitClient): NetworkClient + + @Binds + fun bindChipsRepository(impl: ChipsProfileRepoImpl): ChipsProfileRepo + @Module class ProfileInfoApiModule { @Provides diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt new file mode 100644 index 00000000..06b85cfa --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt @@ -0,0 +1,14 @@ +package com.innoprog.android.feature.profile.profiledetails.domain + +import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.models.Project +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow + +interface ChipsProfileRepo { + suspend fun getAll(authorId: String): Flow>> + suspend fun getProjects(userId: String): Flow>> + suspend fun getIdeas(type: String, userId: String): Flow>> + suspend fun getLikes(lastId: String, pageSize: Int): Flow>> + suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt new file mode 100644 index 00000000..8b90bf2f --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt @@ -0,0 +1,22 @@ +package com.innoprog.android.feature.profile.profiledetails.domain.models + +data class Project( + val id: String, + val name: String, + val shortDescription: String, + val description: String, + val logoFilePath: String, + val publicationsCount: Int, + val area: String, + val financingStage: String, + val deadline: String, + val siteUrls: String, + val documentUrls: List, + val projectAttachments: List +) { + data class ProjectAttachment( + val id: String, + val filePath: String, + val type: String + ) +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt new file mode 100644 index 00000000..9a232c29 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt @@ -0,0 +1,16 @@ +package com.innoprog.android.feature.profile.profiledetails.presentation + +import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.models.Project + +sealed interface ChipsScreenState { + data class All(val content: List) : ChipsScreenState + + data class Projects(val projects: List) : ChipsScreenState + + data class Ideas(val ideas: List) : ChipsScreenState + + data class Liked(val liked: List) : ChipsScreenState + + data class Favorites(val favorites: List) : ChipsScreenState +} diff --git a/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt b/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt index b6d40c23..8aecdb0c 100644 --- a/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt +++ b/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt @@ -6,6 +6,10 @@ object ApiConstants { const val READ_TIMEOUT = 30 const val SUCCESS_CODE = 200 - const val NO_INTERNET_CONNECTION_CODE = -1 const val BAD_REQUEST_CODE = 400 + const val NO_CONNECTION = -1 + const val CAPTCHA_REQUIRED = 403 + const val NOT_FOUND = 404 + const val USER_NAME = "testing@gmail.com" + const val PASSWORD = "testing" } diff --git a/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt b/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt new file mode 100644 index 00000000..6dfe7819 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt @@ -0,0 +1,25 @@ +package com.innoprog.android.network.data + +import android.util.Base64 +import com.innoprog.android.network.data.ApiConstants.PASSWORD +import com.innoprog.android.network.data.ApiConstants.USER_NAME +import okhttp3.Interceptor +import okhttp3.Response + +class AuthInterceptor : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request().newBuilder() + .addHeader( + "Authorization", + "Basic ${ + Base64.encodeToString( + "$USER_NAME:$PASSWORD".toByteArray(), + Base64.NO_WRAP + ) + }" + ) + .build() + return chain.proceed(request) + } +} diff --git a/app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt b/app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt new file mode 100644 index 00000000..1cb7115c --- /dev/null +++ b/app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt @@ -0,0 +1,5 @@ +package com.innoprog.android.network.data + +interface NetworkClient { + suspend fun doRequest(dto: Any): Response +} diff --git a/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt b/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt index 006863c1..2bfa2293 100644 --- a/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt +++ b/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt @@ -15,6 +15,7 @@ class NetworkModule { fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() .callTimeout(ApiConstants.CALL_TIMEOUT.toLong(), TimeUnit.SECONDS) .readTimeout(ApiConstants.READ_TIMEOUT.toLong(), TimeUnit.SECONDS) + .addInterceptor(AuthInterceptor()) .addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }) From 64d47270c78f4fe94d831990bd2cc3b310fa4e58 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 12 Jun 2024 20:29:11 +0300 Subject: [PATCH 02/40] add ChipsInteractor --- .../profiledetails/di/ProfileModule.kt | 5 +++ .../profiledetails/domain/ChipsInteractor.kt | 15 +++++++++ .../domain/impl/ChipsInteractorImpl.kt | 31 +++++++++++++++++++ .../presentation/ProfileViewModel.kt | 7 ++++- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt index 22e82f54..b90caa74 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt @@ -6,10 +6,12 @@ import com.innoprog.android.feature.profile.profiledetails.data.impl.ChipsProfil import com.innoprog.android.feature.profile.profiledetails.data.impl.ProfileInfoRepoImpl import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileApi import com.innoprog.android.feature.profile.profiledetails.data.network.RetrofitClient +import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo +import com.innoprog.android.feature.profile.profiledetails.domain.impl.ChipsInteractorImpl import com.innoprog.android.feature.profile.profiledetails.domain.impl.GetProfileCompanyUseCaseImpl import com.innoprog.android.feature.profile.profiledetails.domain.impl.GetProfileUseCaseImpl import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileViewModel @@ -45,6 +47,9 @@ interface ProfileModule { @Binds fun bindChipsRepository(impl: ChipsProfileRepoImpl): ChipsProfileRepo + @Binds + fun bindChipsInteractor(impl: ChipsInteractorImpl): ChipsInteractor + @Module class ProfileInfoApiModule { @Provides diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt new file mode 100644 index 00000000..45ef18d4 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt @@ -0,0 +1,15 @@ +package com.innoprog.android.feature.profile.profiledetails.domain + +import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.models.Project +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow + +interface ChipsInteractor { + + suspend fun getAll(authorId: String): Flow>> + suspend fun getProjects(userId: String): Flow>> + suspend fun getIdeas(type: String, userId: String): Flow>> + suspend fun getLikes(lastId: String, pageSize: Int): Flow>> + suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt new file mode 100644 index 00000000..8a915c13 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -0,0 +1,31 @@ +package com.innoprog.android.feature.profile.profiledetails.domain.impl + +import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor +import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo +import com.innoprog.android.feature.profile.profiledetails.domain.models.Project +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow + +class ChipsInteractorImpl(private val repo: ChipsProfileRepo): ChipsInteractor { + + override suspend fun getAll(authorId: String): Flow>> { + return repo.getAll(authorId) + } + + override suspend fun getProjects(userId: String): Flow>> { + return repo.getProjects(userId) + } + + override suspend fun getIdeas(type: String, userId: String): Flow>> { + return repo.getIdeas(type, userId) + } + + override suspend fun getLikes(lastId: String, pageSize: Int): Flow>> { + return repo.getLikes(lastId, pageSize) + } + + override suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> { + return repo.getFavorites(lastId, pageSize) + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index ad030931..39957f7e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.innoprog.android.base.BaseViewModel +import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile @@ -16,7 +17,8 @@ import javax.inject.Inject class ProfileViewModel @Inject constructor( private val getProfileUseCase: GetProfileUseCase, - private val getProfileCompanyUseCase: GetProfileCompanyUseCase + private val getProfileCompanyUseCase: GetProfileCompanyUseCase, + private val chipsInteractor: ChipsInteractor ) : BaseViewModel() { @@ -26,6 +28,9 @@ class ProfileViewModel @Inject constructor( private val _uiStateCompany = MutableLiveData() val uiStateCompany: LiveData = _uiStateCompany + private val _chipsUiState = MutableLiveData() + val chipsUiState: LiveData = _chipsUiState + private var profile: Profile? = null private var profileCompany: ProfileCompany? = null From a42ec8ce8b71c9b7be12f4c4b419e8659e029063 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 12 Jun 2024 22:13:21 +0300 Subject: [PATCH 03/40] fix header --- .../domain/impl/ChipsInteractorImpl.kt | 3 ++- .../profiledetails/presentation/ProfileViewModel.kt | 4 ++++ .../android/network/data/AuthInterceptor.kt | 13 +++++-------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt index 8a915c13..daaebb2e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -6,8 +6,9 @@ import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRe import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow +import javax.inject.Inject -class ChipsInteractorImpl(private val repo: ChipsProfileRepo): ChipsInteractor { +class ChipsInteractorImpl @Inject constructor (private val repo: ChipsProfileRepo): ChipsInteractor { override suspend fun getAll(authorId: String): Flow>> { return repo.getAll(authorId) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 39957f7e..3c5bf83e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -79,4 +79,8 @@ class ProfileViewModel @Inject constructor( } } } + + fun loadChips() { + + } } diff --git a/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt b/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt index 6dfe7819..5ff2a402 100644 --- a/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt +++ b/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt @@ -1,23 +1,20 @@ package com.innoprog.android.network.data -import android.util.Base64 import com.innoprog.android.network.data.ApiConstants.PASSWORD import com.innoprog.android.network.data.ApiConstants.USER_NAME import okhttp3.Interceptor import okhttp3.Response +import java.util.Base64 class AuthInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { + val authData = "$USER_NAME:$PASSWORD" + val request = chain.request().newBuilder() .addHeader( - "Authorization", - "Basic ${ - Base64.encodeToString( - "$USER_NAME:$PASSWORD".toByteArray(), - Base64.NO_WRAP - ) - }" + "X-Authorization", + "Basic " + Base64.getEncoder().encodeToString(authData.toByteArray()) ) .build() return chain.proceed(request) From ffa67debbaca998a23417c5068d479bd7af6c8a6 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 12 Jun 2024 22:54:02 +0300 Subject: [PATCH 04/40] add recyclers for chips --- .../presentation/ChipsScreenState.kt | 4 + .../presentation/ProfileViewModel.kt | 135 ++++++++++++------ app/src/main/res/layout/fragment_profile.xml | 55 ++++++- app/src/main/res/layout/item_projects.xml | 6 - 4 files changed, 153 insertions(+), 47 deletions(-) delete mode 100644 app/src/main/res/layout/item_projects.xml diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt index 9a232c29..64bf589e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt @@ -2,6 +2,7 @@ package com.innoprog.android.feature.profile.profiledetails.presentation import com.innoprog.android.feature.feed.newsfeed.domain.models.News import com.innoprog.android.feature.profile.profiledetails.domain.models.Project +import com.innoprog.android.util.ErrorType sealed interface ChipsScreenState { data class All(val content: List) : ChipsScreenState @@ -13,4 +14,7 @@ sealed interface ChipsScreenState { data class Liked(val liked: List) : ChipsScreenState data class Favorites(val favorites: List) : ChipsScreenState + + data class Error(val type: ErrorType) : ChipsScreenState + } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 3c5bf83e..89b6f303 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -7,11 +7,7 @@ import com.innoprog.android.base.BaseViewModel import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase -import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile -import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany -import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import javax.inject.Inject @@ -31,26 +27,16 @@ class ProfileViewModel @Inject constructor( private val _chipsUiState = MutableLiveData() val chipsUiState: LiveData = _chipsUiState - private var profile: Profile? = null - private var profileCompany: ProfileCompany? = null - fun loadProfile() { - if (profile != null) { - _uiState.postValue(ProfileScreenState.Content(profile as Profile)) - } else { - _uiState.value = ProfileScreenState.Error(ErrorType.UNEXPECTED) - - viewModelScope.launch(Dispatchers.IO) { - getProfileUseCase.getProfile().collect { response -> - when (response) { - is Resource.Success -> { - _uiState.postValue(ProfileScreenState.Content(response.data)) - profile = response.data - } - - is Resource.Error -> { - _uiState.postValue(ProfileScreenState.Error(response.errorType)) - } + viewModelScope.launch { + getProfileUseCase.getProfile().collect { response -> + when (response) { + is Resource.Success -> { + _uiState.postValue(ProfileScreenState.Content(response.data)) + } + + is Resource.Error -> { + _uiState.postValue(ProfileScreenState.Error(response.errorType)) } } } @@ -58,29 +44,98 @@ class ProfileViewModel @Inject constructor( } fun loadProfileCompany() { - if (profileCompany != null) { - _uiStateCompany.postValue(ProfileCompanyScreenState.Content(profileCompany as ProfileCompany)) - } else { - _uiStateCompany.value = ProfileCompanyScreenState.Error(ErrorType.UNEXPECTED) - - viewModelScope.launch(Dispatchers.IO) { - getProfileCompanyUseCase.getProfileCompany().collect { response -> - when (response) { - is Resource.Success -> { - _uiStateCompany.postValue(ProfileCompanyScreenState.Content(response.data)) - profileCompany = response.data - } - - is Resource.Error -> { - _uiStateCompany.postValue(ProfileCompanyScreenState.Error(response.errorType)) - } + viewModelScope.launch { + getProfileCompanyUseCase.getProfileCompany().collect { response -> + when (response) { + is Resource.Success -> { + _uiStateCompany.postValue(ProfileCompanyScreenState.Content(response.data)) + } + + is Resource.Error -> { + _uiStateCompany.postValue(ProfileCompanyScreenState.Error(response.errorType)) + } + } + } + } + } + + fun loadChipAll(authorId: String) { + viewModelScope.launch { + chipsInteractor.getAll(authorId).collect { response -> + when(response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.All(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } + } + } + } + } + + fun loadChipProjects(authorId: String) { + viewModelScope.launch { + chipsInteractor.getProjects(authorId).collect { response -> + when(response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Projects(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) } } } } } - fun loadChips() { + fun loadChipIdeas(type: String, authorId: String) { + viewModelScope.launch { + chipsInteractor.getIdeas(type, authorId).collect { response -> + when(response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Ideas(response.data)) + } + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } + } + } + } + } + + fun loadChipLikes(lastId: String, pageSize: Int) { + viewModelScope.launch { + chipsInteractor.getLikes(lastId, pageSize).collect { response -> + when(response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Liked(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } + } + } + } + } + + fun loadChipFavorites(lastId: String, pageSize: Int) { + viewModelScope.launch { + chipsInteractor.getFavorites(lastId, pageSize).collect { response -> + when(response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } + } + } + } } } diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 72cdb707..2661ea47 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -133,6 +133,7 @@ app:layout_constraintTop_toBottomOf="@+id/chips_container" /> + tools:listitem="@layout/item_news" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_projects.xml b/app/src/main/res/layout/item_projects.xml deleted file mode 100644 index 77d9ef65..00000000 --- a/app/src/main/res/layout/item_projects.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file From 4a5b0d72e49d1a2e96ca8cf8a2d2aa879149e6ff Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Fri, 14 Jun 2024 23:28:03 +0300 Subject: [PATCH 05/40] connect with api chip All --- .../data/impl/ChipsProfileRepoImpl.kt | 231 ++++++++++++------ .../data/network/IdeaResponse.kt | 6 + .../data/network/NewsResponse.kt | 6 - .../profiledetails/data/network/ProfileApi.kt | 10 +- .../profiledetails/data/network/Request.kt | 4 +- .../data/network/RetrofitClient.kt | 4 +- .../profiledetails/domain/ChipsInteractor.kt | 10 +- .../profiledetails/domain/ChipsProfileRepo.kt | 10 +- .../domain/impl/ChipsInteractorImpl.kt | 14 +- .../domain/models/FeedWrapper.kt | 72 ++++++ .../profiledetails/domain/models/Project.kt | 22 -- .../presentation/ChipsScreenState.kt | 11 +- .../presentation/ProfileFragment.kt | 160 +++++++++++- .../presentation/ProfileViewModel.kt | 8 +- .../presentation/RecyclerAdapter.kt | 29 +++ .../profiledetails/presentation/ViewHolder.kt | 94 +++++++ app/src/main/res/layout/fragment_profile.xml | 4 +- .../android/uikit/InnoProgChipGroupView.kt | 2 +- 18 files changed, 546 insertions(+), 151 deletions(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt delete mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt delete mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index b11d4d71..ba1fc9fb 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -1,10 +1,10 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl -import com.innoprog.android.feature.feed.newsfeed.domain.models.News -import com.innoprog.android.feature.profile.profiledetails.data.network.NewsResponse +import com.innoprog.android.feature.profile.profiledetails.data.network.IdeaResponse import com.innoprog.android.feature.profile.profiledetails.data.network.ProjectResponse import com.innoprog.android.feature.profile.profiledetails.data.network.Request import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient @@ -18,70 +18,97 @@ class ChipsProfileRepoImpl @Inject constructor( private val network: NetworkClient ) : ChipsProfileRepo { - override suspend fun getAll(authorId: String): Flow>> = flow { + override suspend fun getAll(authorId: String): Flow>> = flow { val response = network.doRequest(Request.GetAll(authorId)) - if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val list: List = response.results.map { - News( - it.id, - it.type, - it.author, - it.projectId, - it.coverUrl, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount - ) + if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val list: List = response.results.map { + when (it.type) { + IDEA -> FeedWrapper.Idea( + it.id, + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite + ) + + NEWS -> FeedWrapper.News( + it.id, + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite + ) + + else -> throw IllegalArgumentException("Unknown feed item type: ${it.type}") + } } emit(Resource.Success(list)) } else emit(Resource.Error(getErrorType(response.resultCode))) } - override suspend fun getProjects(userId: String): Flow>> = flow { - val response = network.doRequest(Request.GetProjects(userId)) + override suspend fun getProjects(userId: String): Flow>> = + flow { + val response = network.doRequest(Request.GetProjects(userId)) - if (response is ProjectResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val projectList: List = response.results.map { - Project( - it.id, - it.name, - it.shortDescription, - it.description, - it.logoFilePath, - it.publicationsCount, - it.area, - it.financingStage, - it.deadline, - it.siteUrls, - it.documentUrls, - it.projectAttachments - ) - } - emit(Resource.Success(projectList)) - } else - emit(Resource.Error(getErrorType(response.resultCode))) - } + if (response is ProjectResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val projectList: List = response.results.map { + Project( + it.id, + it.name, + it.shortDescription, + it.description, + it.logoFilePath, + it.publicationsCount, + it.area, + it.financingStage, + it.deadline, + it.siteUrls, + it.documentUrls, + it.projectAttachments + ) + } + emit(Resource.Success(projectList)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } - override suspend fun getIdeas(type: String, userId: String): Flow>> = flow { + override suspend fun getIdeas( + type: String, + userId: String + ): Flow>> = flow { val response = network.doRequest(Request.GetIdeas(type, userId)) - if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val ideaList: List = response.results.map { - News( + if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val ideaList: List = response.results.map { + FeedWrapper.Idea( it.id, it.type, it.author, it.projectId, - it.coverUrl, it.title, it.content, it.publishedAt, it.likesCount, - it.commentsCount + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite ) } emit(Resource.Success(ideaList)) @@ -89,48 +116,90 @@ class ChipsProfileRepoImpl @Inject constructor( emit(Resource.Error(getErrorType(response.resultCode))) } - override suspend fun getLikes(lastId: String, pageSize: Int): Flow>> = + override suspend fun getLikes(pageSize: Int): Flow>> = flow { - val response = network.doRequest(Request.GetLikes(lastId, pageSize)) + val response = network.doRequest(Request.GetLikes(pageSize)) - if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val likesList: List = response.results.map { - News( - it.id, - it.type, - it.author, - it.projectId, - it.coverUrl, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount - ) + if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val likesList: List = response.results.map { + when (it.type) { + IDEA -> FeedWrapper.Idea( + it.id, + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite + ) + + NEWS -> FeedWrapper.News( + it.id, + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite + ) + + else -> throw IllegalArgumentException("Unknown feed item type: ${it.type}") + } } emit(Resource.Success(likesList)) } else emit(Resource.Error(getErrorType(response.resultCode))) } - override suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> = + override suspend fun getFavorites(pageSize: Int): Flow>> = flow { - val response = network.doRequest(Request.GetFavorites(lastId, pageSize)) + val response = network.doRequest(Request.GetFavorites(pageSize)) - if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val favList: List = response.results.map { - News( - it.id, - it.type, - it.author, - it.projectId, - it.coverUrl, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount - ) + if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val favList: List = response.results.map { + when (it.type) { + IDEA -> FeedWrapper.Idea( + it.id, + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite + ) + + NEWS -> FeedWrapper.News( + it.id, + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite + ) + + else -> throw IllegalArgumentException("Unknown feed item type: ${it.type}") + } } emit(Resource.Success(favList)) } else @@ -144,4 +213,10 @@ class ChipsProfileRepoImpl @Inject constructor( ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND else -> ErrorType.UNEXPECTED } + + companion object { + + private const val IDEA = "IDEA" + private const val NEWS = "NEWS" + } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt new file mode 100644 index 00000000..cd1a66a1 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt @@ -0,0 +1,6 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.network.data.Response + +class IdeaResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt deleted file mode 100644 index d7e71ecb..00000000 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network - -import com.innoprog.android.feature.feed.newsfeed.domain.models.News -import com.innoprog.android.network.data.Response - -class NewsResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index d6ceb23b..162ae8e6 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -14,7 +14,7 @@ interface ProfileApi { @GET("/v1/feed") suspend fun getAll( @Query("authorId") authorId: String - ): NewsResponse + ): IdeaResponse @GET("/v1/projects") suspend fun getProjects( @@ -25,17 +25,15 @@ interface ProfileApi { suspend fun getIdeas( @Query("type") type: String, @Query("authorId") authorId: String - ): NewsResponse + ): IdeaResponse @GET("/v1/feed/likes") suspend fun getLikes( - @Query("lastId") lastId: String, @Query("pageSize") pageSize: Int - ): NewsResponse + ):IdeaResponse @GET("/v1/feed/favorites") suspend fun getFavorites( - @Query("lastId") lastId: String, @Query("pageSize") pageSize: Int - ): NewsResponse + ): IdeaResponse } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt index 745d23f9..555a2dcd 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt @@ -6,6 +6,6 @@ sealed interface Request { data class GetAll(val authorId: String) : Request data class GetProjects(val authorId: String) : Request data class GetIdeas(val type: String, val authorId: String) : Request - data class GetLikes(val lastId: String, val pageSize: Int) : Request - data class GetFavorites(val lastId: String, val pageSize: Int) : Request + data class GetLikes(val pageSize: Int) : Request + data class GetFavorites(val pageSize: Int) : Request } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt index 49aad7ff..822bcd09 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt @@ -39,11 +39,11 @@ class RetrofitClient @Inject constructor( } is Request.GetLikes -> { - service.getLikes(lastId = dto.lastId, pageSize = PAGE_SIZE) + service.getLikes(pageSize = PAGE_SIZE) } is Request.GetFavorites -> { - service.getFavorites(lastId = dto.lastId, pageSize = PAGE_SIZE) + service.getFavorites(pageSize = PAGE_SIZE) } else -> { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt index 45ef18d4..5e4cb571 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt @@ -1,15 +1,15 @@ package com.innoprog.android.feature.profile.profiledetails.domain -import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsInteractor { - suspend fun getAll(authorId: String): Flow>> + suspend fun getAll(authorId: String): Flow>> suspend fun getProjects(userId: String): Flow>> - suspend fun getIdeas(type: String, userId: String): Flow>> - suspend fun getLikes(lastId: String, pageSize: Int): Flow>> - suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> + suspend fun getIdeas(type: String, userId: String): Flow>> + suspend fun getLikes(pageSize: Int): Flow>> + suspend fun getFavorites(pageSize: Int): Flow>> } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt index 06b85cfa..b69b2f92 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt @@ -1,14 +1,14 @@ package com.innoprog.android.feature.profile.profiledetails.domain -import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsProfileRepo { - suspend fun getAll(authorId: String): Flow>> + suspend fun getAll(authorId: String): Flow>> suspend fun getProjects(userId: String): Flow>> - suspend fun getIdeas(type: String, userId: String): Flow>> - suspend fun getLikes(lastId: String, pageSize: Int): Flow>> - suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> + suspend fun getIdeas(type: String, userId: String): Flow>> + suspend fun getLikes(pageSize: Int): Flow>> + suspend fun getFavorites(pageSize: Int): Flow>> } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt index daaebb2e..581c6de6 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -1,8 +1,8 @@ package com.innoprog.android.feature.profile.profiledetails.domain.impl -import com.innoprog.android.feature.feed.newsfeed.domain.models.News import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow @@ -10,7 +10,7 @@ import javax.inject.Inject class ChipsInteractorImpl @Inject constructor (private val repo: ChipsProfileRepo): ChipsInteractor { - override suspend fun getAll(authorId: String): Flow>> { + override suspend fun getAll(authorId: String): Flow>> { return repo.getAll(authorId) } @@ -18,15 +18,15 @@ class ChipsInteractorImpl @Inject constructor (private val repo: ChipsProfileRe return repo.getProjects(userId) } - override suspend fun getIdeas(type: String, userId: String): Flow>> { + override suspend fun getIdeas(type: String, userId: String): Flow>> { return repo.getIdeas(type, userId) } - override suspend fun getLikes(lastId: String, pageSize: Int): Flow>> { - return repo.getLikes(lastId, pageSize) + override suspend fun getLikes(pageSize: Int): Flow>> { + return repo.getLikes(pageSize) } - override suspend fun getFavorites(lastId: String, pageSize: Int): Flow>> { - return repo.getFavorites(lastId, pageSize) + override suspend fun getFavorites(pageSize: Int): Flow>> { + return repo.getFavorites(pageSize) } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt new file mode 100644 index 00000000..1d2c751f --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt @@ -0,0 +1,72 @@ +package com.innoprog.android.feature.profile.profiledetails.domain.models + +sealed class FeedWrapper { + + data class Idea( + val id: String, + val type: String, + val author: Author, + val projectId: String, + val title: String, + val content: String, + val publishedAt: String, + val likesCount: Int, + val commentsCount: Int, + val attachments: List, + val isLiked: Boolean, + val isFavorite: Boolean + ) : FeedWrapper() + + data class News( + val id: String, + val type: String, + val author: Author, + val projectId: String, + val title: String, + val content: String, + val publishedAt: String, + val likesCount: Int, + val commentsCount: Int, + val attachments: List, + val isLiked: Boolean, + val isFavorite: Boolean + ) : FeedWrapper() +} + +data class Project( + val id: String, + val name: String, + val shortDescription: String, + val description: String, + val logoFilePath: String, + val publicationsCount: Int, + val area: String, + val financingStage: String, + val deadline: String, + val siteUrls: String, + val documentUrls: List, + val projectAttachments: List +) + +data class Attachment( + val id: String, + val filePath: String, + val type: String +) + +data class ProjectAttachment( + val id: String, + val filePath: String, + val type: String +) + +data class Author( + val id: String, + val name: String, + val company: Company +) + +data class Company( + val name: String, + val role: String +) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt deleted file mode 100644 index 8b90bf2f..00000000 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/Project.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.innoprog.android.feature.profile.profiledetails.domain.models - -data class Project( - val id: String, - val name: String, - val shortDescription: String, - val description: String, - val logoFilePath: String, - val publicationsCount: Int, - val area: String, - val financingStage: String, - val deadline: String, - val siteUrls: String, - val documentUrls: List, - val projectAttachments: List -) { - data class ProjectAttachment( - val id: String, - val filePath: String, - val type: String - ) -} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt index 64bf589e..c3356583 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt @@ -1,20 +1,19 @@ package com.innoprog.android.feature.profile.profiledetails.presentation -import com.innoprog.android.feature.feed.newsfeed.domain.models.News +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.ErrorType sealed interface ChipsScreenState { - data class All(val content: List) : ChipsScreenState + data class All(val content: List) : ChipsScreenState data class Projects(val projects: List) : ChipsScreenState - data class Ideas(val ideas: List) : ChipsScreenState + data class Ideas(val ideas: List) : ChipsScreenState - data class Liked(val liked: List) : ChipsScreenState + data class Liked(val liked: List) : ChipsScreenState - data class Favorites(val favorites: List) : ChipsScreenState + data class Favorites(val favorites: List) : ChipsScreenState data class Error(val type: ErrorType) : ChipsScreenState - } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index a5199231..2cd71651 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -6,12 +6,15 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager import com.innoprog.android.base.BaseFragment import com.innoprog.android.base.BaseViewModel import com.innoprog.android.databinding.FragmentProfileBinding import com.innoprog.android.di.AppComponentHolder import com.innoprog.android.di.ScreenComponent +import com.innoprog.android.feature.feed.newsfeed.presentation.FeedFragmentDirections import com.innoprog.android.feature.profile.profiledetails.di.DaggerProfileComponent +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.uikit.InnoProgChipGroupView @@ -20,6 +23,25 @@ class ProfileFragment : BaseFragment() { override val viewModel by injectViewModel() + private var user: Profile? = null + + private var publicationList: ArrayList = arrayListOf() + + private val adapter: RecyclerAdapter by lazy { + RecyclerAdapter(publicationList) { publication -> + when (publication) { + is FeedWrapper.Idea -> { + val action = FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) + findNavController().navigate(action) + } + is FeedWrapper.News -> { + val action = FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) + findNavController().navigate(action) + } + } + } + } + override fun diComponent(): ScreenComponent { val appComponent = AppComponentHolder.getComponent() return DaggerProfileComponent @@ -47,25 +69,52 @@ class ProfileFragment : BaseFragment() { initTopBar() initChips() + + initAdapter() } private fun observeData() { viewModel.uiState.observe(viewLifecycleOwner) { state -> - render(state) - } + when (state) { + is ProfileScreenState.Content -> { + user = state.profileInfo + render(state) + user?.let { user -> + viewModel.loadChipAll(authorId = user.userId) + } + } + + is ProfileScreenState.Error -> { + showError() + } + } - viewModel.uiStateCompany.observe(viewLifecycleOwner) { state -> - renderCompany(state) + viewModel.uiStateCompany.observe(viewLifecycleOwner) { state -> + renderCompany(state) + } + + viewModel.chipsUiState.observe(viewLifecycleOwner) { state -> + renderChips(state) + } } } private fun initChips() { val chipTitles = listOf(ALL_CONTENT, PROJECT, IDEAS, LIKES, FAVORITES) binding.chips.setChips(chipTitles) + binding.chips.selectChip(0) binding.chips.setOnChipSelectListener(object : InnoProgChipGroupView.OnChipSelectListener { override fun onChipSelected(chipIndex: Int) { - // Если нужно обработать чип + user?.let { user -> + when (chipIndex) { + 0 -> viewModel.loadChipAll(authorId = user.userId) + 1 -> viewModel.loadChipProjects(authorId = user.userId) + 2 -> viewModel.loadChipIdeas(type = TYPE_IDEA, authorId = user.userId) + 3 -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) + 4 -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) + } + } } }) } @@ -77,6 +126,22 @@ class ProfileFragment : BaseFragment() { } } + private fun initAdapter() { + with(binding) { + recyclerAll.layoutManager = LinearLayoutManager(context) + recyclerProjects.layoutManager = LinearLayoutManager(context) + recyclerIdeas.layoutManager = LinearLayoutManager(context) + recyclerLikes.layoutManager = LinearLayoutManager(context) + recyclerFavorites.layoutManager = LinearLayoutManager(context) + + recyclerAll.adapter = adapter + recyclerProjects.adapter = adapter + recyclerIdeas.adapter = adapter + recyclerLikes.adapter = adapter + recyclerFavorites.adapter = adapter + } + } + private fun render(screenState: ProfileScreenState) { when (screenState) { is ProfileScreenState.Content -> { @@ -101,6 +166,23 @@ class ProfileFragment : BaseFragment() { } } + private fun renderChips(chipsScreenState: ChipsScreenState) { + when (chipsScreenState) { + is ChipsScreenState.All -> showAllContent() + + is ChipsScreenState.Projects -> showUserProjects() + + is ChipsScreenState.Ideas -> showUserIdeas() + + is ChipsScreenState.Liked -> showUserLiked() + + is ChipsScreenState.Favorites -> showUserFavorites() + + is ChipsScreenState.Error -> showPlaceholder() + + } + } + private fun fillViews(profile: Profile) { with(binding) { name.text = profile.name @@ -126,6 +208,72 @@ class ProfileFragment : BaseFragment() { } } + private fun showPlaceholder() { + with(binding) { + recyclerAll.isVisible = false + recyclerProjects.isVisible = false + recyclerIdeas.isVisible = false + recyclerLikes.isVisible = false + recyclerFavorites.isVisible = false + placeholderText.isVisible = true + } + } + + private fun showAllContent() { + with(binding) { + placeholderText.isVisible = false + recyclerAll.isVisible = true + recyclerProjects.isVisible = false + recyclerIdeas.isVisible = false + recyclerLikes.isVisible = false + recyclerFavorites.isVisible = false + } + } + + private fun showUserProjects() { + with(binding) { + placeholderText.isVisible = false + recyclerAll.isVisible = false + recyclerProjects.isVisible = true + recyclerIdeas.isVisible = false + recyclerLikes.isVisible = false + recyclerFavorites.isVisible = false + } + } + + private fun showUserIdeas() { + with(binding) { + placeholderText.isVisible = false + recyclerAll.isVisible = false + recyclerProjects.isVisible = false + recyclerIdeas.isVisible = true + recyclerLikes.isVisible = false + recyclerFavorites.isVisible = false + } + } + + private fun showUserLiked() { + with(binding) { + placeholderText.isVisible = false + recyclerAll.isVisible = false + recyclerProjects.isVisible = false + recyclerIdeas.isVisible = false + recyclerLikes.isVisible = true + recyclerFavorites.isVisible = false + } + } + + private fun showUserFavorites() { + with(binding) { + placeholderText.isVisible = false + recyclerAll.isVisible = false + recyclerProjects.isVisible = false + recyclerIdeas.isVisible = false + recyclerLikes.isVisible = false + recyclerFavorites.isVisible = true + } + } + companion object { private const val ALL_CONTENT = "Всё" @@ -133,5 +281,7 @@ class ProfileFragment : BaseFragment() { private const val IDEAS = "Идеи" private const val LIKES = "Лайкнутые" private const val FAVORITES = "Избранное" + private const val PAGE_SIZE = 10 + private const val TYPE_IDEA = "IDEA" } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 89b6f303..0ccfcb3e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -107,9 +107,9 @@ class ProfileViewModel @Inject constructor( } } - fun loadChipLikes(lastId: String, pageSize: Int) { + fun loadChipLiked(pageSize: Int) { viewModelScope.launch { - chipsInteractor.getLikes(lastId, pageSize).collect { response -> + chipsInteractor.getLikes(pageSize).collect { response -> when(response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.Liked(response.data)) @@ -123,9 +123,9 @@ class ProfileViewModel @Inject constructor( } } - fun loadChipFavorites(lastId: String, pageSize: Int) { + fun loadChipFavorites(pageSize: Int) { viewModelScope.launch { - chipsInteractor.getFavorites(lastId, pageSize).collect { response -> + chipsInteractor.getFavorites(pageSize).collect { response -> when(response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt new file mode 100644 index 00000000..eaee9a60 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt @@ -0,0 +1,29 @@ +package com.innoprog.android.feature.profile.profiledetails.presentation + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.innoprog.android.databinding.ItemNewsBinding +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper + +class RecyclerAdapter( + var publicationList: ArrayList, + private val onNewsClick: (FeedWrapper) -> Unit +) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val layoutInflater = LayoutInflater.from(parent.context) + return ViewHolder(ItemNewsBinding.inflate(layoutInflater, parent, false)) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(publicationList[position]) + holder.itemView.setOnClickListener { + onNewsClick.invoke(publicationList[position]) + } + } + + override fun getItemCount(): Int { + return publicationList.size + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt new file mode 100644 index 00000000..858119ba --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt @@ -0,0 +1,94 @@ +package com.innoprog.android.feature.profile.profiledetails.presentation + +import androidx.core.view.isVisible +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import com.innoprog.android.R +import com.innoprog.android.databinding.ItemNewsBinding +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper + +class ViewHolder(private val binding: ItemNewsBinding) : + RecyclerView.ViewHolder(binding.root) { + + private val radius = binding.root.resources.getDimensionPixelSize(R.dimen.corner_radius_8) + + fun bind(publication: FeedWrapper) { + when (publication) { + is FeedWrapper.Idea -> { + binding.apply { + Glide + .with(itemView) + .load(publication.attachments.firstOrNull()?.filePath) + .placeholder(R.drawable.news_sample) + .centerCrop() + .into(ivPublicationCover) + + tvPublicationTitle.text = publication.title + tvPublicationContent.text = publication.content + + ivIdea.isVisible = true + projectCard.isVisible = false + + // val url = publication.author.avatarUrl + val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person + /* + val imageType = + url?.let { ImageLoadingType.ImageNetwork(it, placeholderResId = placeholderResId) } + if (imageType!= null) { + publicationAuthorAvatar.loadImage(imageType) + } + + */ + + tvPublicationAuthorName.text = publication.author.name + tvCommentsCount.text = publication.commentsCount.toString() + tvLikesCount.text = publication.likesCount.toString() + } + } + + is FeedWrapper.News -> { + binding.apply { + Glide + .with(itemView) + .load("https://example.com/news_image") + .placeholder(R.drawable.news_sample) + .centerCrop() + .into(ivPublicationCover) + + tvPublicationTitle.text = publication.title + tvPublicationContent.text = publication.content + + ivIdea.isVisible = false + projectCard.isVisible = true + + Glide + .with(itemView) + .load("https://example.com/project_logo") + .placeholder(R.drawable.ic_placeholder_logo) + .centerCrop() + .transform(RoundedCorners(radius)) + .into(ivProjectLogo) + + tvProjectName.text = "News Project" + tvProjectDirection.text = "News Direction" + + // val url = publication.author.avatarUrl + val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person + /* + val imageType = + url?.let { ImageLoadingType.ImageNetwork(it, placeholderResId = placeholderResId) } + if (imageType!= null) { + publicationAuthorAvatar.loadImage(imageType) + } + + */ + + tvPublicationAuthorName.text = publication.author.name + tvCommentsCount.text = publication.commentsCount.toString() + tvLikesCount.text = publication.likesCount.toString() + } + } + } + } +} diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 2661ea47..0b24ce61 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -126,7 +126,7 @@ android:gravity="center_horizontal" android:text="@string/empty" android:textColor="@color/text_tertiary" - android:visibility="visible" + android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -137,7 +137,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/padding_8" - android:visibility="gone" + android:visibility="visible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt b/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt index 8e376e51..6b11ee43 100644 --- a/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt +++ b/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt @@ -51,7 +51,7 @@ class InnoProgChipGroupView @JvmOverloads constructor( this.onChipSelectListener = listener } - private fun selectChip(chipIndex: Int) { + fun selectChip(chipIndex: Int) { if (chipIndex == selectedChipIndex) return for (i in 0 until childCount) { From 6dc1fb1f4af845b2fd35271fb88166fa11ad8bb6 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Sat, 15 Jun 2024 00:03:54 +0300 Subject: [PATCH 06/40] fix detekt --- .../profiledetails/data/network/ProfileApi.kt | 2 +- .../domain/impl/ChipsInteractorImpl.kt | 2 +- .../presentation/ProfileFragment.kt | 23 ++++++++----------- .../presentation/ProfileViewModel.kt | 10 ++++---- .../profiledetails/presentation/ViewHolder.kt | 6 ++--- .../di/FillAboutProjectComponent.kt | 2 +- .../di/FillAboutProjectModule.kt | 2 +- app/src/main/res/layout/fragment_profile.xml | 5 ++++ 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index 162ae8e6..3386b56a 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -30,7 +30,7 @@ interface ProfileApi { @GET("/v1/feed/likes") suspend fun getLikes( @Query("pageSize") pageSize: Int - ):IdeaResponse + ): IdeaResponse @GET("/v1/feed/favorites") suspend fun getFavorites( diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt index 581c6de6..ad40a9a1 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -8,7 +8,7 @@ import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow import javax.inject.Inject -class ChipsInteractorImpl @Inject constructor (private val repo: ChipsProfileRepo): ChipsInteractor { +class ChipsInteractorImpl @Inject constructor(private val repo: ChipsProfileRepo) : ChipsInteractor { override suspend fun getAll(authorId: String): Flow>> { return repo.getAll(authorId) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 2cd71651..6a5bb03a 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import androidx.navigation.fragment.findNavController -import androidx.recyclerview.widget.LinearLayoutManager import com.innoprog.android.base.BaseFragment import com.innoprog.android.base.BaseViewModel import com.innoprog.android.databinding.FragmentProfileBinding @@ -108,11 +107,11 @@ class ProfileFragment : BaseFragment() { override fun onChipSelected(chipIndex: Int) { user?.let { user -> when (chipIndex) { - 0 -> viewModel.loadChipAll(authorId = user.userId) - 1 -> viewModel.loadChipProjects(authorId = user.userId) - 2 -> viewModel.loadChipIdeas(type = TYPE_IDEA, authorId = user.userId) - 3 -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) - 4 -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) + FIRST -> viewModel.loadChipAll(authorId = user.userId) + SECOND -> viewModel.loadChipProjects(authorId = user.userId) + THIRD -> viewModel.loadChipIdeas(type = TYPE_IDEA, authorId = user.userId) + FOURTH -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) + FIFTH -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) } } } @@ -128,12 +127,6 @@ class ProfileFragment : BaseFragment() { private fun initAdapter() { with(binding) { - recyclerAll.layoutManager = LinearLayoutManager(context) - recyclerProjects.layoutManager = LinearLayoutManager(context) - recyclerIdeas.layoutManager = LinearLayoutManager(context) - recyclerLikes.layoutManager = LinearLayoutManager(context) - recyclerFavorites.layoutManager = LinearLayoutManager(context) - recyclerAll.adapter = adapter recyclerProjects.adapter = adapter recyclerIdeas.adapter = adapter @@ -179,7 +172,6 @@ class ProfileFragment : BaseFragment() { is ChipsScreenState.Favorites -> showUserFavorites() is ChipsScreenState.Error -> showPlaceholder() - } } @@ -283,5 +275,10 @@ class ProfileFragment : BaseFragment() { private const val FAVORITES = "Избранное" private const val PAGE_SIZE = 10 private const val TYPE_IDEA = "IDEA" + private const val FIRST = 0 + private const val SECOND = 1 + private const val THIRD = 2 + private const val FOURTH = 3 + private const val FIFTH = 4 } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 0ccfcb3e..ed26209b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -62,7 +62,7 @@ class ProfileViewModel @Inject constructor( fun loadChipAll(authorId: String) { viewModelScope.launch { chipsInteractor.getAll(authorId).collect { response -> - when(response) { + when (response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.All(response.data)) } @@ -78,7 +78,7 @@ class ProfileViewModel @Inject constructor( fun loadChipProjects(authorId: String) { viewModelScope.launch { chipsInteractor.getProjects(authorId).collect { response -> - when(response) { + when (response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.Projects(response.data)) } @@ -94,7 +94,7 @@ class ProfileViewModel @Inject constructor( fun loadChipIdeas(type: String, authorId: String) { viewModelScope.launch { chipsInteractor.getIdeas(type, authorId).collect { response -> - when(response) { + when (response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.Ideas(response.data)) } @@ -110,7 +110,7 @@ class ProfileViewModel @Inject constructor( fun loadChipLiked(pageSize: Int) { viewModelScope.launch { chipsInteractor.getLikes(pageSize).collect { response -> - when(response) { + when (response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.Liked(response.data)) } @@ -126,7 +126,7 @@ class ProfileViewModel @Inject constructor( fun loadChipFavorites(pageSize: Int) { viewModelScope.launch { chipsInteractor.getFavorites(pageSize).collect { response -> - when(response) { + when (response) { is Resource.Success -> { _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt index 858119ba..9b62c959 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt @@ -31,7 +31,7 @@ class ViewHolder(private val binding: ItemNewsBinding) : projectCard.isVisible = false // val url = publication.author.avatarUrl - val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person + // val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person /* val imageType = url?.let { ImageLoadingType.ImageNetwork(it, placeholderResId = placeholderResId) } @@ -73,8 +73,8 @@ class ViewHolder(private val binding: ItemNewsBinding) : tvProjectName.text = "News Project" tvProjectDirection.text = "News Direction" - // val url = publication.author.avatarUrl - val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person + // val url = publication.author.avatarUrl + // val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person /* val imageType = url?.let { ImageLoadingType.ImageNetwork(it, placeholderResId = placeholderResId) } diff --git a/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectComponent.kt b/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectComponent.kt index 171387df..49681a48 100644 --- a/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectComponent.kt +++ b/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectComponent.kt @@ -4,4 +4,4 @@ import com.innoprog.android.di.ScreenComponent import dagger.Component @Component(modules = [FillAboutProjectModule::class]) -interface FillAboutProjectComponent : ScreenComponent \ No newline at end of file +interface FillAboutProjectComponent : ScreenComponent diff --git a/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectModule.kt b/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectModule.kt index 4d208ab1..edd1e9e3 100644 --- a/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/projects/create/fillMainProjectInformation/di/FillAboutProjectModule.kt @@ -13,4 +13,4 @@ interface FillAboutProjectModule { @ViewModelKey(FillAboutProjectViewModel::class) @IntoMap fun bindViewModel(viewModel: FillAboutProjectViewModel): ViewModel -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 0b24ce61..68133a94 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -142,6 +142,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/chips_container" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="2" tools:listitem="@layout/item_news" /> @@ -155,6 +156,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/chips_container" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="2" tools:listitem="@layout/item_news" /> @@ -168,6 +170,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/chips_container" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="2" tools:listitem="@layout/item_news" /> @@ -181,6 +184,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/chips_container" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="2" tools:listitem="@layout/item_news" /> @@ -194,6 +198,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/chips_container" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="2" tools:listitem="@layout/item_news" /> From 3c923e7594d608ba26f27534442bf949136d8dd0 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Sat, 15 Jun 2024 01:18:06 +0300 Subject: [PATCH 07/40] fix connect with api chip All --- .../profiledetails/data/network/ProfileApi.kt | 12 +++++++----- .../profiledetails/data/network/RetrofitClient.kt | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index 3386b56a..cf765f7d 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,5 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.network +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import retrofit2.http.GET import retrofit2.http.Query @@ -14,26 +16,26 @@ interface ProfileApi { @GET("/v1/feed") suspend fun getAll( @Query("authorId") authorId: String - ): IdeaResponse + ): List @GET("/v1/projects") suspend fun getProjects( @Query("authorId") authorId: String - ): ProjectResponse + ): List @GET("/v1/feed") suspend fun getIdeas( @Query("type") type: String, @Query("authorId") authorId: String - ): IdeaResponse + ): List @GET("/v1/feed/likes") suspend fun getLikes( @Query("pageSize") pageSize: Int - ): IdeaResponse + ): List @GET("/v1/feed/favorites") suspend fun getFavorites( @Query("pageSize") pageSize: Int - ): IdeaResponse + ): List } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt index 822bcd09..f4e8b56e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt @@ -27,23 +27,23 @@ class RetrofitClient @Inject constructor( } is Request.GetAll -> { - service.getAll(authorId = dto.authorId) + IdeaResponse(service.getAll(authorId = dto.authorId)) } is Request.GetProjects -> { - service.getProjects(authorId = dto.authorId) + ProjectResponse(service.getProjects(authorId = dto.authorId)) } is Request.GetIdeas -> { - service.getIdeas(type = IDEA, authorId = dto.authorId) + IdeaResponse(service.getIdeas(type = IDEA, authorId = dto.authorId)) } is Request.GetLikes -> { - service.getLikes(pageSize = PAGE_SIZE) + IdeaResponse(service.getLikes(pageSize = PAGE_SIZE)) } is Request.GetFavorites -> { - service.getFavorites(pageSize = PAGE_SIZE) + IdeaResponse(service.getFavorites(pageSize = PAGE_SIZE)) } else -> { From c44a89a473f2b2273a779ae9cc7e1781d6a077e0 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 19 Jun 2024 16:57:04 +0300 Subject: [PATCH 08/40] fix chip project --- .../data/impl/ChipsProfileRepoImpl.kt | 42 ++--- .../{ProjectResponse.kt => ChipsResponse.kt} | 4 +- .../data/network/NewsResponse.kt | 6 + .../profiledetails/data/network/ProfileApi.kt | 12 +- .../profiledetails/data/network/Request.kt | 2 +- .../data/network/RetrofitClient.kt | 9 +- .../profiledetails/domain/ChipsInteractor.kt | 3 +- .../profiledetails/domain/ChipsProfileRepo.kt | 3 +- .../domain/impl/ChipsInteractorImpl.kt | 5 +- .../domain/models/FeedWrapper.kt | 81 ++++----- .../presentation/ChipsScreenState.kt | 3 +- .../presentation/ProfileFragment.kt | 122 ++++++++++---- .../presentation/ProfileViewModel.kt | 159 +++++++++++------- ...pter.kt => PublicationsRecyclerAdapter.kt} | 18 +- ...iewHolder.kt => PublicationsViewHolder.kt} | 13 +- app/src/main/res/layout/fragment_profile.xml | 148 ++++++++-------- app/src/main/res/layout/item_news.xml | 4 +- 17 files changed, 347 insertions(+), 287 deletions(-) rename app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/{ProjectResponse.kt => ChipsResponse.kt} (68%) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt rename app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/{RecyclerAdapter.kt => PublicationsRecyclerAdapter.kt} (56%) rename app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/{ViewHolder.kt => PublicationsViewHolder.kt} (85%) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index ba1fc9fb..d969e978 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -1,11 +1,11 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl +import com.innoprog.android.feature.profile.profiledetails.data.network.ChipsResponse import com.innoprog.android.feature.profile.profiledetails.data.network.IdeaResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.ProjectResponse +import com.innoprog.android.feature.profile.profiledetails.data.network.NewsResponse import com.innoprog.android.feature.profile.profiledetails.data.network.Request import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient import com.innoprog.android.util.ErrorType @@ -21,7 +21,7 @@ class ChipsProfileRepoImpl @Inject constructor( override suspend fun getAll(authorId: String): Flow>> = flow { val response = network.doRequest(Request.GetAll(authorId)) - if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { val list: List = response.results.map { when (it.type) { IDEA -> FeedWrapper.Idea( @@ -62,25 +62,25 @@ class ChipsProfileRepoImpl @Inject constructor( emit(Resource.Error(getErrorType(response.resultCode))) } - override suspend fun getProjects(userId: String): Flow>> = + override suspend fun getProjects(type: String, userId: String): Flow>> = flow { - val response = network.doRequest(Request.GetProjects(userId)) + val response = network.doRequest(Request.GetProjects(type, userId)) - if (response is ProjectResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val projectList: List = response.results.map { - Project( + if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val projectList: List = response.results.map { + FeedWrapper.News( it.id, - it.name, - it.shortDescription, - it.description, - it.logoFilePath, - it.publicationsCount, - it.area, - it.financingStage, - it.deadline, - it.siteUrls, - it.documentUrls, - it.projectAttachments + it.type, + it.author, + it.projectId, + it.title, + it.content, + it.publishedAt, + it.likesCount, + it.commentsCount, + it.attachments, + it.isLiked, + it.isFavorite ) } emit(Resource.Success(projectList)) @@ -120,7 +120,7 @@ class ChipsProfileRepoImpl @Inject constructor( flow { val response = network.doRequest(Request.GetLikes(pageSize)) - if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { val likesList: List = response.results.map { when (it.type) { IDEA -> FeedWrapper.Idea( @@ -165,7 +165,7 @@ class ChipsProfileRepoImpl @Inject constructor( flow { val response = network.doRequest(Request.GetFavorites(pageSize)) - if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { val favList: List = response.results.map { when (it.type) { IDEA -> FeedWrapper.Idea( diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt similarity index 68% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt rename to app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt index f49cc757..1405a3bc 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProjectResponse.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt @@ -1,6 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.network -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.network.data.Response -data class ProjectResponse(val results: List) : Response() +class ChipsResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt new file mode 100644 index 00000000..b59aa62e --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt @@ -0,0 +1,6 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.network.data.Response + +class NewsResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index cf765f7d..325b5110 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,7 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import retrofit2.http.GET import retrofit2.http.Query @@ -16,12 +15,13 @@ interface ProfileApi { @GET("/v1/feed") suspend fun getAll( @Query("authorId") authorId: String - ): List + ): List - @GET("/v1/projects") + @GET("/v1/feed") suspend fun getProjects( + @Query("type") type: String, @Query("authorId") authorId: String - ): List + ): List @GET("/v1/feed") suspend fun getIdeas( @@ -32,10 +32,10 @@ interface ProfileApi { @GET("/v1/feed/likes") suspend fun getLikes( @Query("pageSize") pageSize: Int - ): List + ): List @GET("/v1/feed/favorites") suspend fun getFavorites( @Query("pageSize") pageSize: Int - ): List + ): List } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt index 555a2dcd..4599dd1f 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt @@ -4,7 +4,7 @@ sealed interface Request { data object GetProfile : Request data object GetProfileCompany : Request data class GetAll(val authorId: String) : Request - data class GetProjects(val authorId: String) : Request + data class GetProjects(val type: String, val authorId: String) : Request data class GetIdeas(val type: String, val authorId: String) : Request data class GetLikes(val pageSize: Int) : Request data class GetFavorites(val pageSize: Int) : Request diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt index f4e8b56e..ee713bd8 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt @@ -27,11 +27,11 @@ class RetrofitClient @Inject constructor( } is Request.GetAll -> { - IdeaResponse(service.getAll(authorId = dto.authorId)) + ChipsResponse(service.getAll(authorId = dto.authorId)) } is Request.GetProjects -> { - ProjectResponse(service.getProjects(authorId = dto.authorId)) + NewsResponse(service.getProjects(type = NEWS, authorId = dto.authorId)) } is Request.GetIdeas -> { @@ -39,11 +39,11 @@ class RetrofitClient @Inject constructor( } is Request.GetLikes -> { - IdeaResponse(service.getLikes(pageSize = PAGE_SIZE)) + ChipsResponse(service.getLikes(pageSize = PAGE_SIZE)) } is Request.GetFavorites -> { - IdeaResponse(service.getFavorites(pageSize = PAGE_SIZE)) + ChipsResponse(service.getFavorites(pageSize = PAGE_SIZE)) } else -> { @@ -60,6 +60,7 @@ class RetrofitClient @Inject constructor( companion object { private const val IDEA = "IDEA" + private const val NEWS = "NEWS" private const val PAGE_SIZE = 50 } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt index 5e4cb571..a4e58f69 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt @@ -1,14 +1,13 @@ package com.innoprog.android.feature.profile.profiledetails.domain import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsInteractor { suspend fun getAll(authorId: String): Flow>> - suspend fun getProjects(userId: String): Flow>> + suspend fun getProjects(type: String, userId: String): Flow>> suspend fun getIdeas(type: String, userId: String): Flow>> suspend fun getLikes(pageSize: Int): Flow>> suspend fun getFavorites(pageSize: Int): Flow>> diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt index b69b2f92..bacdbdad 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt @@ -1,13 +1,12 @@ package com.innoprog.android.feature.profile.profiledetails.domain import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsProfileRepo { suspend fun getAll(authorId: String): Flow>> - suspend fun getProjects(userId: String): Flow>> + suspend fun getProjects(type: String, userId: String): Flow>> suspend fun getIdeas(type: String, userId: String): Flow>> suspend fun getLikes(pageSize: Int): Flow>> suspend fun getFavorites(pageSize: Int): Flow>> diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt index ad40a9a1..6f27efca 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -3,7 +3,6 @@ package com.innoprog.android.feature.profile.profiledetails.domain.impl import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow import javax.inject.Inject @@ -14,8 +13,8 @@ class ChipsInteractorImpl @Inject constructor(private val repo: ChipsProfileRepo return repo.getAll(authorId) } - override suspend fun getProjects(userId: String): Flow>> { - return repo.getProjects(userId) + override suspend fun getProjects(type: String, userId: String): Flow>> { + return repo.getProjects(type, userId) } override suspend fun getIdeas(type: String, userId: String): Flow>> { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt index 1d2c751f..ec44016b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt @@ -1,65 +1,56 @@ package com.innoprog.android.feature.profile.profiledetails.domain.models sealed class FeedWrapper { + abstract val id: String + abstract val type: String + abstract val author: Author + abstract val projectId: String + abstract val title: String + abstract val content: String + abstract val publishedAt: String + abstract val likesCount: Int + abstract val commentsCount: Int + abstract val attachments: List + abstract val isLiked: Boolean + abstract val isFavorite: Boolean data class Idea( - val id: String, - val type: String, - val author: Author, - val projectId: String, - val title: String, - val content: String, - val publishedAt: String, - val likesCount: Int, - val commentsCount: Int, - val attachments: List, - val isLiked: Boolean, - val isFavorite: Boolean + override val id: String, + override val type: String, + override val author: Author, + override val projectId: String, + override val title: String, + override val content: String, + override val publishedAt: String, + override val likesCount: Int, + override val commentsCount: Int, + override val attachments: List, + override val isLiked: Boolean, + override val isFavorite: Boolean ) : FeedWrapper() data class News( - val id: String, - val type: String, - val author: Author, - val projectId: String, - val title: String, - val content: String, - val publishedAt: String, - val likesCount: Int, - val commentsCount: Int, - val attachments: List, - val isLiked: Boolean, - val isFavorite: Boolean + override val id: String, + override val type: String, + override val author: Author, + override val projectId: String, + override val title: String, + override val content: String, + override val publishedAt: String, + override val likesCount: Int, + override val commentsCount: Int, + override val attachments: List, + override val isLiked: Boolean, + override val isFavorite: Boolean ) : FeedWrapper() } -data class Project( - val id: String, - val name: String, - val shortDescription: String, - val description: String, - val logoFilePath: String, - val publicationsCount: Int, - val area: String, - val financingStage: String, - val deadline: String, - val siteUrls: String, - val documentUrls: List, - val projectAttachments: List -) - data class Attachment( val id: String, val filePath: String, val type: String ) -data class ProjectAttachment( - val id: String, - val filePath: String, - val type: String -) - data class Author( val id: String, val name: String, diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt index c3356583..8caff37b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt @@ -1,13 +1,12 @@ package com.innoprog.android.feature.profile.profiledetails.presentation import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.feature.profile.profiledetails.domain.models.Project import com.innoprog.android.util.ErrorType sealed interface ChipsScreenState { data class All(val content: List) : ChipsScreenState - data class Projects(val projects: List) : ChipsScreenState + data class Projects(val projects: List) : ChipsScreenState data class Ideas(val ideas: List) : ChipsScreenState diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 6a5bb03a..117e3fe3 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -1,6 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.presentation import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -23,18 +24,20 @@ class ProfileFragment : BaseFragment() { override val viewModel by injectViewModel() private var user: Profile? = null + private var publications: ArrayList = arrayListOf() - private var publicationList: ArrayList = arrayListOf() - - private val adapter: RecyclerAdapter by lazy { - RecyclerAdapter(publicationList) { publication -> + private val publicationsAdapter: PublicationsRecyclerAdapter by lazy { + PublicationsRecyclerAdapter(publications) { publication -> when (publication) { is FeedWrapper.Idea -> { - val action = FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) + val action = + FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) findNavController().navigate(action) } + is FeedWrapper.News -> { - val action = FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) + val action = + FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) findNavController().navigate(action) } } @@ -69,7 +72,9 @@ class ProfileFragment : BaseFragment() { initChips() - initAdapter() + initAdapters() + Log.d("ProfileFragment", "RecyclerView initialized") + } private fun observeData() { @@ -101,17 +106,21 @@ class ProfileFragment : BaseFragment() { private fun initChips() { val chipTitles = listOf(ALL_CONTENT, PROJECT, IDEAS, LIKES, FAVORITES) binding.chips.setChips(chipTitles) - binding.chips.selectChip(0) + binding.chips.selectChip(INDEX_1) binding.chips.setOnChipSelectListener(object : InnoProgChipGroupView.OnChipSelectListener { override fun onChipSelected(chipIndex: Int) { user?.let { user -> when (chipIndex) { - FIRST -> viewModel.loadChipAll(authorId = user.userId) - SECOND -> viewModel.loadChipProjects(authorId = user.userId) - THIRD -> viewModel.loadChipIdeas(type = TYPE_IDEA, authorId = user.userId) - FOURTH -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) - FIFTH -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) + INDEX_1 -> viewModel.loadChipAll(authorId = user.userId) + INDEX_2 -> viewModel.loadChipProjects( + type = TYPE_NEWS, + authorId = user.userId + ) + + INDEX_3 -> viewModel.loadChipIdeas(type = TYPE_IDEA, authorId = user.userId) + INDEX_4 -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) + INDEX_5 -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) } } } @@ -125,14 +134,16 @@ class ProfileFragment : BaseFragment() { } } - private fun initAdapter() { + private fun initAdapters() { with(binding) { - recyclerAll.adapter = adapter - recyclerProjects.adapter = adapter - recyclerIdeas.adapter = adapter - recyclerLikes.adapter = adapter - recyclerFavorites.adapter = adapter + recyclerAll.adapter = publicationsAdapter + recyclerProjects.adapter = publicationsAdapter + recyclerIdeas.adapter = publicationsAdapter + recyclerLikes.adapter = publicationsAdapter + recyclerFavorites.adapter = publicationsAdapter } + Log.d("ProfileFragment", "Publications adapter initialized") + } private fun render(screenState: ProfileScreenState) { @@ -161,15 +172,55 @@ class ProfileFragment : BaseFragment() { private fun renderChips(chipsScreenState: ChipsScreenState) { when (chipsScreenState) { - is ChipsScreenState.All -> showAllContent() + is ChipsScreenState.All -> { + publications.clear() + publications.addAll(chipsScreenState.content) + Log.d("ProfileFragment", "list size: ${publications.size}") + Log.d("ProfileFragment", "list: $publications") + publicationsAdapter.notifyDataSetChanged() + Log.d("ProfileFragment", "NotifyDataSetChanged called") + showAllContent() + } - is ChipsScreenState.Projects -> showUserProjects() + is ChipsScreenState.Projects -> { + publications.clear() + publications.addAll(chipsScreenState.projects) + Log.d("ProfileFragment", "list size: ${publications.size}") + Log.d("ProfileFragment", "list: $publications") + publicationsAdapter.notifyDataSetChanged() + Log.d("ProfileFragment", "NotifyDataSetChanged called") + showUserProjects() + } - is ChipsScreenState.Ideas -> showUserIdeas() + is ChipsScreenState.Ideas -> { + publications.clear() + publications.addAll(chipsScreenState.ideas) + Log.d("ProfileFragment", "list size: ${publications.size}") + Log.d("ProfileFragment", "list: $publications") + publicationsAdapter.notifyDataSetChanged() + Log.d("ProfileFragment", "NotifyDataSetChanged called") + showUserIdeas() + } - is ChipsScreenState.Liked -> showUserLiked() + is ChipsScreenState.Liked -> { + publications.clear() + publications.addAll(chipsScreenState.liked) + Log.d("ProfileFragment", "Publications list size: ${publications.size}") + Log.d("ProfileFragment", "Publications list: $publications") + publicationsAdapter.notifyDataSetChanged() + Log.d("ProfileFragment", "NotifyDataSetChanged called") + showUserLiked() + } - is ChipsScreenState.Favorites -> showUserFavorites() + is ChipsScreenState.Favorites -> { + publications.clear() + publications.addAll(chipsScreenState.favorites) + Log.d("ProfileFragment", "list size: ${publications.size}") + Log.d("ProfileFragment", "list: $publications") + publicationsAdapter.notifyDataSetChanged() + Log.d("ProfileFragment", "NotifyDataSetChanged called") + showUserFavorites() + } is ChipsScreenState.Error -> showPlaceholder() } @@ -213,56 +264,58 @@ class ProfileFragment : BaseFragment() { private fun showAllContent() { with(binding) { - placeholderText.isVisible = false recyclerAll.isVisible = true recyclerProjects.isVisible = false recyclerIdeas.isVisible = false recyclerLikes.isVisible = false recyclerFavorites.isVisible = false + placeholderText.isVisible = false + } } private fun showUserProjects() { with(binding) { - placeholderText.isVisible = false recyclerAll.isVisible = false recyclerProjects.isVisible = true recyclerIdeas.isVisible = false recyclerLikes.isVisible = false recyclerFavorites.isVisible = false + placeholderText.isVisible = false } } private fun showUserIdeas() { with(binding) { - placeholderText.isVisible = false recyclerAll.isVisible = false recyclerProjects.isVisible = false recyclerIdeas.isVisible = true recyclerLikes.isVisible = false recyclerFavorites.isVisible = false + placeholderText.isVisible = false } } private fun showUserLiked() { with(binding) { - placeholderText.isVisible = false recyclerAll.isVisible = false recyclerProjects.isVisible = false recyclerIdeas.isVisible = false recyclerLikes.isVisible = true recyclerFavorites.isVisible = false + placeholderText.isVisible = false + } } private fun showUserFavorites() { with(binding) { - placeholderText.isVisible = false recyclerAll.isVisible = false recyclerProjects.isVisible = false recyclerIdeas.isVisible = false recyclerLikes.isVisible = false recyclerFavorites.isVisible = true + placeholderText.isVisible = false } } @@ -275,10 +328,11 @@ class ProfileFragment : BaseFragment() { private const val FAVORITES = "Избранное" private const val PAGE_SIZE = 10 private const val TYPE_IDEA = "IDEA" - private const val FIRST = 0 - private const val SECOND = 1 - private const val THIRD = 2 - private const val FOURTH = 3 - private const val FIFTH = 4 + private const val TYPE_NEWS = "NEWS" + private const val INDEX_1 = 0 + private const val INDEX_2 = 1 + private const val INDEX_3 = 2 + private const val INDEX_4 = 3 + private const val INDEX_5 = 4 } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index ed26209b..6bde09a9 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -7,7 +7,9 @@ import com.innoprog.android.base.BaseViewModel import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase +import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import javax.inject.Inject @@ -28,113 +30,142 @@ class ProfileViewModel @Inject constructor( val chipsUiState: LiveData = _chipsUiState fun loadProfile() { - viewModelScope.launch { - getProfileUseCase.getProfile().collect { response -> - when (response) { - is Resource.Success -> { - _uiState.postValue(ProfileScreenState.Content(response.data)) - } - - is Resource.Error -> { - _uiState.postValue(ProfileScreenState.Error(response.errorType)) + viewModelScope.launch(Dispatchers.IO) { + runCatching { + getProfileUseCase.getProfile().collect { response -> + when (response) { + is Resource.Success -> { + _uiState.postValue(ProfileScreenState.Content(response.data)) + } + + is Resource.Error -> { + _uiState.postValue(ProfileScreenState.Error(response.errorType)) + } } } + }.onFailure { + _uiState.postValue(ProfileScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } fun loadProfileCompany() { - viewModelScope.launch { - getProfileCompanyUseCase.getProfileCompany().collect { response -> - when (response) { - is Resource.Success -> { - _uiStateCompany.postValue(ProfileCompanyScreenState.Content(response.data)) - } - - is Resource.Error -> { - _uiStateCompany.postValue(ProfileCompanyScreenState.Error(response.errorType)) + viewModelScope.launch(Dispatchers.IO) { + runCatching { + getProfileCompanyUseCase.getProfileCompany().collect { response -> + when (response) { + is Resource.Success -> { + _uiStateCompany.postValue(ProfileCompanyScreenState.Content(response.data)) + } + + is Resource.Error -> { + _uiStateCompany.postValue(ProfileCompanyScreenState.Error(response.errorType)) + } } } + }.onFailure { + _uiStateCompany.postValue(ProfileCompanyScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } fun loadChipAll(authorId: String) { - viewModelScope.launch { - chipsInteractor.getAll(authorId).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.All(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + viewModelScope.launch(Dispatchers.IO) { + runCatching { + chipsInteractor.getAll(authorId).collect { response -> + when (response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.All(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } } } + }.onFailure { + _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } - fun loadChipProjects(authorId: String) { - viewModelScope.launch { - chipsInteractor.getProjects(authorId).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Projects(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + fun loadChipProjects(type: String, authorId: String) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + chipsInteractor.getProjects(type, authorId).collect { response -> + when (response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Projects(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } } } + }.onFailure { + _chipsUiState.postValue((ChipsScreenState.Error(type = ErrorType.NO_CONNECTION))) } } } fun loadChipIdeas(type: String, authorId: String) { - viewModelScope.launch { - chipsInteractor.getIdeas(type, authorId).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Ideas(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + viewModelScope.launch(Dispatchers.IO) { + runCatching { + + chipsInteractor.getIdeas(type, authorId).collect { response -> + when (response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Ideas(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } } } + }.onFailure { + _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } fun loadChipLiked(pageSize: Int) { - viewModelScope.launch { - chipsInteractor.getLikes(pageSize).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Liked(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + viewModelScope.launch(Dispatchers.IO) { + runCatching { + chipsInteractor.getLikes(pageSize).collect { response -> + when (response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Liked(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } } } + }.onFailure { + _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } fun loadChipFavorites(pageSize: Int) { - viewModelScope.launch { - chipsInteractor.getFavorites(pageSize).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + viewModelScope.launch(Dispatchers.IO) { + runCatching { + chipsInteractor.getFavorites(pageSize).collect { response -> + when (response) { + is Resource.Success -> { + _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) + } + + is Resource.Error -> { + _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + } } } + }.onFailure { + _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsRecyclerAdapter.kt similarity index 56% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt rename to app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsRecyclerAdapter.kt index eaee9a60..81ad6e95 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/RecyclerAdapter.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsRecyclerAdapter.kt @@ -6,24 +6,24 @@ import androidx.recyclerview.widget.RecyclerView import com.innoprog.android.databinding.ItemNewsBinding import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -class RecyclerAdapter( - var publicationList: ArrayList, +class PublicationsRecyclerAdapter( + var publications: ArrayList, private val onNewsClick: (FeedWrapper) -> Unit -) : RecyclerView.Adapter() { +) : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PublicationsViewHolder { val layoutInflater = LayoutInflater.from(parent.context) - return ViewHolder(ItemNewsBinding.inflate(layoutInflater, parent, false)) + return PublicationsViewHolder(ItemNewsBinding.inflate(layoutInflater, parent, false)) } - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(publicationList[position]) + override fun onBindViewHolder(holder: PublicationsViewHolder, position: Int) { + holder.bind(publications[position]) holder.itemView.setOnClickListener { - onNewsClick.invoke(publicationList[position]) + onNewsClick.invoke(publications[position]) } } override fun getItemCount(): Int { - return publicationList.size + return publications.size } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsViewHolder.kt similarity index 85% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt rename to app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsViewHolder.kt index 9b62c959..ff5253f9 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ViewHolder.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsViewHolder.kt @@ -8,7 +8,7 @@ import com.innoprog.android.R import com.innoprog.android.databinding.ItemNewsBinding import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -class ViewHolder(private val binding: ItemNewsBinding) : +class PublicationsViewHolder(private val binding: ItemNewsBinding) : RecyclerView.ViewHolder(binding.root) { private val radius = binding.root.resources.getDimensionPixelSize(R.dimen.corner_radius_8) @@ -30,17 +30,6 @@ class ViewHolder(private val binding: ItemNewsBinding) : ivIdea.isVisible = true projectCard.isVisible = false - // val url = publication.author.avatarUrl - // val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person - /* - val imageType = - url?.let { ImageLoadingType.ImageNetwork(it, placeholderResId = placeholderResId) } - if (imageType!= null) { - publicationAuthorAvatar.loadImage(imageType) - } - - */ - tvPublicationAuthorName.text = publication.author.name tvCommentsCount.text = publication.commentsCount.toString() tvLikesCount.text = publication.likesCount.toString() diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 68133a94..94807bee 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -118,88 +118,80 @@ - - - - - - - + app:layout_constraintTop_toBottomOf="@id/chips_container"> - - - + - \ No newline at end of file + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_news.xml b/app/src/main/res/layout/item_news.xml index 5ed29921..e150ea5a 100644 --- a/app/src/main/res/layout/item_news.xml +++ b/app/src/main/res/layout/item_news.xml @@ -101,7 +101,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/ivProjectLogo" app:layout_constraintTop_toTopOf="parent" - tools:text="Мой стартап Мой стартап Мой стартапМой стартап Мой стартап Мой стартап Мой стартап" /> + tools:text="Мой стартап" /> + tools:text="Искусственный интеллект" /> From 9bdeab2f61995016470141d2ff0e356f263d7d9c Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 19 Jun 2024 17:36:24 +0300 Subject: [PATCH 09/40] delete AuthInterceptor & add if --- .../presentation/ProfileFragment.kt | 27 ++++++++++--------- .../android/network/data/ApiConstants.kt | 2 -- .../android/network/data/AuthInterceptor.kt | 22 --------------- .../android/network/data/NetworkModule.kt | 1 + app/src/main/res/layout/fragment_profile.xml | 8 +++--- 5 files changed, 18 insertions(+), 42 deletions(-) delete mode 100644 app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 117e3fe3..d0c33a8b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -252,13 +252,15 @@ class ProfileFragment : BaseFragment() { } private fun showPlaceholder() { - with(binding) { - recyclerAll.isVisible = false - recyclerProjects.isVisible = false - recyclerIdeas.isVisible = false - recyclerLikes.isVisible = false - recyclerFavorites.isVisible = false - placeholderText.isVisible = true + if (publicationsAdapter.publications.isNullOrEmpty()) { + with(binding) { + recyclerAll.isVisible = false + recyclerProjects.isVisible = false + recyclerIdeas.isVisible = false + recyclerLikes.isVisible = false + recyclerFavorites.isVisible = false + placeholderText.isVisible = true + } } } @@ -269,8 +271,7 @@ class ProfileFragment : BaseFragment() { recyclerIdeas.isVisible = false recyclerLikes.isVisible = false recyclerFavorites.isVisible = false - placeholderText.isVisible = false - + showPlaceholder() } } @@ -281,7 +282,7 @@ class ProfileFragment : BaseFragment() { recyclerIdeas.isVisible = false recyclerLikes.isVisible = false recyclerFavorites.isVisible = false - placeholderText.isVisible = false + showPlaceholder() } } @@ -292,7 +293,7 @@ class ProfileFragment : BaseFragment() { recyclerIdeas.isVisible = true recyclerLikes.isVisible = false recyclerFavorites.isVisible = false - placeholderText.isVisible = false + showPlaceholder() } } @@ -304,7 +305,7 @@ class ProfileFragment : BaseFragment() { recyclerLikes.isVisible = true recyclerFavorites.isVisible = false placeholderText.isVisible = false - + showPlaceholder() } } @@ -315,7 +316,7 @@ class ProfileFragment : BaseFragment() { recyclerIdeas.isVisible = false recyclerLikes.isVisible = false recyclerFavorites.isVisible = true - placeholderText.isVisible = false + showPlaceholder() } } diff --git a/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt b/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt index 8aecdb0c..5e54a938 100644 --- a/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt +++ b/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt @@ -10,6 +10,4 @@ object ApiConstants { const val NO_CONNECTION = -1 const val CAPTCHA_REQUIRED = 403 const val NOT_FOUND = 404 - const val USER_NAME = "testing@gmail.com" - const val PASSWORD = "testing" } diff --git a/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt b/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt deleted file mode 100644 index 5ff2a402..00000000 --- a/app/src/main/java/com/innoprog/android/network/data/AuthInterceptor.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.innoprog.android.network.data - -import com.innoprog.android.network.data.ApiConstants.PASSWORD -import com.innoprog.android.network.data.ApiConstants.USER_NAME -import okhttp3.Interceptor -import okhttp3.Response -import java.util.Base64 - -class AuthInterceptor : Interceptor { - - override fun intercept(chain: Interceptor.Chain): Response { - val authData = "$USER_NAME:$PASSWORD" - - val request = chain.request().newBuilder() - .addHeader( - "X-Authorization", - "Basic " + Base64.getEncoder().encodeToString(authData.toByteArray()) - ) - .build() - return chain.proceed(request) - } -} diff --git a/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt b/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt index 3528cae8..de87e9d6 100644 --- a/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt +++ b/app/src/main/java/com/innoprog/android/network/data/NetworkModule.kt @@ -1,5 +1,6 @@ package com.innoprog.android.network.data +import com.innoprog.android.network.domain.AuthorizationDataRepository import dagger.Module import dagger.Provides import okhttp3.OkHttpClient diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 94807bee..f44a11cf 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -121,7 +121,6 @@ + android:layout_height="wrap_content"> + android:visibility="visible" /> From 17ee503eae18bea4477479c650350c31c7bf27a4 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 19 Jun 2024 18:47:29 +0300 Subject: [PATCH 10/40] fix after detekt --- .../profile/profiledetails/presentation/ProfileFragment.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index d0c33a8b..a73633a8 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -1,5 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.presentation +import android.annotation.SuppressLint import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -74,9 +75,9 @@ class ProfileFragment : BaseFragment() { initAdapters() Log.d("ProfileFragment", "RecyclerView initialized") - } + @Suppress("NAME_SHADOWING") private fun observeData() { viewModel.uiState.observe(viewLifecycleOwner) { state -> when (state) { @@ -143,7 +144,6 @@ class ProfileFragment : BaseFragment() { recyclerFavorites.adapter = publicationsAdapter } Log.d("ProfileFragment", "Publications adapter initialized") - } private fun render(screenState: ProfileScreenState) { @@ -170,6 +170,7 @@ class ProfileFragment : BaseFragment() { } } + @SuppressLint("NotifyDataSetChanged") private fun renderChips(chipsScreenState: ChipsScreenState) { when (chipsScreenState) { is ChipsScreenState.All -> { @@ -252,7 +253,7 @@ class ProfileFragment : BaseFragment() { } private fun showPlaceholder() { - if (publicationsAdapter.publications.isNullOrEmpty()) { + if (publicationsAdapter.publications.isEmpty()) { with(binding) { recyclerAll.isVisible = false recyclerProjects.isVisible = false From 93b166b7b303fd64b50ac6b4da79607252b498fb Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 19 Jun 2024 19:17:48 +0300 Subject: [PATCH 11/40] fix layout --- app/src/main/res/layout/fragment_profile.xml | 30 +++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index f44a11cf..38dffd88 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -118,9 +118,23 @@ + + - - + android:layout_height="match_parent"> From 7e8543b3e12c64ffefd2252b62f5141ca13b8552 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 19 Jun 2024 22:09:14 +0300 Subject: [PATCH 12/40] fix connect chips --- .../profiledetails/data/dto/model/FeedDto.kt | 110 ++++++++++ .../data/impl/ChipsProfileRepoImpl.kt | 204 ++++-------------- .../data/network/ChipsResponse.kt | 4 +- .../data/network/IdeaResponse.kt | 6 - .../data/network/NewsResponse.kt | 6 - .../profiledetails/data/network/ProfileApi.kt | 12 +- .../data/network/RetrofitClient.kt | 4 +- .../domain/models/FeedWrapper.kt | 64 +++--- 8 files changed, 183 insertions(+), 227 deletions(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt delete mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt delete mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt new file mode 100644 index 00000000..256f5f62 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt @@ -0,0 +1,110 @@ +package com.innoprog.android.feature.profile.profiledetails.data.dto.model + +import com.google.gson.annotations.SerializedName +import com.innoprog.android.feature.feed.newsfeed.domain.models.PublicationType +import com.innoprog.android.feature.profile.profiledetails.domain.models.Attachment +import com.innoprog.android.feature.profile.profiledetails.domain.models.Author +import com.innoprog.android.feature.profile.profiledetails.domain.models.Company +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper + +class FeedDto( + @SerializedName("id") + val id: String, + @SerializedName("type") + val type: String, + @SerializedName("author") + val author: AuthorDto, + @SerializedName("projectId") + val projectId: String, + @SerializedName("title") + val title: String, + @SerializedName("content") + val content: String, + @SerializedName("publishedAt") + val publishedAt: String, + @SerializedName("likesCount") + val likesCount: Int, + @SerializedName("commentsCount") + val commentsCount: Int, + @SerializedName("attachments") + val attachments: List, + @SerializedName("isLiked") + val isLiked: Boolean, + @SerializedName("isFavorite") + val isFavorite: Boolean +) + +class AttachmentDto( + @SerializedName("id") + val id: String, + @SerializedName("filePath") + val filePath: String, + @SerializedName("type") + val type: String +) + +class AuthorDto( + @SerializedName("id") + val id: String, + @SerializedName("name") + val name: String, + @SerializedName("company") + val company: CompanyDto +) + +class CompanyDto( + @SerializedName("name") + val name: String, + @SerializedName("role") + val role: String +) + +fun FeedDto.mapToDomain(): FeedWrapper { + return when (type) { + PublicationType.NEWS.value -> { + FeedWrapper.News( + id = id, + author = Author( + id = author.id, + name = author.name, + company = Company( + name = author.company.name, + role = author.company.role + ) + ), + projectId = projectId, + title = title, + content = content, + publishedAt = publishedAt, + likesCount = likesCount, + commentsCount = commentsCount, + attachments = attachments.map { Attachment(it.id, it.filePath, it.type) }, + isLiked = isLiked, + isFavorite = isFavorite + ) + } + else -> { + FeedWrapper.Idea( + id = id, + author = Author( + id = author.id, + name = author.name, + company = Company( + name = author.company.name, + role = author.company.role + ) + ), + projectId = projectId, + title = title, + content = content, + publishedAt = publishedAt, + likesCount = likesCount, + commentsCount = commentsCount, + attachments = attachments.map { Attachment(it.id, it.filePath, it.type) }, + isLiked = isLiked, + isFavorite = isFavorite + ) + } + } +} + diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index d969e978..b2a4f08f 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -1,8 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl +import com.innoprog.android.feature.profile.profiledetails.data.dto.model.mapToDomain import com.innoprog.android.feature.profile.profiledetails.data.network.ChipsResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.IdeaResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.NewsResponse import com.innoprog.android.feature.profile.profiledetails.data.network.Request import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper @@ -18,193 +17,72 @@ class ChipsProfileRepoImpl @Inject constructor( private val network: NetworkClient ) : ChipsProfileRepo { - override suspend fun getAll(authorId: String): Flow>> = flow { - val response = network.doRequest(Request.GetAll(authorId)) + override suspend fun getAll(authorId: String): Flow>> { + return flow { + val response = network.doRequest(Request.GetAll(authorId)) - if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val list: List = response.results.map { - when (it.type) { - IDEA -> FeedWrapper.Idea( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - - NEWS -> FeedWrapper.News( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - - else -> throw IllegalArgumentException("Unknown feed item type: ${it.type}") - } - } - emit(Resource.Success(list)) - } else - emit(Resource.Error(getErrorType(response.resultCode))) + if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(response.results.map { it.mapToDomain() })) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } } - override suspend fun getProjects(type: String, userId: String): Flow>> = - flow { + override suspend fun getProjects( + type: String, + userId: String + ): Flow>> { + return flow { val response = network.doRequest(Request.GetProjects(type, userId)) - if (response is NewsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val projectList: List = response.results.map { - FeedWrapper.News( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) + if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val projects = response.results.map { + it.mapToDomain() as FeedWrapper.News } - emit(Resource.Success(projectList)) + emit(Resource.Success(projects)) } else emit(Resource.Error(getErrorType(response.resultCode))) } + } override suspend fun getIdeas( type: String, userId: String - ): Flow>> = flow { - val response = network.doRequest(Request.GetIdeas(type, userId)) + ): Flow>> { + return flow { + val response = network.doRequest(Request.GetIdeas(type, userId)) - if (response is IdeaResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val ideaList: List = response.results.map { - FeedWrapper.Idea( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - } - emit(Resource.Success(ideaList)) - } else - emit(Resource.Error(getErrorType(response.resultCode))) + if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + val ideas = response.results.map { + it.mapToDomain() as FeedWrapper.Idea + } + emit(Resource.Success(ideas)) + } else + emit(Resource.Error(getErrorType(response.resultCode))) + } } - override suspend fun getLikes(pageSize: Int): Flow>> = - flow { + override suspend fun getLikes(pageSize: Int): Flow>> { + return flow { val response = network.doRequest(Request.GetLikes(pageSize)) if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val likesList: List = response.results.map { - when (it.type) { - IDEA -> FeedWrapper.Idea( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - - NEWS -> FeedWrapper.News( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - - else -> throw IllegalArgumentException("Unknown feed item type: ${it.type}") - } - } - emit(Resource.Success(likesList)) + emit(Resource.Success(response.results.map { it.mapToDomain() })) } else emit(Resource.Error(getErrorType(response.resultCode))) } + } - override suspend fun getFavorites(pageSize: Int): Flow>> = - flow { + override suspend fun getFavorites(pageSize: Int): Flow>> { + return flow { val response = network.doRequest(Request.GetFavorites(pageSize)) if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val favList: List = response.results.map { - when (it.type) { - IDEA -> FeedWrapper.Idea( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - - NEWS -> FeedWrapper.News( - it.id, - it.type, - it.author, - it.projectId, - it.title, - it.content, - it.publishedAt, - it.likesCount, - it.commentsCount, - it.attachments, - it.isLiked, - it.isFavorite - ) - - else -> throw IllegalArgumentException("Unknown feed item type: ${it.type}") - } - } - emit(Resource.Success(favList)) + emit(Resource.Success(response.results.map { it.mapToDomain() })) } else emit(Resource.Error(getErrorType(response.resultCode))) } + } private fun getErrorType(code: Int): ErrorType = when (code) { ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION @@ -213,10 +91,4 @@ class ChipsProfileRepoImpl @Inject constructor( ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND else -> ErrorType.UNEXPECTED } - - companion object { - - private const val IDEA = "IDEA" - private const val NEWS = "NEWS" - } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt index 1405a3bc..95f96a27 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ChipsResponse.kt @@ -1,6 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.network -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.data.dto.model.FeedDto import com.innoprog.android.network.data.Response -class ChipsResponse(val results: List) : Response() +class ChipsResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt deleted file mode 100644 index cd1a66a1..00000000 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/IdeaResponse.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network - -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.network.data.Response - -class IdeaResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt deleted file mode 100644 index b59aa62e..00000000 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/NewsResponse.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network - -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.network.data.Response - -class NewsResponse(val results: List) : Response() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index 325b5110..aef6ffef 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,6 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.network -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.data.dto.model.FeedDto import retrofit2.http.GET import retrofit2.http.Query @@ -15,27 +15,27 @@ interface ProfileApi { @GET("/v1/feed") suspend fun getAll( @Query("authorId") authorId: String - ): List + ): List @GET("/v1/feed") suspend fun getProjects( @Query("type") type: String, @Query("authorId") authorId: String - ): List + ): List @GET("/v1/feed") suspend fun getIdeas( @Query("type") type: String, @Query("authorId") authorId: String - ): List + ): List @GET("/v1/feed/likes") suspend fun getLikes( @Query("pageSize") pageSize: Int - ): List + ): List @GET("/v1/feed/favorites") suspend fun getFavorites( @Query("pageSize") pageSize: Int - ): List + ): List } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt index ee713bd8..a8561191 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt @@ -31,11 +31,11 @@ class RetrofitClient @Inject constructor( } is Request.GetProjects -> { - NewsResponse(service.getProjects(type = NEWS, authorId = dto.authorId)) + ChipsResponse(service.getProjects(type = NEWS, authorId = dto.authorId)) } is Request.GetIdeas -> { - IdeaResponse(service.getIdeas(type = IDEA, authorId = dto.authorId)) + ChipsResponse(service.getIdeas(type = IDEA, authorId = dto.authorId)) } is Request.GetLikes -> { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt index ec44016b..50e55204 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt @@ -1,48 +1,34 @@ package com.innoprog.android.feature.profile.profiledetails.domain.models -sealed class FeedWrapper { - abstract val id: String - abstract val type: String - abstract val author: Author - abstract val projectId: String - abstract val title: String - abstract val content: String - abstract val publishedAt: String - abstract val likesCount: Int - abstract val commentsCount: Int - abstract val attachments: List - abstract val isLiked: Boolean - abstract val isFavorite: Boolean +sealed interface FeedWrapper { data class Idea( - override val id: String, - override val type: String, - override val author: Author, - override val projectId: String, - override val title: String, - override val content: String, - override val publishedAt: String, - override val likesCount: Int, - override val commentsCount: Int, - override val attachments: List, - override val isLiked: Boolean, - override val isFavorite: Boolean - ) : FeedWrapper() + val id: String, + val author: Author, + val projectId: String, + val title: String, + val content: String, + val publishedAt: String, + val likesCount: Int, + val commentsCount: Int, + val attachments: List, + val isLiked: Boolean, + val isFavorite: Boolean + ) : FeedWrapper data class News( - override val id: String, - override val type: String, - override val author: Author, - override val projectId: String, - override val title: String, - override val content: String, - override val publishedAt: String, - override val likesCount: Int, - override val commentsCount: Int, - override val attachments: List, - override val isLiked: Boolean, - override val isFavorite: Boolean - ) : FeedWrapper() + val id: String, + val author: Author, + val projectId: String, + val title: String, + val content: String, + val publishedAt: String, + val likesCount: Int, + val commentsCount: Int, + val attachments: List, + val isLiked: Boolean, + val isFavorite: Boolean + ) : FeedWrapper } data class Attachment( From baee54df35e580009566be7b29c1fad17d81e942 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 19 Jun 2024 23:01:44 +0300 Subject: [PATCH 13/40] fix actions --- .../profiledetails/data/dto/model/FeedDto.kt | 1 - .../presentation/ProfileFragment.kt | 10 +++++----- .../PublicationsRecyclerAdapter.kt | 6 +++--- .../{ => adapter}/PublicationsViewHolder.kt | 20 +++++++++---------- app/src/main/res/layout/item_news.xml | 2 +- app/src/main/res/navigation/app_nav_graph.xml | 6 ++++++ config/detekt/detekt.yml | 2 +- 7 files changed, 25 insertions(+), 22 deletions(-) rename app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/{ => adapter}/PublicationsRecyclerAdapter.kt (87%) rename app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/{ => adapter}/PublicationsViewHolder.kt (83%) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt index 256f5f62..d0ee2974 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt @@ -107,4 +107,3 @@ fun FeedDto.mapToDomain(): FeedWrapper { } } } - diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index a73633a8..4f839abc 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -13,11 +13,11 @@ import com.innoprog.android.base.BaseViewModel import com.innoprog.android.databinding.FragmentProfileBinding import com.innoprog.android.di.AppComponentHolder import com.innoprog.android.di.ScreenComponent -import com.innoprog.android.feature.feed.newsfeed.presentation.FeedFragmentDirections import com.innoprog.android.feature.profile.profiledetails.di.DaggerProfileComponent import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.feature.profile.profiledetails.presentation.adapter.PublicationsRecyclerAdapter import com.innoprog.android.uikit.InnoProgChipGroupView class ProfileFragment : BaseFragment() { @@ -32,13 +32,13 @@ class ProfileFragment : BaseFragment() { when (publication) { is FeedWrapper.Idea -> { val action = - FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) + ProfileFragmentDirections.actionProfileFragmentToIdeaDetailsFragment(publication.id) findNavController().navigate(action) } is FeedWrapper.News -> { val action = - FeedFragmentDirections.actionFeedFragmentToNewsDetailsFragment(publication.id) + ProfileFragmentDirections.actionProfileFragmentToNewsDetailsFragment(publication.id) findNavController().navigate(action) } } @@ -206,8 +206,8 @@ class ProfileFragment : BaseFragment() { is ChipsScreenState.Liked -> { publications.clear() publications.addAll(chipsScreenState.liked) - Log.d("ProfileFragment", "Publications list size: ${publications.size}") - Log.d("ProfileFragment", "Publications list: $publications") + Log.d("ProfileFragment", "list size: ${publications.size}") + Log.d("ProfileFragment", "list: $publications") publicationsAdapter.notifyDataSetChanged() Log.d("ProfileFragment", "NotifyDataSetChanged called") showUserLiked() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsRecyclerAdapter.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt similarity index 87% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsRecyclerAdapter.kt rename to app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt index 81ad6e95..e0be9cc4 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsRecyclerAdapter.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt @@ -1,4 +1,4 @@ -package com.innoprog.android.feature.profile.profiledetails.presentation +package com.innoprog.android.feature.profile.profiledetails.presentation.adapter import android.view.LayoutInflater import android.view.ViewGroup @@ -8,7 +8,7 @@ import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWra class PublicationsRecyclerAdapter( var publications: ArrayList, - private val onNewsClick: (FeedWrapper) -> Unit + private val onPublicationClick: (FeedWrapper) -> Unit ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PublicationsViewHolder { @@ -19,7 +19,7 @@ class PublicationsRecyclerAdapter( override fun onBindViewHolder(holder: PublicationsViewHolder, position: Int) { holder.bind(publications[position]) holder.itemView.setOnClickListener { - onNewsClick.invoke(publications[position]) + onPublicationClick.invoke(publications[position]) } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt similarity index 83% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsViewHolder.kt rename to app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt index ff5253f9..4fd5bd9c 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/PublicationsViewHolder.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt @@ -1,4 +1,4 @@ -package com.innoprog.android.feature.profile.profiledetails.presentation +package com.innoprog.android.feature.profile.profiledetails.presentation.adapter import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView @@ -7,6 +7,7 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.innoprog.android.R import com.innoprog.android.databinding.ItemNewsBinding import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.uikit.ImageLoadingType class PublicationsViewHolder(private val binding: ItemNewsBinding) : RecyclerView.ViewHolder(binding.root) { @@ -30,6 +31,10 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : ivIdea.isVisible = true projectCard.isVisible = false + val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person + val imageType = ImageLoadingType.ImageDrawable(placeholderResId) + publicationAuthorAvatar.loadImage(imageType) + tvPublicationAuthorName.text = publication.author.name tvCommentsCount.text = publication.commentsCount.toString() tvLikesCount.text = publication.likesCount.toString() @@ -62,16 +67,9 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : tvProjectName.text = "News Project" tvProjectDirection.text = "News Direction" - // val url = publication.author.avatarUrl - // val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person - /* - val imageType = - url?.let { ImageLoadingType.ImageNetwork(it, placeholderResId = placeholderResId) } - if (imageType!= null) { - publicationAuthorAvatar.loadImage(imageType) - } - - */ + val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person + val imageType = ImageLoadingType.ImageDrawable(placeholderResId) + publicationAuthorAvatar.loadImage(imageType) tvPublicationAuthorName.text = publication.author.name tvCommentsCount.text = publication.commentsCount.toString() diff --git a/app/src/main/res/layout/item_news.xml b/app/src/main/res/layout/item_news.xml index e150ea5a..fca225c1 100644 --- a/app/src/main/res/layout/item_news.xml +++ b/app/src/main/res/layout/item_news.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_begin="@dimen/margin_16" /> + app:layout_constraintGuide_end="395dp" /> + + Date: Wed, 19 Jun 2024 23:51:22 +0300 Subject: [PATCH 14/40] add di --- .../editingprofile/data/EditingProfileApi.kt | 19 ++++++++++++++ .../editingprofile/data/EditingProfileBody.kt | 10 +++++++ .../data/EditingProfileCompanyBody.kt | 12 +++++++++ .../data/impl/EditProfileInfoRepoImpl.kt | 4 +++ .../di/EditingProfileComponent.kt | 10 ++++++- .../editingprofile/di/EditingProfileModule.kt | 26 +++++++++++++++++++ .../domain/EditProfileCompanyUseCase.kt | 4 +++ .../domain/EditProfileInfoRepo.kt | 5 ++++ .../domain/EditProfileUseCase.kt | 4 +++ .../impl/EditProfileCompanyUseCaseImpl.kt | 4 +++ .../domain/impl/EditProfileUseCaseImpl.kt | 4 +++ 11 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt new file mode 100644 index 00000000..55564e1b --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt @@ -0,0 +1,19 @@ +package com.innoprog.android.feature.profile.editingprofile.data + +import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse +import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse +import retrofit2.http.Body +import retrofit2.http.PUT + +interface EditingProfileApi { + + @PUT("/v1/profile") + suspend fun saveProfile( + @Body body: EditingProfileBody + ): ProfileResponse + + @PUT("/v1/profile/company") + suspend fun saveProfileCompany( + @Body body: EditingProfileCompanyBody + ): ProfileCompanyResponse +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt new file mode 100644 index 00000000..546fe5a7 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt @@ -0,0 +1,10 @@ +package com.innoprog.android.feature.profile.editingprofile.data + +import com.google.gson.annotations.SerializedName + +data class EditingProfileBody( + @SerializedName("name") + val name: String, + @SerializedName("about") + val about: String, +) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt new file mode 100644 index 00000000..6e294076 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt @@ -0,0 +1,12 @@ +package com.innoprog.android.feature.profile.editingprofile.data + +import com.google.gson.annotations.SerializedName + +data class EditingProfileCompanyBody( + @SerializedName("name") + val name: String, + @SerializedName("url") + val url: String, + @SerializedName("role") + val role: String +) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt new file mode 100644 index 00000000..b1e93433 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt @@ -0,0 +1,4 @@ +package com.innoprog.android.feature.profile.editingprofile.data.impl + +class EditProfileInfoRepoImpl { +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileComponent.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileComponent.kt index 596a1aae..2fc6f54b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileComponent.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileComponent.kt @@ -1,9 +1,17 @@ package com.innoprog.android.feature.profile.editingprofile.di +import com.innoprog.android.di.AppComponent import com.innoprog.android.di.ScreenComponent import dagger.Component @Component( + dependencies = [AppComponent::class], modules = [EditingProfileModule::class] ) -interface EditingProfileComponent : ScreenComponent +interface EditingProfileComponent : ScreenComponent { + @Component.Builder + interface Builder { + fun build(): EditingProfileComponent + fun appComponent(appComponent: AppComponent): Builder + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt index 6f08bcb7..e8d97803 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt @@ -2,10 +2,19 @@ package com.innoprog.android.feature.profile.editingprofile.di import androidx.lifecycle.ViewModel import com.innoprog.android.di.ViewModelKey +import com.innoprog.android.feature.profile.editingprofile.data.EditingProfileApi +import com.innoprog.android.feature.profile.editingprofile.data.impl.EditProfileInfoRepoImpl +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileCompanyUseCase +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileUseCase +import com.innoprog.android.feature.profile.editingprofile.domain.impl.EditProfileCompanyUseCaseImpl +import com.innoprog.android.feature.profile.editingprofile.domain.impl.EditProfileUseCaseImpl import com.innoprog.android.feature.profile.editingprofile.presentation.EditingProfileViewModel import dagger.Binds import dagger.Module +import dagger.Provides import dagger.multibindings.IntoMap +import retrofit2.Retrofit @Module interface EditingProfileModule { @@ -14,4 +23,21 @@ interface EditingProfileModule { @ViewModelKey(EditingProfileViewModel::class) @Binds fun bindEditingProfileViewModel(impl: EditingProfileViewModel): ViewModel + + @Binds + fun bindRepository(impl: EditProfileInfoRepoImpl): EditProfileInfoRepo + + @Binds + fun bindEditProfileUseCase(impl: EditProfileUseCaseImpl): EditProfileUseCase + + @Binds + fun bindEditProfileCompanyUseCase(impl: EditProfileCompanyUseCaseImpl): EditProfileCompanyUseCase + + @Module + class EditProfileApiModule { + @Provides + fun provideApi(retrofit: Retrofit): EditingProfileApi { + return retrofit.create(EditingProfileApi::class.java) + } + } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt new file mode 100644 index 00000000..2c528135 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt @@ -0,0 +1,4 @@ +package com.innoprog.android.feature.profile.editingprofile.domain + +interface EditProfileCompanyUseCase { +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt new file mode 100644 index 00000000..ac4d7542 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt @@ -0,0 +1,5 @@ +package com.innoprog.android.feature.profile.editingprofile.domain + +interface EditProfileInfoRepo { + +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt new file mode 100644 index 00000000..aa37b8d4 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt @@ -0,0 +1,4 @@ +package com.innoprog.android.feature.profile.editingprofile.domain + +interface EditProfileUseCase { +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt new file mode 100644 index 00000000..6f9f145e --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt @@ -0,0 +1,4 @@ +package com.innoprog.android.feature.profile.editingprofile.domain.impl + +class EditProfileCompanyUseCaseImpl { +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt new file mode 100644 index 00000000..2d4724a7 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt @@ -0,0 +1,4 @@ +package com.innoprog.android.feature.profile.editingprofile.domain.impl + +class EditProfileUseCaseImpl { +} \ No newline at end of file From d5c8c83c67b52ff49c1b27c77ac682b5ba227bf2 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Thu, 20 Jun 2024 00:28:54 +0300 Subject: [PATCH 15/40] add data --- .../ProfileCompanyResponse.kt | 2 +- .../network => common}/ProfileResponse.kt | 2 +- .../data/impl/EditProfileInfoRepoImpl.kt | 86 ++++++++++++++++++- .../data/{ => network}/EditingProfileApi.kt | 10 +-- .../data/{ => network}/EditingProfileBody.kt | 2 +- .../EditingProfileCompanyBody.kt | 2 +- .../editingprofile/di/EditingProfileModule.kt | 2 +- .../domain/EditProfileCompanyUseCase.kt | 7 +- .../domain/EditProfileInfoRepo.kt | 10 ++- .../domain/EditProfileUseCase.kt | 6 ++ .../data/impl/ProfileInfoRepoImpl.kt | 8 +- .../profiledetails/data/network/ProfileApi.kt | 2 + 12 files changed, 120 insertions(+), 19 deletions(-) rename app/src/main/java/com/innoprog/android/feature/profile/{profiledetails/data/network => common}/ProfileCompanyResponse.kt (84%) rename app/src/main/java/com/innoprog/android/feature/profile/{profiledetails/data/network => common}/ProfileResponse.kt (88%) rename app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/{ => network}/EditingProfileApi.kt (58%) rename app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/{ => network}/EditingProfileBody.kt (96%) rename app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/{ => network}/EditingProfileCompanyBody.kt (97%) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/common/ProfileCompanyResponse.kt similarity index 84% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt rename to app/src/main/java/com/innoprog/android/feature/profile/common/ProfileCompanyResponse.kt index 8982cbc2..65504b1d 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/common/ProfileCompanyResponse.kt @@ -1,4 +1,4 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network +package com.innoprog.android.feature.profile.common import com.google.gson.annotations.SerializedName import com.innoprog.android.network.data.Response diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/common/ProfileResponse.kt similarity index 88% rename from app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt rename to app/src/main/java/com/innoprog/android/feature/profile/common/ProfileResponse.kt index 7b5d8017..6a2cd7a0 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/common/ProfileResponse.kt @@ -1,4 +1,4 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network +package com.innoprog.android.feature.profile.common import com.google.gson.annotations.SerializedName import com.innoprog.android.feature.profile.profiledetails.domain.models.CommunicationChannel diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt index b1e93433..79218e57 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt @@ -1,4 +1,86 @@ package com.innoprog.android.feature.profile.editingprofile.data.impl -class EditProfileInfoRepoImpl { -} \ No newline at end of file +import com.innoprog.android.feature.profile.common.ProfileCompanyResponse +import com.innoprog.android.feature.profile.common.ProfileResponse +import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileApi +import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileBody +import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileCompanyBody +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.network.data.ApiConstants +import com.innoprog.android.util.ErrorType +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class EditProfileInfoRepoImpl @Inject constructor( + private val network: EditingProfileApi +) : EditProfileInfoRepo { + + override suspend fun editProfile(name: String, about: String): Flow> = flow { + + val editingProfileBody = EditingProfileBody(name, about) + val response = network.editProfile(editingProfileBody) + + when (response.resultCode) { + ApiConstants.NO_INTERNET_CONNECTION_CODE -> { + emit(Resource.Error(ErrorType.NO_CONNECTION)) + } + + ApiConstants.SUCCESS_CODE -> { + with(response) { + val result = mapToProfile(this) + emit(Resource.Success(result)) + } + } + + else -> { + emit(Resource.Error(ErrorType.BAD_REQUEST)) + } + } + } + + override suspend fun editProfileCompany(name: String, url: String, role: String): Flow> = flow { + val editingProfileBody = EditingProfileCompanyBody(name, url, role) + val response = network.editProfileCompany(editingProfileBody) + + when (response.resultCode) { + ApiConstants.NO_INTERNET_CONNECTION_CODE -> { + emit(Resource.Error(ErrorType.NO_CONNECTION)) + } + + ApiConstants.SUCCESS_CODE -> { + with(response) { + val result = mapToProfileCompany(this) + emit(Resource.Success(result)) + } + } + + else -> { + emit(Resource.Error(ErrorType.BAD_REQUEST)) + } + } + } + + private fun mapToProfile(response: ProfileResponse): Profile { + return Profile( + response.userId, + response.name, + response.about, + response.communicationChannels, + response.authorities + ) + } + + private fun mapToProfileCompany(response: ProfileCompanyResponse): ProfileCompany { + return ProfileCompany( + response.id, + response.userId, + response.name, + response.url, + response.role + ) + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileApi.kt similarity index 58% rename from app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt rename to app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileApi.kt index 55564e1b..db9adcea 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileApi.kt @@ -1,19 +1,19 @@ -package com.innoprog.android.feature.profile.editingprofile.data +package com.innoprog.android.feature.profile.editingprofile.data.network -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse +import com.innoprog.android.feature.profile.common.ProfileCompanyResponse +import com.innoprog.android.feature.profile.common.ProfileResponse import retrofit2.http.Body import retrofit2.http.PUT interface EditingProfileApi { @PUT("/v1/profile") - suspend fun saveProfile( + suspend fun editProfile( @Body body: EditingProfileBody ): ProfileResponse @PUT("/v1/profile/company") - suspend fun saveProfileCompany( + suspend fun editProfileCompany( @Body body: EditingProfileCompanyBody ): ProfileCompanyResponse } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileBody.kt similarity index 96% rename from app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt rename to app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileBody.kt index 546fe5a7..33172970 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileBody.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileBody.kt @@ -1,4 +1,4 @@ -package com.innoprog.android.feature.profile.editingprofile.data +package com.innoprog.android.feature.profile.editingprofile.data.network import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileCompanyBody.kt similarity index 97% rename from app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt rename to app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileCompanyBody.kt index 6e294076..2499311d 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/EditingProfileCompanyBody.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/EditingProfileCompanyBody.kt @@ -1,4 +1,4 @@ -package com.innoprog.android.feature.profile.editingprofile.data +package com.innoprog.android.feature.profile.editingprofile.data.network import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt index e8d97803..1a5f04d4 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt @@ -2,7 +2,7 @@ package com.innoprog.android.feature.profile.editingprofile.di import androidx.lifecycle.ViewModel import com.innoprog.android.di.ViewModelKey -import com.innoprog.android.feature.profile.editingprofile.data.EditingProfileApi +import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileApi import com.innoprog.android.feature.profile.editingprofile.data.impl.EditProfileInfoRepoImpl import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileCompanyUseCase import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt index 2c528135..0f016e02 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt @@ -1,4 +1,9 @@ package com.innoprog.android.feature.profile.editingprofile.domain +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow + interface EditProfileCompanyUseCase { -} \ No newline at end of file + suspend fun editProfileCompany(): Flow> +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt index ac4d7542..d2036a91 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileInfoRepo.kt @@ -1,5 +1,11 @@ package com.innoprog.android.feature.profile.editingprofile.domain -interface EditProfileInfoRepo { +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow -} \ No newline at end of file +interface EditProfileInfoRepo { + suspend fun editProfile(name: String, about: String): Flow> + suspend fun editProfileCompany(name: String, url: String, role: String): Flow> +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt index aa37b8d4..92233c07 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt @@ -1,4 +1,10 @@ package com.innoprog.android.feature.profile.editingprofile.domain +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow + interface EditProfileUseCase { + suspend fun editProfile(): Flow> + } \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index 0622396c..579ba68c 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -1,11 +1,11 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl import com.innoprog.android.db.RoomDB +import com.innoprog.android.feature.profile.common.ProfileCompanyResponse +import com.innoprog.android.feature.profile.common.ProfileResponse import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileCompanyEntity import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileEntity import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileApi -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany @@ -40,7 +40,7 @@ class ProfileInfoRepoImpl @Inject constructor( } ApiConstants.SUCCESS_CODE -> { - with(response as ProfileResponse) { + with(response) { val result = mapToProfile(this) emit(Resource.Success(result)) } @@ -69,7 +69,7 @@ class ProfileInfoRepoImpl @Inject constructor( } ApiConstants.SUCCESS_CODE -> { - with(response as ProfileCompanyResponse) { + with(response) { val result = mapToProfileCompany(this) emit(Resource.Success(result)) } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index 2fe0d05b..e1b87a9e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,5 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.network +import com.innoprog.android.feature.profile.common.ProfileCompanyResponse +import com.innoprog.android.feature.profile.common.ProfileResponse import retrofit2.http.GET interface ProfileApi { From 5a3234dfa6531c871b3231533d1c96f69de97b0b Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Thu, 20 Jun 2024 00:40:15 +0300 Subject: [PATCH 16/40] add domain --- .../domain/EditProfileCompanyUseCase.kt | 2 +- .../editingprofile/domain/EditProfileUseCase.kt | 5 ++--- .../domain/impl/EditProfileCompanyUseCaseImpl.kt | 16 ++++++++++++++-- .../domain/impl/EditProfileUseCaseImpl.kt | 15 +++++++++++++-- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt index 0f016e02..9b4796e2 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileCompanyUseCase.kt @@ -5,5 +5,5 @@ import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface EditProfileCompanyUseCase { - suspend fun editProfileCompany(): Flow> + suspend fun editProfileCompany(name: String, url: String, role: String): Flow> } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt index 92233c07..6bca2eb5 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/EditProfileUseCase.kt @@ -5,6 +5,5 @@ import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface EditProfileUseCase { - suspend fun editProfile(): Flow> - -} \ No newline at end of file + suspend fun editProfile(name: String, about: String): Flow> +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt index 6f9f145e..52b21ce9 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileCompanyUseCaseImpl.kt @@ -1,4 +1,16 @@ package com.innoprog.android.feature.profile.editingprofile.domain.impl -class EditProfileCompanyUseCaseImpl { -} \ No newline at end of file +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileCompanyUseCase +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class EditProfileCompanyUseCaseImpl @Inject constructor(private val repository: EditProfileInfoRepo) : + EditProfileCompanyUseCase { + + override suspend fun editProfileCompany(name: String, url: String, role: String): Flow> { + return repository.editProfileCompany(name, url, role) + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt index 2d4724a7..f2f3b35b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/domain/impl/EditProfileUseCaseImpl.kt @@ -1,4 +1,15 @@ package com.innoprog.android.feature.profile.editingprofile.domain.impl -class EditProfileUseCaseImpl { -} \ No newline at end of file +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo +import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileUseCase +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.util.Resource +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class EditProfileUseCaseImpl @Inject constructor(val repository: EditProfileInfoRepo): EditProfileUseCase { + + override suspend fun editProfile(name: String, about: String): Flow> { + return repository.editProfile(name, about) + } +} From 1653cd172d041706144551b6c17088220ca76f51 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Thu, 20 Jun 2024 16:25:59 +0300 Subject: [PATCH 17/40] add presentation --- .../data/impl/EditProfileInfoRepoImpl.kt | 92 +++++++++------- .../editingprofile/data/network/Request.kt | 6 + .../data/network/RetrofitClient.kt | 47 ++++++++ .../editingprofile/di/EditingProfileModule.kt | 11 +- .../presentation/EditingProfileFragment.kt | 104 +++++++++++++++++- .../presentation/EditingProfileViewModel.kt | 63 ++++++++++- .../data/impl/ProfileInfoRepoImpl.kt | 4 +- .../android/network/data/ApiConstants.kt | 4 +- .../android/network/data/NetworkClient.kt | 5 + 9 files changed, 287 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/Request.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/RetrofitClient.kt create mode 100644 app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt index 79218e57..2985383b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt @@ -1,14 +1,16 @@ package com.innoprog.android.feature.profile.editingprofile.data.impl +import com.innoprog.android.db.RoomDB import com.innoprog.android.feature.profile.common.ProfileCompanyResponse import com.innoprog.android.feature.profile.common.ProfileResponse -import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileApi -import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileBody -import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileCompanyBody +import com.innoprog.android.feature.profile.editingprofile.data.network.Request import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo +import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileCompanyEntity +import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileEntity import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.network.data.ApiConstants +import com.innoprog.android.network.data.NetworkClient import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow @@ -16,52 +18,50 @@ import kotlinx.coroutines.flow.flow import javax.inject.Inject class EditProfileInfoRepoImpl @Inject constructor( - private val network: EditingProfileApi + private val network: NetworkClient, + private val roomDB: RoomDB + ) : EditProfileInfoRepo { override suspend fun editProfile(name: String, about: String): Flow> = flow { - val editingProfileBody = EditingProfileBody(name, about) - val response = network.editProfile(editingProfileBody) - - when (response.resultCode) { - ApiConstants.NO_INTERNET_CONNECTION_CODE -> { - emit(Resource.Error(ErrorType.NO_CONNECTION)) - } + val apiResponse = + network.doRequest(Request.PutProfile) - ApiConstants.SUCCESS_CODE -> { - with(response) { - val result = mapToProfile(this) - emit(Resource.Success(result)) - } - } - - else -> { - emit(Resource.Error(ErrorType.BAD_REQUEST)) - } - } + if (apiResponse is ProfileResponse && apiResponse.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(mapToProfile(apiResponse))) + roomDB.profileDao().saveProfile( + ProfileEntity( + userId = apiResponse.userId, + name = apiResponse.name, + about = apiResponse.about, + communicationChannels = apiResponse.communicationChannels, + authorities = apiResponse.authorities + ) + ) + } else + emit(Resource.Error(getErrorType(apiResponse.resultCode))) } - override suspend fun editProfileCompany(name: String, url: String, role: String): Flow> = flow { - val editingProfileBody = EditingProfileCompanyBody(name, url, role) - val response = network.editProfileCompany(editingProfileBody) - - when (response.resultCode) { - ApiConstants.NO_INTERNET_CONNECTION_CODE -> { - emit(Resource.Error(ErrorType.NO_CONNECTION)) - } - - ApiConstants.SUCCESS_CODE -> { - with(response) { - val result = mapToProfileCompany(this) - emit(Resource.Success(result)) - } - } - - else -> { - emit(Resource.Error(ErrorType.BAD_REQUEST)) - } - } + override suspend fun editProfileCompany( + name: String, + url: String, + role: String + ): Flow> = flow { + val response = network.doRequest(Request.PutProfileCompany) + if (response is ProfileCompanyResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(mapToProfileCompany(response))) + roomDB.profileCompanyDao().saveProfileCompany( + ProfileCompanyEntity( + id = response.id, + userId = response.userId, + name = response.name, + url = response.url, + role = response.role + ) + ) + } else + emit(Resource.Error(getErrorType(response.resultCode))) } private fun mapToProfile(response: ProfileResponse): Profile { @@ -83,4 +83,12 @@ class EditProfileInfoRepoImpl @Inject constructor( response.role ) } + + private fun getErrorType(code: Int): ErrorType = when (code) { + ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION + ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST + ApiConstants.CAPTCHA_REQUIRED -> ErrorType.CAPTCHA_REQUIRED + ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND + else -> ErrorType.UNEXPECTED + } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/Request.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/Request.kt new file mode 100644 index 00000000..addb85cf --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/Request.kt @@ -0,0 +1,6 @@ +package com.innoprog.android.feature.profile.editingprofile.data.network + +sealed interface Request { + data object PutProfile : Request + data object PutProfileCompany : Request +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/RetrofitClient.kt new file mode 100644 index 00000000..7d6afa4a --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/network/RetrofitClient.kt @@ -0,0 +1,47 @@ +package com.innoprog.android.feature.profile.editingprofile.data.network + +import com.innoprog.android.network.data.ApiConstants +import com.innoprog.android.network.data.NetworkClient +import com.innoprog.android.network.data.Response +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import retrofit2.HttpException +import javax.inject.Inject + +class RetrofitClient @Inject constructor( + private val service: EditingProfileApi +) : NetworkClient { + + override suspend fun doRequest(dto: Any): Response { + + var response = Response() + + return withContext(Dispatchers.IO) { + try { + response = when (dto) { + + is Request.PutProfile -> { + val body = EditingProfileBody(name = "actual_name", about = "actual_about") + service.editProfile(body = body) + } + + is Request.PutProfileCompany -> { + val body = EditingProfileCompanyBody( + name = "actual_name", + url = "actual_url", + role = "actual_role" + ) + service.editProfileCompany(body = body) + } + + else -> { + throw IllegalArgumentException("Unsupported request type") + } + } + response.apply { resultCode = ApiConstants.SUCCESS_CODE } + } catch (exception: HttpException) { + response.apply { resultCode = exception.code() } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt index 1a5f04d4..f79791ac 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/di/EditingProfileModule.kt @@ -2,21 +2,25 @@ package com.innoprog.android.feature.profile.editingprofile.di import androidx.lifecycle.ViewModel import com.innoprog.android.di.ViewModelKey -import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileApi import com.innoprog.android.feature.profile.editingprofile.data.impl.EditProfileInfoRepoImpl +import com.innoprog.android.feature.profile.editingprofile.data.network.EditingProfileApi +import com.innoprog.android.feature.profile.editingprofile.data.network.RetrofitClient import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileCompanyUseCase import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileInfoRepo import com.innoprog.android.feature.profile.editingprofile.domain.EditProfileUseCase import com.innoprog.android.feature.profile.editingprofile.domain.impl.EditProfileCompanyUseCaseImpl import com.innoprog.android.feature.profile.editingprofile.domain.impl.EditProfileUseCaseImpl import com.innoprog.android.feature.profile.editingprofile.presentation.EditingProfileViewModel +import com.innoprog.android.network.data.NetworkClient import dagger.Binds import dagger.Module import dagger.Provides import dagger.multibindings.IntoMap import retrofit2.Retrofit -@Module +@Module( + includes = [EditingProfileModule.EditProfileApiModule::class] +) interface EditingProfileModule { @IntoMap @@ -33,6 +37,9 @@ interface EditingProfileModule { @Binds fun bindEditProfileCompanyUseCase(impl: EditProfileCompanyUseCaseImpl): EditProfileCompanyUseCase + @Binds + fun bindNetworkClient(impl: RetrofitClient): NetworkClient + @Module class EditProfileApiModule { @Provides diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt index 82055e83..cd7d8c0d 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt @@ -1,6 +1,7 @@ package com.innoprog.android.feature.profile.editingprofile.presentation import android.os.Bundle +import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,13 +10,26 @@ import com.innoprog.android.R import com.innoprog.android.base.BaseFragment import com.innoprog.android.base.BaseViewModel import com.innoprog.android.databinding.FragmentEditingProfileBinding +import com.innoprog.android.di.AppComponentHolder import com.innoprog.android.di.ScreenComponent import com.innoprog.android.feature.profile.editingprofile.di.DaggerEditingProfileComponent +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileCompanyScreenState +import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileScreenState +import com.innoprog.android.feature.projects.projectdetails.presentation.TextChangedListener class EditingProfileFragment : BaseFragment() { override val viewModel by injectViewModel() - override fun diComponent(): ScreenComponent = DaggerEditingProfileComponent.builder().build() + + override fun diComponent(): ScreenComponent { + val appComponent = AppComponentHolder.getComponent() + return DaggerEditingProfileComponent + .builder() + .appComponent(appComponent) + .build() + } override fun createBinding( inflater: LayoutInflater, @@ -26,8 +40,78 @@ class EditingProfileFragment : BaseFragment + render(state) + } + + viewModel.uiStateCompany.observe(viewLifecycleOwner) { state -> + renderCompany(state) + } + } + + private fun render(screenState: ProfileScreenState) { + when (screenState) { + is ProfileScreenState.Content -> { + fillViews(screenState.profileInfo) + } + + is ProfileScreenState.Error -> { + showError() + } + } + } + + private fun renderCompany(screenState: ProfileCompanyScreenState) { + when (screenState) { + is ProfileCompanyScreenState.Content -> { + fillViewsCompany(screenState.profileCompany) + } + + is ProfileCompanyScreenState.Error -> { + showErrorCompanyInfo() + } + } + } + + private fun fillViews(profile: Profile) { + with(binding) { + inputFIO.setText(profile.name) + inputAboutMe.setText(profile.about) + viewModel.editProfile(profile.name, profile.about) + } + } + + private fun showError() { + with(binding) { + inputFIO.setText("") + inputAboutMe.setText("") + } + } + + private fun fillViewsCompany(company: ProfileCompany) { + with(binding) { + inputCompanyName.setText(company.name) + inputJobTitle.setText(company.role) + inputLinkToWebSite.setText(company.url) + viewModel.editProfileCompany(company.name, company.url, company.role) + } + } + + private fun showErrorCompanyInfo() { + with(binding) { + inputCompanyName.setText("") + inputJobTitle.setText("") + inputLinkToWebSite.setText("") + } } private fun initButton() { @@ -57,4 +141,22 @@ class EditingProfileFragment : BaseFragment() + val uiState: LiveData = _uiState + + private val _uiStateCompany = MutableLiveData() + val uiStateCompany: LiveData = _uiStateCompany + + fun editProfile(name: String, about: String) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + editProfileUseCase.editProfile(name, about).collect { response -> + when (response) { + is Resource.Success -> { + _uiState.postValue(ProfileScreenState.Content(response.data)) + } + + is Resource.Error -> { + _uiState.postValue(ProfileScreenState.Error(response.errorType)) + } + } + } + }.onFailure { + _uiState.postValue(ProfileScreenState.Error(type = ErrorType.NO_CONNECTION)) + } + } + } + + fun editProfileCompany(name: String, url: String, role: String) { + viewModelScope.launch(Dispatchers.IO) { + runCatching { + editProfileCompanyUseCase.editProfileCompany(name, url, role).collect { response -> + when (response) { + is Resource.Success -> { + _uiStateCompany.postValue(ProfileCompanyScreenState.Content(response.data)) + } + + is Resource.Error -> { + _uiStateCompany.postValue(ProfileCompanyScreenState.Error(response.errorType)) + } + } + } + }.onFailure { + _uiStateCompany.postValue(ProfileCompanyScreenState.Error(type = ErrorType.NO_CONNECTION)) + } + } + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index 579ba68c..a912e0cd 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -35,7 +35,7 @@ class ProfileInfoRepoImpl @Inject constructor( ) ) when (response.resultCode) { - ApiConstants.NO_INTERNET_CONNECTION_CODE -> { + ApiConstants.NO_CONNECTION -> { emit(Resource.Error(ErrorType.NO_CONNECTION)) } @@ -64,7 +64,7 @@ class ProfileInfoRepoImpl @Inject constructor( ) ) when (response.resultCode) { - ApiConstants.NO_INTERNET_CONNECTION_CODE -> { + ApiConstants.NO_CONNECTION -> { emit(Resource.Error(ErrorType.NO_CONNECTION)) } diff --git a/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt b/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt index b6d40c23..5e54a938 100644 --- a/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt +++ b/app/src/main/java/com/innoprog/android/network/data/ApiConstants.kt @@ -6,6 +6,8 @@ object ApiConstants { const val READ_TIMEOUT = 30 const val SUCCESS_CODE = 200 - const val NO_INTERNET_CONNECTION_CODE = -1 const val BAD_REQUEST_CODE = 400 + const val NO_CONNECTION = -1 + const val CAPTCHA_REQUIRED = 403 + const val NOT_FOUND = 404 } diff --git a/app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt b/app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt new file mode 100644 index 00000000..1cb7115c --- /dev/null +++ b/app/src/main/java/com/innoprog/android/network/data/NetworkClient.kt @@ -0,0 +1,5 @@ +package com.innoprog.android.network.data + +interface NetworkClient { + suspend fun doRequest(dto: Any): Response +} From 6ff0c80c834bef3753858307c7938e4e1c6c9033 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Fri, 28 Jun 2024 15:38:54 +0300 Subject: [PATCH 18/40] add navigation --- .../presentation/EditingProfileFragment.kt | 113 ++++++++++++++---- .../presentation/EditingProfileViewModel.kt | 4 + .../presentation/BottomSheetProfile.kt | 24 ++-- .../presentation/ProfileFragment.kt | 8 +- app/src/main/res/navigation/app_nav_graph.xml | 11 +- 5 files changed, 120 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt index cd7d8c0d..4a1efe9a 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt @@ -1,10 +1,12 @@ package com.innoprog.android.feature.profile.editingprofile.presentation +import android.content.Context.INPUT_METHOD_SERVICE import android.os.Bundle import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager import androidx.core.content.ContextCompat import com.innoprog.android.R import com.innoprog.android.base.BaseFragment @@ -15,6 +17,7 @@ import com.innoprog.android.di.ScreenComponent import com.innoprog.android.feature.profile.editingprofile.di.DaggerEditingProfileComponent import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.feature.profile.profiledetails.presentation.BottomSheetProfileArgs.Companion.fromBundle import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileCompanyScreenState import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileScreenState import com.innoprog.android.feature.projects.projectdetails.presentation.TextChangedListener @@ -23,6 +26,13 @@ class EditingProfileFragment : BaseFragment() + private val user by lazy { + arguments?.let { args -> + EditingProfileFragmentDirections.fromBundle(args).userId + } + } + + override fun diComponent(): ScreenComponent { val appComponent = AppComponentHolder.getComponent() return DaggerEditingProfileComponent @@ -46,6 +56,12 @@ class EditingProfileFragment : BaseFragment() { @@ -23,12 +24,14 @@ class BottomSheetProfile : BaseBottomSheetFragment() return BottomSheetProfileBinding.inflate(inflater, container, false) } + private var user: Profile? = null + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initButton() - navigateTo() + user?.let { navigateTo(it.userId) } } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -48,25 +51,22 @@ class BottomSheetProfile : BaseBottomSheetFragment() } } - private fun navigateTo() { + private fun navigateTo(userId: String) { with(binding) { editText.setOnClickListener { - findNavController().navigate( - com.innoprog.android - .R.id.action_profile_bottom_sheet_to_editingProfileFragment - ) + val direction = BottomSheetProfileDirections.actionProfileBottomSheetToEditingProfileFragment(userId) + findNavController().navigate(direction) } infoText.setOnClickListener { - findNavController().navigate(com.innoprog.android - .R.id.action_profile_bottom_sheet_to_aboutAppFragment) + val direction = BottomSheetProfileDirections.actionProfileBottomSheetToAboutAppFragment() + findNavController().navigate(direction) + } docksText.setOnClickListener { - findNavController().navigate( - com.innoprog.android - .R.id.action_profile_bottom_sheet_to_legalDocumentsFragment - ) + val direction = BottomSheetProfileDirections.actionProfileBottomSheetToLegalDocumentsFragment() + findNavController().navigate(direction) } } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index a5199231..f44daffb 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -20,6 +20,8 @@ class ProfileFragment : BaseFragment() { override val viewModel by injectViewModel() + private var user: Profile? = null + override fun diComponent(): ScreenComponent { val appComponent = AppComponentHolder.getComponent() return DaggerProfileComponent @@ -44,7 +46,7 @@ class ProfileFragment : BaseFragment() { viewModel.loadProfileCompany() - initTopBar() + user?.let { initTopBar(it.userId) } initChips() } @@ -70,9 +72,9 @@ class ProfileFragment : BaseFragment() { }) } - private fun initTopBar() { + private fun initTopBar(userId: String) { binding.topbarProfile.setRightIconClickListener { - val direction = ProfileFragmentDirections.actionProfileFragmentToProfileBottomSheet() + val direction = ProfileFragmentDirections.actionProfileFragmentToProfileBottomSheet(userId) findNavController().navigate(direction) } } diff --git a/app/src/main/res/navigation/app_nav_graph.xml b/app/src/main/res/navigation/app_nav_graph.xml index 5265fb26..bcb281f1 100644 --- a/app/src/main/res/navigation/app_nav_graph.xml +++ b/app/src/main/res/navigation/app_nav_graph.xml @@ -125,7 +125,9 @@ android:name="com.innoprog.android.feature.profile.profiledetails.presentation.BottomSheetProfile" android:label="@string/label_bottom_sheet_profile" tools:layout="@layout/bottom_sheet_profile"> - + - + @@ -171,6 +175,9 @@ android:name="com.innoprog.android.feature.profile.editingprofile.presentation.DialogForDeleteAccountFragment" android:label="DialogForDeleteAccountFragment" tools:layout="@layout/fragment_dialog_for_delete_account"> + Date: Fri, 28 Jun 2024 19:36:03 +0300 Subject: [PATCH 19/40] resolve conflicts --- .../data/impl/ProfileInfoRepoImpl.kt | 1 - .../profiledetails/data/network/RetrofitClient.kt | 1 - .../profiledetails/presentation/ProfileFragment.kt | 14 -------------- 3 files changed, 16 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index bb7a166e..e4f14405 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -24,7 +24,6 @@ class ProfileInfoRepoImpl @Inject constructor( ) : ProfileInfoRepo { override suspend fun loadProfile(): Flow> = flow { - val apiResponse = network.doRequest(Request.GetProfile) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt index a8561191..6cec0832 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt @@ -13,7 +13,6 @@ class RetrofitClient @Inject constructor( ) : NetworkClient { override suspend fun doRequest(dto: Any): Response { - var response = Response() return withContext(Dispatchers.IO) { try { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 4f839abc..3db65c4e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -74,7 +74,6 @@ class ProfileFragment : BaseFragment() { initChips() initAdapters() - Log.d("ProfileFragment", "RecyclerView initialized") } @Suppress("NAME_SHADOWING") @@ -143,7 +142,6 @@ class ProfileFragment : BaseFragment() { recyclerLikes.adapter = publicationsAdapter recyclerFavorites.adapter = publicationsAdapter } - Log.d("ProfileFragment", "Publications adapter initialized") } private fun render(screenState: ProfileScreenState) { @@ -176,40 +174,28 @@ class ProfileFragment : BaseFragment() { is ChipsScreenState.All -> { publications.clear() publications.addAll(chipsScreenState.content) - Log.d("ProfileFragment", "list size: ${publications.size}") - Log.d("ProfileFragment", "list: $publications") publicationsAdapter.notifyDataSetChanged() - Log.d("ProfileFragment", "NotifyDataSetChanged called") showAllContent() } is ChipsScreenState.Projects -> { publications.clear() publications.addAll(chipsScreenState.projects) - Log.d("ProfileFragment", "list size: ${publications.size}") - Log.d("ProfileFragment", "list: $publications") publicationsAdapter.notifyDataSetChanged() - Log.d("ProfileFragment", "NotifyDataSetChanged called") showUserProjects() } is ChipsScreenState.Ideas -> { publications.clear() publications.addAll(chipsScreenState.ideas) - Log.d("ProfileFragment", "list size: ${publications.size}") - Log.d("ProfileFragment", "list: $publications") publicationsAdapter.notifyDataSetChanged() - Log.d("ProfileFragment", "NotifyDataSetChanged called") showUserIdeas() } is ChipsScreenState.Liked -> { publications.clear() publications.addAll(chipsScreenState.liked) - Log.d("ProfileFragment", "list size: ${publications.size}") - Log.d("ProfileFragment", "list: $publications") publicationsAdapter.notifyDataSetChanged() - Log.d("ProfileFragment", "NotifyDataSetChanged called") showUserLiked() } From 4fb41db213fd2fdb82f30472297e2ae3ab4e4900 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Fri, 28 Jun 2024 23:14:13 +0300 Subject: [PATCH 20/40] add plugin --- app/build.gradle.kts | 4 ++++ .../presentation/EditingProfileFragment.kt | 17 +++++++++-------- .../presentation/EditingProfileViewModel.kt | 4 ---- .../profiledetails/domain/models/Profile.kt | 6 +++++- .../presentation/BottomSheetProfile.kt | 1 + build.gradle.kts | 1 + gradle/libs.versions.toml | 2 +- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2040bea1..cd706193 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,9 +3,12 @@ plugins { alias(libs.plugins.jetbrainsKotlinAndroid) alias(libs.plugins.ksp) alias(libs.plugins.navigation.safeargs) + alias(libs.plugins.kotlinParcelize) + } android { + namespace = "com.innoprog.android" compileSdk = libs.versions.compileSdk.get().toInt() @@ -75,4 +78,5 @@ dependencies { implementation(project(":uikit")) + } \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt index 7711216b..a75cf5ef 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt @@ -1,6 +1,8 @@ package com.innoprog.android.feature.profile.editingprofile.presentation +import android.content.Context.INPUT_METHOD_SERVICE import android.os.Bundle +import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,20 +11,19 @@ import com.innoprog.android.R import com.innoprog.android.base.BaseFragment import com.innoprog.android.base.BaseViewModel import com.innoprog.android.databinding.FragmentEditingProfileBinding +import com.innoprog.android.di.AppComponentHolder import com.innoprog.android.di.ScreenComponent import com.innoprog.android.feature.profile.editingprofile.di.DaggerEditingProfileComponent +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany +import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileCompanyScreenState +import com.innoprog.android.feature.profile.profiledetails.presentation.ProfileScreenState +import com.innoprog.android.feature.projects.projectdetails.presentation.TextChangedListener class EditingProfileFragment : BaseFragment() { override val viewModel by injectViewModel() - private val user by lazy { - arguments?.let { args -> - EditingProfileFragmentDirections.fromBundle(args).userId - } - } - - override fun diComponent(): ScreenComponent { val appComponent = AppComponentHolder.getComponent() return DaggerEditingProfileComponent @@ -88,7 +89,7 @@ class EditingProfileFragment : BaseFragment, val authorities: List -) +) : Parcelable diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt index 94dfd32e..7d088746 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt @@ -12,6 +12,7 @@ import androidx.navigation.fragment.findNavController import com.google.android.material.bottomsheet.BottomSheetDialog import com.innoprog.android.base.BaseBottomSheetFragment import com.innoprog.android.databinding.BottomSheetProfileBinding +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.uikit.R class BottomSheetProfile : BaseBottomSheetFragment() { diff --git a/build.gradle.kts b/build.gradle.kts index 4b69e2d1..bc2d20b7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,7 @@ plugins { alias(libs.plugins.ksp) apply false alias(libs.plugins.navigation.safeargs) apply false alias(libs.plugins.detekt) + alias(libs.plugins.kotlinParcelize) apply false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0138219d..846bbd7f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -107,4 +107,4 @@ ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } androidLibrary = { id = "com.android.library", version.ref = "agp" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } navigation-safeargs = { id = "androidx.navigation.safeargs.kotlin", version.ref = "navigationUiKtx" } - +kotlinParcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } From 8b6e56ef33047add489fac6dc7dfcd210f99ebff Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Sat, 29 Jun 2024 00:26:01 +0300 Subject: [PATCH 21/40] add args --- .../presentation/EditingProfileFragment.kt | 21 ++++++++----------- .../domain/models/CommunicationChannel.kt | 6 +++++- .../profiledetails/domain/models/Profile.kt | 6 +++--- .../domain/models/ProfileCompany.kt | 6 +++++- .../presentation/BottomSheetProfile.kt | 15 ++++++++----- .../presentation/ProfileFragment.kt | 20 ++++++++++++------ .../presentation/ProfileViewModel.kt | 1 + app/src/main/res/navigation/app_nav_graph.xml | 19 +++++++++++------ 8 files changed, 60 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt index a75cf5ef..3f483514 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/presentation/EditingProfileFragment.kt @@ -1,12 +1,12 @@ package com.innoprog.android.feature.profile.editingprofile.presentation -import android.content.Context.INPUT_METHOD_SERVICE import android.os.Bundle import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat +import androidx.navigation.fragment.navArgs import com.innoprog.android.R import com.innoprog.android.base.BaseFragment import com.innoprog.android.base.BaseViewModel @@ -66,9 +66,12 @@ class EditingProfileFragment : BaseFragment { - fillViews(screenState.profileInfo) + fillViews(userInfo) } is ProfileScreenState.Error -> { @@ -78,9 +81,12 @@ class EditingProfileFragment : BaseFragment { - fillViewsCompany(screenState.profileCompany) + fillViewsCompany(userCompany) } is ProfileCompanyScreenState.Error -> { @@ -185,15 +191,6 @@ class EditingProfileFragment : BaseFragment, val authorities: List -) : Parcelable +): Parcelable diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/ProfileCompany.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/ProfileCompany.kt index 9486c4eb..efaaa426 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/ProfileCompany.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/ProfileCompany.kt @@ -1,9 +1,13 @@ package com.innoprog.android.feature.profile.profiledetails.domain.models +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize class ProfileCompany( val id: String, val userId: String, val name: String, val url: String, val role: String -) +):Parcelable diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt index 7d088746..5c5d5c14 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/BottomSheetProfile.kt @@ -9,10 +9,13 @@ import android.view.View import android.view.ViewGroup import android.view.Window import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs import com.google.android.material.bottomsheet.BottomSheetDialog import com.innoprog.android.base.BaseBottomSheetFragment import com.innoprog.android.databinding.BottomSheetProfileBinding +import com.innoprog.android.feature.profile.editingprofile.presentation.EditingProfileFragmentArgs import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.uikit.R class BottomSheetProfile : BaseBottomSheetFragment() { @@ -24,14 +27,16 @@ class BottomSheetProfile : BaseBottomSheetFragment() return BottomSheetProfileBinding.inflate(inflater, container, false) } - private var user: Profile? = null - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + val infoArgs: EditingProfileFragmentArgs by navArgs() + val userInfo = infoArgs.user + val company = infoArgs.userCompany + initButton() - user?.let { navigateTo(it.userId) } + navigateTo(userInfo, company) } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -51,10 +56,10 @@ class BottomSheetProfile : BaseBottomSheetFragment() } } - private fun navigateTo(userId: String) { + private fun navigateTo(user: Profile, userCompany: ProfileCompany) { with(binding) { editText.setOnClickListener { - val direction = BottomSheetProfileDirections.actionProfileBottomSheetToEditingProfileFragment(userId) + val direction = BottomSheetProfileDirections.actionProfileBottomSheetToEditingProfileFragment(user, userCompany) findNavController().navigate(direction) } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index f44daffb..f25668a2 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -21,6 +21,7 @@ class ProfileFragment : BaseFragment() { override val viewModel by injectViewModel() private var user: Profile? = null + private var company: ProfileCompany? = null override fun diComponent(): ScreenComponent { val appComponent = AppComponentHolder.getComponent() @@ -46,18 +47,20 @@ class ProfileFragment : BaseFragment() { viewModel.loadProfileCompany() - user?.let { initTopBar(it.userId) } - initChips() } private fun observeData() { viewModel.uiState.observe(viewLifecycleOwner) { state -> render(state) + user = (state as? ProfileScreenState.Content)?.profileInfo + user?.let { company?.let { it1 -> initTopBar(it, it1) } } } viewModel.uiStateCompany.observe(viewLifecycleOwner) { state -> renderCompany(state) + company = (state as? ProfileCompanyScreenState.Content)?.profileCompany + user?.let { company?.let { it1 -> initTopBar(it, it1) } } } } @@ -72,10 +75,15 @@ class ProfileFragment : BaseFragment() { }) } - private fun initTopBar(userId: String) { - binding.topbarProfile.setRightIconClickListener { - val direction = ProfileFragmentDirections.actionProfileFragmentToProfileBottomSheet(userId) - findNavController().navigate(direction) + private fun initTopBar(user: Profile, company: ProfileCompany) { + if (user != null && company != null) { + binding.topbarProfile.setRightIconClickListener { + val direction = ProfileFragmentDirections.actionProfileFragmentToProfileBottomSheet( + user, + company + ) + findNavController().navigate(direction) + } } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 1554ed66..af958c09 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -78,4 +78,5 @@ class ProfileViewModel @Inject constructor( } } } + } diff --git a/app/src/main/res/navigation/app_nav_graph.xml b/app/src/main/res/navigation/app_nav_graph.xml index bcb281f1..84e1e2c6 100644 --- a/app/src/main/res/navigation/app_nav_graph.xml +++ b/app/src/main/res/navigation/app_nav_graph.xml @@ -126,8 +126,12 @@ android:label="@string/label_bottom_sheet_profile" tools:layout="@layout/bottom_sheet_profile"> + android:name="user" + app:argType="com.innoprog.android.feature.profile.profiledetails.domain.models.Profile" /> + + + android:name="user" + app:argType="com.innoprog.android.feature.profile.profiledetails.domain.models.Profile" /> + @@ -176,8 +183,8 @@ android:label="DialogForDeleteAccountFragment" tools:layout="@layout/fragment_dialog_for_delete_account"> + android:name="userCompany" + app:argType="com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany" /> Date: Sat, 29 Jun 2024 00:58:09 +0300 Subject: [PATCH 22/40] fix after detekt --- .../data/impl/ChipsProfileRepoImpl.kt | 15 ++++++++++----- .../data/impl/ProfileInfoRepoImpl.kt | 6 ++++-- .../presentation/ProfileFragment.kt | 4 ---- .../presentation/ProfileViewModel.kt | 3 +-- config/detekt/detekt.yml | 12 ++++++------ 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index b2a4f08f..9262c968 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -23,8 +23,9 @@ class ChipsProfileRepoImpl @Inject constructor( if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(response.results.map { it.mapToDomain() })) - } else + } else { emit(Resource.Error(getErrorType(response.resultCode))) + } } } @@ -40,8 +41,9 @@ class ChipsProfileRepoImpl @Inject constructor( it.mapToDomain() as FeedWrapper.News } emit(Resource.Success(projects)) - } else + } else { emit(Resource.Error(getErrorType(response.resultCode))) + } } } @@ -57,8 +59,9 @@ class ChipsProfileRepoImpl @Inject constructor( it.mapToDomain() as FeedWrapper.Idea } emit(Resource.Success(ideas)) - } else + } else { emit(Resource.Error(getErrorType(response.resultCode))) + } } } @@ -68,8 +71,9 @@ class ChipsProfileRepoImpl @Inject constructor( if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(response.results.map { it.mapToDomain() })) - } else + } else { emit(Resource.Error(getErrorType(response.resultCode))) + } } } @@ -79,8 +83,9 @@ class ChipsProfileRepoImpl @Inject constructor( if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(response.results.map { it.mapToDomain() })) - } else + } else { emit(Resource.Error(getErrorType(response.resultCode))) + } } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index e4f14405..befa5084 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -38,8 +38,9 @@ class ProfileInfoRepoImpl @Inject constructor( authorities = apiResponse.authorities ) ) - } else + } else { emit(Resource.Error(getErrorType(apiResponse.resultCode))) + } } override suspend fun loadProfileCompany(): Flow> = flow { @@ -55,8 +56,9 @@ class ProfileInfoRepoImpl @Inject constructor( role = response.role ) ) - } else + } else { emit(Resource.Error(getErrorType(response.resultCode))) + } } private fun mapToProfile(response: ProfileResponse): Profile { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 3db65c4e..ed7b79f5 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -2,7 +2,6 @@ package com.innoprog.android.feature.profile.profiledetails.presentation import android.annotation.SuppressLint import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -202,10 +201,7 @@ class ProfileFragment : BaseFragment() { is ChipsScreenState.Favorites -> { publications.clear() publications.addAll(chipsScreenState.favorites) - Log.d("ProfileFragment", "list size: ${publications.size}") - Log.d("ProfileFragment", "list: $publications") publicationsAdapter.notifyDataSetChanged() - Log.d("ProfileFragment", "NotifyDataSetChanged called") showUserFavorites() } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 6bde09a9..74a785b3 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -104,7 +104,7 @@ class ProfileViewModel @Inject constructor( } } }.onFailure { - _chipsUiState.postValue((ChipsScreenState.Error(type = ErrorType.NO_CONNECTION))) + _chipsUiState.postValue(ChipsScreenState.Error(ErrorType.NO_CONNECTION)) } } } @@ -112,7 +112,6 @@ class ProfileViewModel @Inject constructor( fun loadChipIdeas(type: String, authorId: String) { viewModelScope.launch(Dispatchers.IO) { runCatching { - chipsInteractor.getIdeas(type, authorId).collect { response -> when (response) { is Resource.Success -> { diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index d9c838cb..d6fa8a05 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -81,7 +81,7 @@ complexity: threshold: 15 CyclomaticComplexMethod: active: true - threshold: 10 + threshold: 13 ignoreSingleWhenExpression: true ignoreSimpleWhenEntries: true ignoreNestingFunctions: false @@ -90,17 +90,17 @@ complexity: active: true ignoredLabels: [ ] LargeClass: - active: true + active: false threshold: 200 LongMethod: active: true - threshold: 40 + threshold: 60 excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] ignoreAnnotated: [ "Composable" ] LongParameterList: active: true functionThreshold: 6 - constructorThreshold: 7 + constructorThreshold: 28 ignoreDefaultParameters: true ignoreDataClasses: true ignoreAnnotated: [ "Inject", "InjectConstructor", "Composable" ] @@ -116,7 +116,7 @@ complexity: ReplaceSafeCallChainWithRun: active: false StringLiteralDuplication: - active: true + active: false threshold: 3 ignoreAnnotation: true excludeStringsWithLessThan5Characters: true @@ -295,7 +295,7 @@ formatting: active: true autoCorrect: true MultiLineIfElse: - active: true + active: false autoCorrect: true # Правило выключено, потому что удобно оставлять пустую строчку # перед закрывающей скобкой класса From 9e092c28e9ff94bbca0aa6e4f4c0385af68ac13f Mon Sep 17 00:00:00 2001 From: Cdarius Date: Sat, 6 Jul 2024 13:44:54 +0300 Subject: [PATCH 23/40] Add examples of common methods, fix item_news.xml guideline distance, move setOnClickListener to onCreateViewHolder method, resolve merge conflict --- .../data/impl/ChipsProfileRepoImpl.kt | 26 +++++++---- .../data/impl/ProfileInfoRepoImpl.kt | 8 ++-- .../profiledetails/domain/ChipsInteractor.kt | 1 - .../domain/impl/ChipsInteractorImpl.kt | 1 - .../presentation/ProfileViewModel.kt | 43 +++++++++++++------ .../adapter/PublicationsRecyclerAdapter.kt | 13 +++--- app/src/main/res/layout/item_news.xml | 3 +- 7 files changed, 59 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index 9262c968..270c7113 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -7,6 +7,7 @@ import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRe import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient +import com.innoprog.android.network.data.Response import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow @@ -66,8 +67,15 @@ class ChipsProfileRepoImpl @Inject constructor( } override suspend fun getLikes(pageSize: Int): Flow>> { + return getResult>( + getResponse = { network.doRequest(Request.GetLikes(pageSize)) }, + mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } + ) + } + + override suspend fun getFavorites(pageSize: Int): Flow>> { return flow { - val response = network.doRequest(Request.GetLikes(pageSize)) + val response = network.doRequest(Request.GetFavorites(pageSize)) if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(response.results.map { it.mapToDomain() })) @@ -77,12 +85,14 @@ class ChipsProfileRepoImpl @Inject constructor( } } - override suspend fun getFavorites(pageSize: Int): Flow>> { + private inline fun getResult( + crossinline getResponse: suspend () -> Response, + crossinline mapToDomain: (Data) -> Domain + ): Flow> { return flow { - val response = network.doRequest(Request.GetFavorites(pageSize)) - - if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - emit(Resource.Success(response.results.map { it.mapToDomain() })) + val response = getResponse() + if (response is Data && response.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(mapToDomain(response))) } else { emit(Resource.Error(getErrorType(response.resultCode))) } @@ -90,9 +100,9 @@ class ChipsProfileRepoImpl @Inject constructor( } private fun getErrorType(code: Int): ErrorType = when (code) { - ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION + ApiConstants.NO_INTERNET_CONNECTION_CODE -> ErrorType.NO_CONNECTION ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST - ApiConstants.CAPTCHA_REQUIRED -> ErrorType.CAPTCHA_REQUIRED + ApiConstants.FORBIDDEN -> ErrorType.CAPTCHA_REQUIRED ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND else -> ErrorType.UNEXPECTED } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index befa5084..f7f517ba 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -20,12 +20,10 @@ import javax.inject.Inject class ProfileInfoRepoImpl @Inject constructor( private val network: NetworkClient, private val roomDB: RoomDB - ) : ProfileInfoRepo { override suspend fun loadProfile(): Flow> = flow { - val apiResponse = - network.doRequest(Request.GetProfile) + val apiResponse = network.doRequest(Request.GetProfile) if (apiResponse is ProfileResponse && apiResponse.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(mapToProfile(apiResponse))) @@ -82,9 +80,9 @@ class ProfileInfoRepoImpl @Inject constructor( } private fun getErrorType(code: Int): ErrorType = when (code) { - ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION + ApiConstants.NO_INTERNET_CONNECTION_CODE -> ErrorType.NO_CONNECTION ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST - ApiConstants.CAPTCHA_REQUIRED -> ErrorType.CAPTCHA_REQUIRED + ApiConstants.FORBIDDEN -> ErrorType.CAPTCHA_REQUIRED ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND else -> ErrorType.UNEXPECTED } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt index a4e58f69..494a3bd5 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt @@ -5,7 +5,6 @@ import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsInteractor { - suspend fun getAll(authorId: String): Flow>> suspend fun getProjects(type: String, userId: String): Flow>> suspend fun getIdeas(type: String, userId: String): Flow>> diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt index 6f27efca..c048f7cd 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -8,7 +8,6 @@ import kotlinx.coroutines.flow.Flow import javax.inject.Inject class ChipsInteractorImpl @Inject constructor(private val repo: ChipsProfileRepo) : ChipsInteractor { - override suspend fun getAll(authorId: String): Flow>> { return repo.getAll(authorId) } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 74a785b3..06da5485 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -1,15 +1,19 @@ package com.innoprog.android.feature.profile.profiledetails.presentation +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope +import com.innoprog.android.BuildConfig import com.innoprog.android.base.BaseViewModel import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import javax.inject.Inject @@ -17,8 +21,7 @@ class ProfileViewModel @Inject constructor( private val getProfileUseCase: GetProfileUseCase, private val getProfileCompanyUseCase: GetProfileCompanyUseCase, private val chipsInteractor: ChipsInteractor -) : - BaseViewModel() { +) : BaseViewModel() { private val _uiState = MutableLiveData() val uiState: LiveData = _uiState @@ -130,12 +133,18 @@ class ProfileViewModel @Inject constructor( } fun loadChipLiked(pageSize: Int) { + runSafelyUseCase>( + getUseCaseFlow = { chipsInteractor.getLikes(pageSize) } + ) { _chipsUiState.postValue(ChipsScreenState.Liked(it)) } + } + + fun loadChipFavorites(pageSize: Int) { viewModelScope.launch(Dispatchers.IO) { runCatching { - chipsInteractor.getLikes(pageSize).collect { response -> + chipsInteractor.getFavorites(pageSize).collect { response -> when (response) { is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Liked(response.data)) + _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) } is Resource.Error -> { @@ -149,23 +158,31 @@ class ProfileViewModel @Inject constructor( } } - fun loadChipFavorites(pageSize: Int) { + private inline fun runSafelyUseCase( + crossinline getUseCaseFlow: suspend () -> Flow>, + crossinline onSuccess: (D) -> Unit + ) { viewModelScope.launch(Dispatchers.IO) { runCatching { - chipsInteractor.getFavorites(pageSize).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) - } - + getUseCaseFlow().collect { result -> + when (result) { + is Resource.Success -> onSuccess(result.data) is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) + _chipsUiState.postValue(ChipsScreenState.Error(result.errorType)) } } } - }.onFailure { + }.onFailure { error -> + if (BuildConfig.DEBUG) { + Log.v(TAG, "error -> ${error.localizedMessage}") + error.printStackTrace() + } _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) } } } + + companion object { + private val TAG = ProfileViewModel::class.simpleName + } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt index e0be9cc4..03ce10ee 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt @@ -13,17 +13,16 @@ class PublicationsRecyclerAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PublicationsViewHolder { val layoutInflater = LayoutInflater.from(parent.context) - return PublicationsViewHolder(ItemNewsBinding.inflate(layoutInflater, parent, false)) + return PublicationsViewHolder(ItemNewsBinding.inflate(layoutInflater, parent, false)).apply { + itemView.setOnClickListener { + onPublicationClick.invoke(publications[bindingAdapterPosition]) + } + } } override fun onBindViewHolder(holder: PublicationsViewHolder, position: Int) { holder.bind(publications[position]) - holder.itemView.setOnClickListener { - onPublicationClick.invoke(publications[position]) - } } - override fun getItemCount(): Int { - return publications.size - } + override fun getItemCount(): Int = publications.size } diff --git a/app/src/main/res/layout/item_news.xml b/app/src/main/res/layout/item_news.xml index fca225c1..a9b32dcf 100644 --- a/app/src/main/res/layout/item_news.xml +++ b/app/src/main/res/layout/item_news.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_end="395dp" /> + app:layout_constraintGuide_begin="16dp" /> Date: Sat, 6 Jul 2024 14:32:29 +0300 Subject: [PATCH 24/40] Return detekt rules, refactoring, add marker NetworkModel for detekt --- .../profiledetails/data/dto/model/FeedDto.kt | 94 +++++++------- .../data/network/ProfileRetrofitClient.kt | 69 +++++++++++ .../data/network/RetrofitClient.kt | 65 ---------- .../profiledetails/di/ProfileModule.kt | 4 +- .../presentation/ProfileFragment.kt | 115 +++++++----------- .../innoprog/android/network/data/Response.kt | 3 + app/src/main/res/layout/fragment_profile.xml | 2 +- app/src/main/res/values/strings.xml | 8 ++ config/detekt/detekt.yml | 14 +-- .../android/uikit/InnoProgChipGroupView.kt | 2 +- 10 files changed, 184 insertions(+), 192 deletions(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt delete mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt index d0ee2974..1acfde03 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/FeedDto.kt @@ -6,7 +6,9 @@ import com.innoprog.android.feature.profile.profiledetails.domain.models.Attachm import com.innoprog.android.feature.profile.profiledetails.domain.models.Author import com.innoprog.android.feature.profile.profiledetails.domain.models.Company import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.network.data.NetworkModel +@NetworkModel class FeedDto( @SerializedName("id") val id: String, @@ -61,49 +63,53 @@ class CompanyDto( fun FeedDto.mapToDomain(): FeedWrapper { return when (type) { - PublicationType.NEWS.value -> { - FeedWrapper.News( - id = id, - author = Author( - id = author.id, - name = author.name, - company = Company( - name = author.company.name, - role = author.company.role - ) - ), - projectId = projectId, - title = title, - content = content, - publishedAt = publishedAt, - likesCount = likesCount, - commentsCount = commentsCount, - attachments = attachments.map { Attachment(it.id, it.filePath, it.type) }, - isLiked = isLiked, - isFavorite = isFavorite - ) - } - else -> { - FeedWrapper.Idea( - id = id, - author = Author( - id = author.id, - name = author.name, - company = Company( - name = author.company.name, - role = author.company.role - ) - ), - projectId = projectId, - title = title, - content = content, - publishedAt = publishedAt, - likesCount = likesCount, - commentsCount = commentsCount, - attachments = attachments.map { Attachment(it.id, it.filePath, it.type) }, - isLiked = isLiked, - isFavorite = isFavorite - ) - } + PublicationType.NEWS.value -> mapToNews() + else -> mapToIdea() } } + +private fun FeedDto.mapToNews(): FeedWrapper.News { + return FeedWrapper.News( + id = id, + author = Author( + id = author.id, + name = author.name, + company = Company( + name = author.company.name, + role = author.company.role + ) + ), + projectId = projectId, + title = title, + content = content, + publishedAt = publishedAt, + likesCount = likesCount, + commentsCount = commentsCount, + attachments = attachments.map { Attachment(it.id, it.filePath, it.type) }, + isLiked = isLiked, + isFavorite = isFavorite + ) +} + +private fun FeedDto.mapToIdea(): FeedWrapper.Idea { + return FeedWrapper.Idea( + id = id, + author = Author( + id = author.id, + name = author.name, + company = Company( + name = author.company.name, + role = author.company.role + ) + ), + projectId = projectId, + title = title, + content = content, + publishedAt = publishedAt, + likesCount = likesCount, + commentsCount = commentsCount, + attachments = attachments.map { Attachment(it.id, it.filePath, it.type) }, + isLiked = isLiked, + isFavorite = isFavorite + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt new file mode 100644 index 00000000..9dd146dc --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -0,0 +1,69 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +import com.innoprog.android.network.data.ApiConstants +import com.innoprog.android.network.data.NetworkClient +import com.innoprog.android.network.data.Response +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import retrofit2.HttpException +import javax.inject.Inject + +class ProfileRetrofitClient @Inject constructor( + private val service: ProfileApi +) : NetworkClient { + + override suspend fun doRequest(dto: Any): Response { + var response = Response() + return withContext(Dispatchers.IO) { + try { + response = getResponse(dto) + response.apply { resultCode = ApiConstants.SUCCESS_CODE } + } catch (exception: HttpException) { + response.apply { resultCode = exception.code() } + } + } + } + + private suspend fun getResponse(dto: Any): Response { + return when (dto) { + is Request.GetProfile -> { + service.loadProfile() + } + + is Request.GetProfileCompany -> { + service.loadProfileCompany() + } + + is Request.GetAll -> { + ChipsResponse(service.getAll(authorId = dto.authorId)) + } + + is Request.GetProjects -> { + ChipsResponse(service.getProjects(type = NEWS, authorId = dto.authorId)) + } + + is Request.GetIdeas -> { + ChipsResponse(service.getIdeas(type = IDEA, authorId = dto.authorId)) + } + + is Request.GetLikes -> { + ChipsResponse(service.getLikes(pageSize = PAGE_SIZE)) + } + + is Request.GetFavorites -> { + ChipsResponse(service.getFavorites(pageSize = PAGE_SIZE)) + } + + else -> { + throw IllegalArgumentException("Unsupported request type") + } + } + } + + companion object { + + private const val IDEA = "IDEA" + private const val NEWS = "NEWS" + private const val PAGE_SIZE = 50 + } +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt deleted file mode 100644 index 6cec0832..00000000 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RetrofitClient.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network - -import com.innoprog.android.network.data.ApiConstants -import com.innoprog.android.network.data.NetworkClient -import com.innoprog.android.network.data.Response -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import retrofit2.HttpException -import javax.inject.Inject - -class RetrofitClient @Inject constructor( - private val service: ProfileApi -) : NetworkClient { - - override suspend fun doRequest(dto: Any): Response { - var response = Response() - return withContext(Dispatchers.IO) { - try { - response = when (dto) { - is Request.GetProfile -> { - service.loadProfile() - } - - is Request.GetProfileCompany -> { - service.loadProfileCompany() - } - - is Request.GetAll -> { - ChipsResponse(service.getAll(authorId = dto.authorId)) - } - - is Request.GetProjects -> { - ChipsResponse(service.getProjects(type = NEWS, authorId = dto.authorId)) - } - - is Request.GetIdeas -> { - ChipsResponse(service.getIdeas(type = IDEA, authorId = dto.authorId)) - } - - is Request.GetLikes -> { - ChipsResponse(service.getLikes(pageSize = PAGE_SIZE)) - } - - is Request.GetFavorites -> { - ChipsResponse(service.getFavorites(pageSize = PAGE_SIZE)) - } - - else -> { - throw IllegalArgumentException("Unsupported request type") - } - } - response.apply { resultCode = ApiConstants.SUCCESS_CODE } - } catch (exception: HttpException) { - response.apply { resultCode = exception.code() } - } - } - } - - companion object { - - private const val IDEA = "IDEA" - private const val NEWS = "NEWS" - private const val PAGE_SIZE = 50 - } -} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt index b90caa74..954db979 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/di/ProfileModule.kt @@ -5,7 +5,7 @@ import com.innoprog.android.di.ViewModelKey import com.innoprog.android.feature.profile.profiledetails.data.impl.ChipsProfileRepoImpl import com.innoprog.android.feature.profile.profiledetails.data.impl.ProfileInfoRepoImpl import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileApi -import com.innoprog.android.feature.profile.profiledetails.data.network.RetrofitClient +import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileRetrofitClient import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase @@ -42,7 +42,7 @@ interface ProfileModule { fun bindGetProfileCompanyUseCase(impl: GetProfileCompanyUseCaseImpl): GetProfileCompanyUseCase @Binds - fun bindNetworkClient(impl: RetrofitClient): NetworkClient + fun bindNetworkClient(impl: ProfileRetrofitClient): NetworkClient @Binds fun bindChipsRepository(impl: ChipsProfileRepoImpl): ChipsProfileRepo diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index ed7b79f5..59d22af8 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -1,54 +1,54 @@ package com.innoprog.android.feature.profile.profiledetails.presentation -import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import androidx.navigation.fragment.findNavController +import com.innoprog.android.R import com.innoprog.android.base.BaseFragment import com.innoprog.android.base.BaseViewModel import com.innoprog.android.databinding.FragmentProfileBinding import com.innoprog.android.di.AppComponentHolder import com.innoprog.android.di.ScreenComponent +import com.innoprog.android.feature.feed.newsfeed.domain.models.PublicationType import com.innoprog.android.feature.profile.profiledetails.di.DaggerProfileComponent import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.feature.profile.profiledetails.presentation.adapter.PublicationsRecyclerAdapter -import com.innoprog.android.uikit.InnoProgChipGroupView class ProfileFragment : BaseFragment() { - override val viewModel by injectViewModel() - - private var user: Profile? = null - private var publications: ArrayList = arrayListOf() - private val publicationsAdapter: PublicationsRecyclerAdapter by lazy { PublicationsRecyclerAdapter(publications) { publication -> when (publication) { is FeedWrapper.Idea -> { val action = - ProfileFragmentDirections.actionProfileFragmentToIdeaDetailsFragment(publication.id) + ProfileFragmentDirections.actionProfileFragmentToIdeaDetailsFragment( + publication.id + ) findNavController().navigate(action) } is FeedWrapper.News -> { val action = - ProfileFragmentDirections.actionProfileFragmentToNewsDetailsFragment(publication.id) + ProfileFragmentDirections.actionProfileFragmentToNewsDetailsFragment( + publication.id + ) findNavController().navigate(action) } } } } + private var user: Profile? = null + private var publications: ArrayList = arrayListOf() override fun diComponent(): ScreenComponent { - val appComponent = AppComponentHolder.getComponent() return DaggerProfileComponent .builder() - .appComponent(appComponent) + .appComponent(AppComponentHolder.getComponent()) .build() } @@ -61,69 +61,59 @@ class ProfileFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - observeData() - viewModel.loadProfile() - viewModel.loadProfileCompany() - initTopBar() - initChips() - initAdapters() } - @Suppress("NAME_SHADOWING") private fun observeData() { viewModel.uiState.observe(viewLifecycleOwner) { state -> when (state) { is ProfileScreenState.Content -> { user = state.profileInfo render(state) - user?.let { user -> - viewModel.loadChipAll(authorId = user.userId) - } + viewModel.loadChipAll(authorId = state.profileInfo.userId) } - is ProfileScreenState.Error -> { - showError() - } + is ProfileScreenState.Error -> showError() } - viewModel.uiStateCompany.observe(viewLifecycleOwner) { state -> - renderCompany(state) + viewModel.uiStateCompany.observe(viewLifecycleOwner) { stateCompany -> + renderCompany(stateCompany) } - viewModel.chipsUiState.observe(viewLifecycleOwner) { state -> - renderChips(state) + viewModel.chipsUiState.observe(viewLifecycleOwner) { stateChips -> + renderChips(stateChips) } } } private fun initChips() { - val chipTitles = listOf(ALL_CONTENT, PROJECT, IDEAS, LIKES, FAVORITES) + val chipTitles = resources.getStringArray(R.array.profile_chips).toList() binding.chips.setChips(chipTitles) binding.chips.selectChip(INDEX_1) - binding.chips.setOnChipSelectListener(object : - InnoProgChipGroupView.OnChipSelectListener { - override fun onChipSelected(chipIndex: Int) { - user?.let { user -> - when (chipIndex) { - INDEX_1 -> viewModel.loadChipAll(authorId = user.userId) - INDEX_2 -> viewModel.loadChipProjects( - type = TYPE_NEWS, - authorId = user.userId - ) - - INDEX_3 -> viewModel.loadChipIdeas(type = TYPE_IDEA, authorId = user.userId) - INDEX_4 -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) - INDEX_5 -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) - } + binding.chips.setOnChipSelectListener { chipIndex -> + user?.let { user -> + when (chipIndex) { + INDEX_1 -> viewModel.loadChipAll(authorId = user.userId) + INDEX_2 -> viewModel.loadChipProjects( + type = PublicationType.NEWS.value, + authorId = user.userId + ) + + INDEX_3 -> viewModel.loadChipIdeas( + type = PublicationType.IDEA.value, + authorId = user.userId + ) + + INDEX_4 -> viewModel.loadChipLiked(pageSize = PAGE_SIZE) + INDEX_5 -> viewModel.loadChipFavorites(pageSize = PAGE_SIZE) } } - }) + } } private fun initTopBar() { @@ -145,13 +135,9 @@ class ProfileFragment : BaseFragment() { private fun render(screenState: ProfileScreenState) { when (screenState) { - is ProfileScreenState.Content -> { - fillViews(screenState.profileInfo) - } + is ProfileScreenState.Content -> fillViews(screenState.profileInfo) - is ProfileScreenState.Error -> { - showError() - } + is ProfileScreenState.Error -> showError() } } @@ -161,13 +147,10 @@ class ProfileFragment : BaseFragment() { fillViewsCompany(screenStateCompany.profileCompany) } - is ProfileCompanyScreenState.Error -> { - showError() - } + is ProfileCompanyScreenState.Error -> showError() } } - @SuppressLint("NotifyDataSetChanged") private fun renderChips(chipsScreenState: ChipsScreenState) { when (chipsScreenState) { is ChipsScreenState.All -> { @@ -210,18 +193,14 @@ class ProfileFragment : BaseFragment() { } private fun fillViews(profile: Profile) { - with(binding) { - name.text = profile.name - description.text = profile.about - } + binding.name.text = profile.name + binding.description.text = profile.about } private fun fillViewsCompany(company: ProfileCompany) { - with(binding) { - position.text = company.role - companyName.text = company.name - profileIn.isVisible = true - } + binding.position.text = company.role + binding.companyName.text = company.name + binding.profileIn.isVisible = true } private fun showError() { @@ -304,15 +283,7 @@ class ProfileFragment : BaseFragment() { } companion object { - - private const val ALL_CONTENT = "Всё" - private const val PROJECT = "Проекты" - private const val IDEAS = "Идеи" - private const val LIKES = "Лайкнутые" - private const val FAVORITES = "Избранное" private const val PAGE_SIZE = 10 - private const val TYPE_IDEA = "IDEA" - private const val TYPE_NEWS = "NEWS" private const val INDEX_1 = 0 private const val INDEX_2 = 1 private const val INDEX_3 = 2 diff --git a/app/src/main/java/com/innoprog/android/network/data/Response.kt b/app/src/main/java/com/innoprog/android/network/data/Response.kt index 91fbaa43..2afb6076 100644 --- a/app/src/main/java/com/innoprog/android/network/data/Response.kt +++ b/app/src/main/java/com/innoprog/android/network/data/Response.kt @@ -3,3 +3,6 @@ package com.innoprog.android.network.data open class Response { var resultCode = 0 } + +@Target(AnnotationTarget.CLASS) +annotation class NetworkModel diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 38dffd88..d74871d5 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -112,7 +112,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 54f0d997..c87d552c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -122,4 +122,12 @@ Проекты Идеи + + + Всё + Проекты + Идеи + Лайкнутые + Избранное + \ No newline at end of file diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index d6fa8a05..2915b80d 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -81,7 +81,7 @@ complexity: threshold: 15 CyclomaticComplexMethod: active: true - threshold: 13 + threshold: 10 ignoreSingleWhenExpression: true ignoreSimpleWhenEntries: true ignoreNestingFunctions: false @@ -90,20 +90,20 @@ complexity: active: true ignoredLabels: [ ] LargeClass: - active: false + active: true threshold: 200 LongMethod: active: true - threshold: 60 + threshold: 40 excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] ignoreAnnotated: [ "Composable" ] LongParameterList: active: true functionThreshold: 6 - constructorThreshold: 28 + constructorThreshold: 7 ignoreDefaultParameters: true ignoreDataClasses: true - ignoreAnnotated: [ "Inject", "InjectConstructor", "Composable" ] + ignoreAnnotated: [ "Inject", "InjectConstructor", "Composable", "NetworkModel" ] MethodOverloading: active: true threshold: 6 @@ -116,7 +116,7 @@ complexity: ReplaceSafeCallChainWithRun: active: false StringLiteralDuplication: - active: false + active: true threshold: 3 ignoreAnnotation: true excludeStringsWithLessThan5Characters: true @@ -295,7 +295,7 @@ formatting: active: true autoCorrect: true MultiLineIfElse: - active: false + active: true autoCorrect: true # Правило выключено, потому что удобно оставлять пустую строчку # перед закрывающей скобкой класса diff --git a/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt b/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt index 6b11ee43..4959414a 100644 --- a/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt +++ b/uikit/src/main/java/com/innoprog/android/uikit/InnoProgChipGroupView.kt @@ -74,7 +74,7 @@ class InnoProgChipGroupView @JvmOverloads constructor( } } - interface OnChipSelectListener { + fun interface OnChipSelectListener { fun onChipSelected(chipIndex: Int) } From 8c44d687d21645f3ee3edb643735226d2a48334e Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Sun, 7 Jul 2024 22:33:10 +0300 Subject: [PATCH 25/40] add fun getResult & refactor delete recyclers & refactor fragment add fun runSafelyUseCase & refactor rename Request --- .../data/impl/ChipsProfileRepoImpl.kt | 62 ++++---------- .../data/impl/ProfileInfoRepoImpl.kt | 6 +- .../data/network/ProfileRetrofitClient.kt | 21 +++-- .../profiledetails/data/network/Request.kt | 11 --- .../data/network/RequestByProfile.kt | 11 +++ .../presentation/ProfileFragment.kt | 77 +++-------------- .../presentation/ProfileViewModel.kt | 83 ++++--------------- app/src/main/res/layout/fragment_profile.xml | 42 +--------- 8 files changed, 68 insertions(+), 245 deletions(-) delete mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index 270c7113..9e84a4a4 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -2,7 +2,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl import com.innoprog.android.feature.profile.profiledetails.data.dto.model.mapToDomain import com.innoprog.android.feature.profile.profiledetails.data.network.ChipsResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.Request +import com.innoprog.android.feature.profile.profiledetails.data.network.RequestByProfile import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.network.data.ApiConstants @@ -19,70 +19,44 @@ class ChipsProfileRepoImpl @Inject constructor( ) : ChipsProfileRepo { override suspend fun getAll(authorId: String): Flow>> { - return flow { - val response = network.doRequest(Request.GetAll(authorId)) - - if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - emit(Resource.Success(response.results.map { it.mapToDomain() })) - } else { - emit(Resource.Error(getErrorType(response.resultCode))) - } - } + return getResult>( + getResponse = { network.doRequest(RequestByProfile.GetAll(authorId)) }, + mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } + ) } override suspend fun getProjects( type: String, userId: String ): Flow>> { - return flow { - val response = network.doRequest(Request.GetProjects(type, userId)) - - if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val projects = response.results.map { - it.mapToDomain() as FeedWrapper.News - } - emit(Resource.Success(projects)) - } else { - emit(Resource.Error(getErrorType(response.resultCode))) - } - } + return getResult>( + getResponse = { network.doRequest(RequestByProfile.GetProjects(type, userId)) }, + mapToDomain = { response -> response.results.map { item -> item.mapToDomain() as FeedWrapper.News } } + ) } override suspend fun getIdeas( type: String, userId: String ): Flow>> { - return flow { - val response = network.doRequest(Request.GetIdeas(type, userId)) - - if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - val ideas = response.results.map { - it.mapToDomain() as FeedWrapper.Idea - } - emit(Resource.Success(ideas)) - } else { - emit(Resource.Error(getErrorType(response.resultCode))) - } - } + return getResult>( + getResponse = { network.doRequest(RequestByProfile.GetIdeas(type, userId)) }, + mapToDomain = { response -> response.results.map { item -> item.mapToDomain() as FeedWrapper.Idea } } + ) } override suspend fun getLikes(pageSize: Int): Flow>> { return getResult>( - getResponse = { network.doRequest(Request.GetLikes(pageSize)) }, + getResponse = { network.doRequest(RequestByProfile.GetLikes(pageSize)) }, mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } ) } override suspend fun getFavorites(pageSize: Int): Flow>> { - return flow { - val response = network.doRequest(Request.GetFavorites(pageSize)) - - if (response is ChipsResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - emit(Resource.Success(response.results.map { it.mapToDomain() })) - } else { - emit(Resource.Error(getErrorType(response.resultCode))) - } - } + return getResult>( + getResponse = {network.doRequest(RequestByProfile.GetFavorites(pageSize)) }, + mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } + ) } private inline fun getResult( diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index f7f517ba..45aa34fa 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -5,7 +5,7 @@ import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileCompan import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileEntity import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.Request +import com.innoprog.android.feature.profile.profiledetails.data.network.RequestByProfile import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany @@ -23,7 +23,7 @@ class ProfileInfoRepoImpl @Inject constructor( ) : ProfileInfoRepo { override suspend fun loadProfile(): Flow> = flow { - val apiResponse = network.doRequest(Request.GetProfile) + val apiResponse = network.doRequest(RequestByProfile.GetProfile) if (apiResponse is ProfileResponse && apiResponse.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(mapToProfile(apiResponse))) @@ -42,7 +42,7 @@ class ProfileInfoRepoImpl @Inject constructor( } override suspend fun loadProfileCompany(): Flow> = flow { - val response = network.doRequest(Request.GetProfileCompany) + val response = network.doRequest(RequestByProfile.GetProfileCompany) if (response is ProfileCompanyResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { emit(Resource.Success(mapToProfileCompany(response))) roomDB.profileCompanyDao().saveProfileCompany( diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 9dd146dc..51f6831b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -1,5 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.network +import com.innoprog.android.feature.feed.newsfeed.domain.models.PublicationType import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient import com.innoprog.android.network.data.Response @@ -26,31 +27,31 @@ class ProfileRetrofitClient @Inject constructor( private suspend fun getResponse(dto: Any): Response { return when (dto) { - is Request.GetProfile -> { + is RequestByProfile.GetProfile -> { service.loadProfile() } - is Request.GetProfileCompany -> { + is RequestByProfile.GetProfileCompany -> { service.loadProfileCompany() } - is Request.GetAll -> { + is RequestByProfile.GetAll -> { ChipsResponse(service.getAll(authorId = dto.authorId)) } - is Request.GetProjects -> { - ChipsResponse(service.getProjects(type = NEWS, authorId = dto.authorId)) + is RequestByProfile.GetProjects -> { + ChipsResponse(service.getProjects(type = PublicationType.NEWS.value, authorId = dto.authorId)) } - is Request.GetIdeas -> { - ChipsResponse(service.getIdeas(type = IDEA, authorId = dto.authorId)) + is RequestByProfile.GetIdeas -> { + ChipsResponse(service.getIdeas(type = PublicationType.IDEA.value, authorId = dto.authorId)) } - is Request.GetLikes -> { + is RequestByProfile.GetLikes -> { ChipsResponse(service.getLikes(pageSize = PAGE_SIZE)) } - is Request.GetFavorites -> { + is RequestByProfile.GetFavorites -> { ChipsResponse(service.getFavorites(pageSize = PAGE_SIZE)) } @@ -62,8 +63,6 @@ class ProfileRetrofitClient @Inject constructor( companion object { - private const val IDEA = "IDEA" - private const val NEWS = "NEWS" private const val PAGE_SIZE = 50 } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt deleted file mode 100644 index 4599dd1f..00000000 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/Request.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.innoprog.android.feature.profile.profiledetails.data.network - -sealed interface Request { - data object GetProfile : Request - data object GetProfileCompany : Request - data class GetAll(val authorId: String) : Request - data class GetProjects(val type: String, val authorId: String) : Request - data class GetIdeas(val type: String, val authorId: String) : Request - data class GetLikes(val pageSize: Int) : Request - data class GetFavorites(val pageSize: Int) : Request -} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt new file mode 100644 index 00000000..83dd1e06 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt @@ -0,0 +1,11 @@ +package com.innoprog.android.feature.profile.profiledetails.data.network + +sealed interface RequestByProfile { + data object GetProfile : RequestByProfile + data object GetProfileCompany : RequestByProfile + data class GetAll(val authorId: String) : RequestByProfile + data class GetProjects(val type: String, val authorId: String) : RequestByProfile + data class GetIdeas(val type: String, val authorId: String) : RequestByProfile + data class GetLikes(val pageSize: Int) : RequestByProfile + data class GetFavorites(val pageSize: Int) : RequestByProfile +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 59d22af8..b71b9f29 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -1,5 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.presentation +import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -125,11 +126,7 @@ class ProfileFragment : BaseFragment() { private fun initAdapters() { with(binding) { - recyclerAll.adapter = publicationsAdapter - recyclerProjects.adapter = publicationsAdapter - recyclerIdeas.adapter = publicationsAdapter - recyclerLikes.adapter = publicationsAdapter - recyclerFavorites.adapter = publicationsAdapter + recyclerContent.adapter = publicationsAdapter } } @@ -151,41 +148,42 @@ class ProfileFragment : BaseFragment() { } } + @SuppressLint("NotifyDataSetChanged") private fun renderChips(chipsScreenState: ChipsScreenState) { when (chipsScreenState) { is ChipsScreenState.All -> { + showContent() publications.clear() publications.addAll(chipsScreenState.content) publicationsAdapter.notifyDataSetChanged() - showAllContent() } is ChipsScreenState.Projects -> { + showContent() publications.clear() publications.addAll(chipsScreenState.projects) publicationsAdapter.notifyDataSetChanged() - showUserProjects() } is ChipsScreenState.Ideas -> { + showContent() publications.clear() publications.addAll(chipsScreenState.ideas) publicationsAdapter.notifyDataSetChanged() - showUserIdeas() } is ChipsScreenState.Liked -> { + showContent() publications.clear() publications.addAll(chipsScreenState.liked) publicationsAdapter.notifyDataSetChanged() - showUserLiked() } is ChipsScreenState.Favorites -> { + showContent() publications.clear() publications.addAll(chipsScreenState.favorites) publicationsAdapter.notifyDataSetChanged() - showUserFavorites() } is ChipsScreenState.Error -> showPlaceholder() @@ -216,68 +214,15 @@ class ProfileFragment : BaseFragment() { private fun showPlaceholder() { if (publicationsAdapter.publications.isEmpty()) { with(binding) { - recyclerAll.isVisible = false - recyclerProjects.isVisible = false - recyclerIdeas.isVisible = false - recyclerLikes.isVisible = false - recyclerFavorites.isVisible = false + recyclerContent.isVisible = false placeholderText.isVisible = true } } } - private fun showAllContent() { + private fun showContent() { with(binding) { - recyclerAll.isVisible = true - recyclerProjects.isVisible = false - recyclerIdeas.isVisible = false - recyclerLikes.isVisible = false - recyclerFavorites.isVisible = false - showPlaceholder() - } - } - - private fun showUserProjects() { - with(binding) { - recyclerAll.isVisible = false - recyclerProjects.isVisible = true - recyclerIdeas.isVisible = false - recyclerLikes.isVisible = false - recyclerFavorites.isVisible = false - showPlaceholder() - } - } - - private fun showUserIdeas() { - with(binding) { - recyclerAll.isVisible = false - recyclerProjects.isVisible = false - recyclerIdeas.isVisible = true - recyclerLikes.isVisible = false - recyclerFavorites.isVisible = false - showPlaceholder() - } - } - - private fun showUserLiked() { - with(binding) { - recyclerAll.isVisible = false - recyclerProjects.isVisible = false - recyclerIdeas.isVisible = false - recyclerLikes.isVisible = true - recyclerFavorites.isVisible = false - placeholderText.isVisible = false - showPlaceholder() - } - } - - private fun showUserFavorites() { - with(binding) { - recyclerAll.isVisible = false - recyclerProjects.isVisible = false - recyclerIdeas.isVisible = false - recyclerLikes.isVisible = false - recyclerFavorites.isVisible = true + recyclerContent.isVisible = true showPlaceholder() } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 06da5485..6ba52fa5 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -4,8 +4,8 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.innoprog.android.BuildConfig import com.innoprog.android.base.BaseViewModel +import com.innoprog.android.BuildConfig import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase @@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import javax.inject.Inject + class ProfileViewModel @Inject constructor( private val getProfileUseCase: GetProfileUseCase, private val getProfileCompanyUseCase: GetProfileCompanyUseCase, @@ -73,63 +74,21 @@ class ProfileViewModel @Inject constructor( } fun loadChipAll(authorId: String) { - viewModelScope.launch(Dispatchers.IO) { - runCatching { - chipsInteractor.getAll(authorId).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.All(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) - } - } - } - }.onFailure { - _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) - } - } + runSafelyUseCase>( + getUseCaseFlow = { chipsInteractor.getAll(authorId) } + ) { _chipsUiState.postValue(ChipsScreenState.All(it)) } } fun loadChipProjects(type: String, authorId: String) { - viewModelScope.launch(Dispatchers.IO) { - runCatching { - chipsInteractor.getProjects(type, authorId).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Projects(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) - } - } - } - }.onFailure { - _chipsUiState.postValue(ChipsScreenState.Error(ErrorType.NO_CONNECTION)) - } - } + runSafelyUseCase>( + getUseCaseFlow = { chipsInteractor.getProjects(type, authorId) } + ) { _chipsUiState.postValue(ChipsScreenState.Projects(it)) } } fun loadChipIdeas(type: String, authorId: String) { - viewModelScope.launch(Dispatchers.IO) { - runCatching { - chipsInteractor.getIdeas(type, authorId).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Ideas(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) - } - } - } - }.onFailure { - _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) - } - } + runSafelyUseCase>( + getUseCaseFlow = { chipsInteractor.getIdeas(type, authorId) } + ) { _chipsUiState.postValue(ChipsScreenState.Ideas(it)) } } fun loadChipLiked(pageSize: Int) { @@ -139,23 +98,9 @@ class ProfileViewModel @Inject constructor( } fun loadChipFavorites(pageSize: Int) { - viewModelScope.launch(Dispatchers.IO) { - runCatching { - chipsInteractor.getFavorites(pageSize).collect { response -> - when (response) { - is Resource.Success -> { - _chipsUiState.postValue(ChipsScreenState.Favorites(response.data)) - } - - is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(response.errorType)) - } - } - } - }.onFailure { - _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) - } - } + runSafelyUseCase>( + getUseCaseFlow = { chipsInteractor.getFavorites(pageSize) } + ) { _chipsUiState.postValue(ChipsScreenState.Favorites(it)) } } private inline fun runSafelyUseCase( diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index d74871d5..936f14b3 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -146,47 +146,7 @@ android:layout_height="match_parent"> - - - - - - - - Date: Sun, 7 Jul 2024 22:44:06 +0300 Subject: [PATCH 26/40] refactor sealed interfaces --- .../profiledetails/data/network/RequestByProfile.kt | 10 +++++----- .../profiledetails/presentation/ChipsScreenState.kt | 12 ++++++------ .../presentation/ProfileScreenState.kt | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt index 83dd1e06..928b08dc 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt @@ -3,9 +3,9 @@ package com.innoprog.android.feature.profile.profiledetails.data.network sealed interface RequestByProfile { data object GetProfile : RequestByProfile data object GetProfileCompany : RequestByProfile - data class GetAll(val authorId: String) : RequestByProfile - data class GetProjects(val type: String, val authorId: String) : RequestByProfile - data class GetIdeas(val type: String, val authorId: String) : RequestByProfile - data class GetLikes(val pageSize: Int) : RequestByProfile - data class GetFavorites(val pageSize: Int) : RequestByProfile + class GetAll(val authorId: String) : RequestByProfile + class GetProjects(val type: String, val authorId: String) : RequestByProfile + class GetIdeas(val type: String, val authorId: String) : RequestByProfile + class GetLikes(val pageSize: Int) : RequestByProfile + class GetFavorites(val pageSize: Int) : RequestByProfile } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt index 8caff37b..b42a8480 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt @@ -4,15 +4,15 @@ import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWra import com.innoprog.android.util.ErrorType sealed interface ChipsScreenState { - data class All(val content: List) : ChipsScreenState + class All(val content: List) : ChipsScreenState - data class Projects(val projects: List) : ChipsScreenState + class Projects(val projects: List) : ChipsScreenState - data class Ideas(val ideas: List) : ChipsScreenState + class Ideas(val ideas: List) : ChipsScreenState - data class Liked(val liked: List) : ChipsScreenState + class Liked(val liked: List) : ChipsScreenState - data class Favorites(val favorites: List) : ChipsScreenState + class Favorites(val favorites: List) : ChipsScreenState - data class Error(val type: ErrorType) : ChipsScreenState + class Error(val type: ErrorType) : ChipsScreenState } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileScreenState.kt index 35e14c7c..ae988851 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileScreenState.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileScreenState.kt @@ -5,7 +5,7 @@ import com.innoprog.android.util.ErrorType sealed interface ProfileScreenState { - data class Content(val profileInfo: Profile) : ProfileScreenState + class Content(val profileInfo: Profile) : ProfileScreenState - data class Error(val type: ErrorType) : ProfileScreenState + class Error(val type: ErrorType) : ProfileScreenState } From 0703d92a74794b457b8994a9e6d281517ea5bd3b Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Mon, 8 Jul 2024 01:10:52 +0300 Subject: [PATCH 27/40] add extensions & refactor ProfileInfoRepoImplRepo --- .../data/impl/ProfileInfoRepoImpl.kt | 26 +++---------------- .../data/network/ProfileCompanyResponse.kt | 13 ++++++++++ .../data/network/ProfileResponse.kt | 11 ++++++++ .../uikitsample/ExampleInstrumentedTest.kt | 4 +-- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index 45aa34fa..be2706d3 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -6,6 +6,8 @@ import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileEntity import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse import com.innoprog.android.feature.profile.profiledetails.data.network.RequestByProfile +import com.innoprog.android.feature.profile.profiledetails.data.network.mapToDomainCompany +import com.innoprog.android.feature.profile.profiledetails.data.network.mapToDomainUserData import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany @@ -26,7 +28,7 @@ class ProfileInfoRepoImpl @Inject constructor( val apiResponse = network.doRequest(RequestByProfile.GetProfile) if (apiResponse is ProfileResponse && apiResponse.resultCode == ApiConstants.SUCCESS_CODE) { - emit(Resource.Success(mapToProfile(apiResponse))) + emit(Resource.Success(apiResponse.mapToDomainUserData())) roomDB.profileDao().saveProfile( ProfileEntity( userId = apiResponse.userId, @@ -44,7 +46,7 @@ class ProfileInfoRepoImpl @Inject constructor( override suspend fun loadProfileCompany(): Flow> = flow { val response = network.doRequest(RequestByProfile.GetProfileCompany) if (response is ProfileCompanyResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { - emit(Resource.Success(mapToProfileCompany(response))) + emit(Resource.Success(response.mapToDomainCompany())) roomDB.profileCompanyDao().saveProfileCompany( ProfileCompanyEntity( id = response.id, @@ -59,26 +61,6 @@ class ProfileInfoRepoImpl @Inject constructor( } } - private fun mapToProfile(response: ProfileResponse): Profile { - return Profile( - response.userId, - response.name, - response.about, - response.communicationChannels, - response.authorities - ) - } - - private fun mapToProfileCompany(response: ProfileCompanyResponse): ProfileCompany { - return ProfileCompany( - response.id, - response.userId, - response.name, - response.url, - response.role - ) - } - private fun getErrorType(code: Int): ErrorType = when (code) { ApiConstants.NO_INTERNET_CONNECTION_CODE -> ErrorType.NO_CONNECTION ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt index 8982cbc2..dc189698 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileCompanyResponse.kt @@ -1,6 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import com.google.gson.annotations.SerializedName +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.network.data.Response data class ProfileCompanyResponse( @@ -15,3 +16,15 @@ data class ProfileCompanyResponse( @SerializedName("role") val role: String ) : Response() + +fun ProfileCompanyResponse.mapToDomainCompany(): ProfileCompany { + return ProfileCompany( + id = id, + userId = userId, + name = name, + url = url, + role = role + ) +} + + diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt index 7b5d8017..b426e8a3 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileResponse.kt @@ -2,6 +2,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import com.google.gson.annotations.SerializedName import com.innoprog.android.feature.profile.profiledetails.domain.models.CommunicationChannel +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.network.data.Response data class ProfileResponse( @@ -16,3 +17,13 @@ data class ProfileResponse( @SerializedName("authorities") val authorities: List ) : Response() + +fun ProfileResponse.mapToDomainUserData(): Profile { + return Profile( + userId = userId, + name = name, + about = about, + communicationChannels = communicationChannels, + authorities = authorities + ) +} diff --git a/uikit-sample/src/androidTest/java/com/innoprog/android/uikitsample/ExampleInstrumentedTest.kt b/uikit-sample/src/androidTest/java/com/innoprog/android/uikitsample/ExampleInstrumentedTest.kt index df921d50..99cef58c 100644 --- a/uikit-sample/src/androidTest/java/com/innoprog/android/uikitsample/ExampleInstrumentedTest.kt +++ b/uikit-sample/src/androidTest/java/com/innoprog/android/uikitsample/ExampleInstrumentedTest.kt @@ -1,8 +1,8 @@ package com.innoprog.android.uikitsample -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.* +import androidx.test.runner.AndroidJUnit4 +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith From 744d6d5422b93c7a2885049cb0dc89aa5629e06f Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Mon, 8 Jul 2024 09:07:34 +0300 Subject: [PATCH 28/40] add Response wrapper --- .../profiledetails/data/network/ProfileApi.kt | 15 ++++++------ .../data/network/ProfileRetrofitClient.kt | 24 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index aef6ffef..a617fd62 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,41 +1,42 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import com.innoprog.android.feature.profile.profiledetails.data.dto.model.FeedDto +import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Query interface ProfileApi { @GET("/v1/profile") - suspend fun loadProfile(): ProfileResponse + suspend fun loadProfile(): Response @GET("/v1/profile/company") - suspend fun loadProfileCompany(): ProfileCompanyResponse + suspend fun loadProfileCompany(): Response @GET("/v1/feed") suspend fun getAll( @Query("authorId") authorId: String - ): List + ): Response> @GET("/v1/feed") suspend fun getProjects( @Query("type") type: String, @Query("authorId") authorId: String - ): List + ): Response> @GET("/v1/feed") suspend fun getIdeas( @Query("type") type: String, @Query("authorId") authorId: String - ): List + ): Response> @GET("/v1/feed/likes") suspend fun getLikes( @Query("pageSize") pageSize: Int - ): List + ): Response> @GET("/v1/feed/favorites") suspend fun getFavorites( @Query("pageSize") pageSize: Int - ): List + ): Response> } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 51f6831b..3952550f 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -1,7 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import com.innoprog.android.feature.feed.newsfeed.domain.models.PublicationType -import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient import com.innoprog.android.network.data.Response import kotlinx.coroutines.Dispatchers @@ -14,18 +13,19 @@ class ProfileRetrofitClient @Inject constructor( ) : NetworkClient { override suspend fun doRequest(dto: Any): Response { - var response = Response() return withContext(Dispatchers.IO) { try { - response = getResponse(dto) - response.apply { resultCode = ApiConstants.SUCCESS_CODE } + val response = getResponse(dto) + response.body()?.let { + Response().apply { resultCode = response.code() } + } ?: Response().apply { resultCode = response.code() } } catch (exception: HttpException) { - response.apply { resultCode = exception.code() } + Response().apply { resultCode = exception.code() } } } } - private suspend fun getResponse(dto: Any): Response { + private suspend fun getResponse(dto: Any): retrofit2.Response { return when (dto) { is RequestByProfile.GetProfile -> { service.loadProfile() @@ -36,23 +36,23 @@ class ProfileRetrofitClient @Inject constructor( } is RequestByProfile.GetAll -> { - ChipsResponse(service.getAll(authorId = dto.authorId)) + service.getAll(authorId = dto.authorId) } is RequestByProfile.GetProjects -> { - ChipsResponse(service.getProjects(type = PublicationType.NEWS.value, authorId = dto.authorId)) + service.getProjects(type = PublicationType.NEWS.value, authorId = dto.authorId) } is RequestByProfile.GetIdeas -> { - ChipsResponse(service.getIdeas(type = PublicationType.IDEA.value, authorId = dto.authorId)) + service.getIdeas(type = PublicationType.IDEA.value, authorId = dto.authorId) } is RequestByProfile.GetLikes -> { - ChipsResponse(service.getLikes(pageSize = PAGE_SIZE)) + service.getLikes(pageSize = PAGE_SIZE) } is RequestByProfile.GetFavorites -> { - ChipsResponse(service.getFavorites(pageSize = PAGE_SIZE)) + service.getFavorites(pageSize = PAGE_SIZE) } else -> { @@ -65,4 +65,4 @@ class ProfileRetrofitClient @Inject constructor( private const val PAGE_SIZE = 50 } -} +} \ No newline at end of file From c7316cea0433334cd1650493fc0c6778f9c07e27 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Mon, 8 Jul 2024 17:00:17 +0300 Subject: [PATCH 29/40] add catch blocks refactor viewHolder --- .../data/network/ProfileRetrofitClient.kt | 27 +++++ .../domain/models/FeedWrapper.kt | 31 +++--- .../adapter/PublicationsViewHolder.kt | 100 ++++++++---------- app/src/main/res/layout/item_news.xml | 12 ++- 4 files changed, 99 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 3952550f..90499c33 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -1,11 +1,15 @@ package com.innoprog.android.feature.profile.profiledetails.data.network +import com.google.gson.JsonParseException import com.innoprog.android.feature.feed.newsfeed.domain.models.PublicationType +import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient import com.innoprog.android.network.data.Response import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import okio.IOException import retrofit2.HttpException +import java.net.SocketTimeoutException import javax.inject.Inject class ProfileRetrofitClient @Inject constructor( @@ -21,6 +25,12 @@ class ProfileRetrofitClient @Inject constructor( } ?: Response().apply { resultCode = response.code() } } catch (exception: HttpException) { Response().apply { resultCode = exception.code() } + } catch (exception: IOException) { + logAndCreateErrorResponse(exception) + } catch (exception: JsonParseException) { + logAndCreateErrorResponse(exception) + } catch (exception: SocketTimeoutException) { + logAndCreateErrorResponse(exception) } } } @@ -61,6 +71,23 @@ class ProfileRetrofitClient @Inject constructor( } } + private fun createErrorResponse(code: Int): Response { + return Response().apply { + resultCode = code + } + } + + private fun logAndCreateErrorResponse(exception: Throwable): Response { + val errorCode = when (exception) { + is HttpException -> exception.code() + is IOException -> ApiConstants.NO_INTERNET_CONNECTION_CODE + is JsonParseException -> ApiConstants.BAD_REQUEST_CODE + is SocketTimeoutException -> ApiConstants.NO_INTERNET_CONNECTION_CODE + else -> ApiConstants.INTERNAL_SERVER_ERROR + } + return createErrorResponse(errorCode) + } + companion object { private const val PAGE_SIZE = 50 diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt index 50e55204..3cd5f883 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt @@ -2,30 +2,37 @@ package com.innoprog.android.feature.profile.profiledetails.domain.models sealed interface FeedWrapper { + val title: String + val content: String + val author: Author + val commentsCount: Int + val likesCount: Int + val attachments: List? + data class Idea( val id: String, - val author: Author, + override val author: Author, val projectId: String, - val title: String, - val content: String, + override val title: String, + override val content: String, val publishedAt: String, - val likesCount: Int, - val commentsCount: Int, - val attachments: List, + override val likesCount: Int, + override val commentsCount: Int, + override val attachments: List, val isLiked: Boolean, val isFavorite: Boolean ) : FeedWrapper data class News( val id: String, - val author: Author, + override val author: Author, val projectId: String, - val title: String, - val content: String, + override val title: String, + override val content: String, val publishedAt: String, - val likesCount: Int, - val commentsCount: Int, - val attachments: List, + override val likesCount: Int, + override val commentsCount: Int, + override val attachments: List, val isLiked: Boolean, val isFavorite: Boolean ) : FeedWrapper diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt index 4fd5bd9c..fcf08328 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt @@ -7,7 +7,6 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.innoprog.android.R import com.innoprog.android.databinding.ItemNewsBinding import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper -import com.innoprog.android.uikit.ImageLoadingType class PublicationsViewHolder(private val binding: ItemNewsBinding) : RecyclerView.ViewHolder(binding.root) { @@ -15,67 +14,60 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : private val radius = binding.root.resources.getDimensionPixelSize(R.dimen.corner_radius_8) fun bind(publication: FeedWrapper) { + bindCommonData(publication) when (publication) { - is FeedWrapper.Idea -> { - binding.apply { - Glide - .with(itemView) - .load(publication.attachments.firstOrNull()?.filePath) - .placeholder(R.drawable.news_sample) - .centerCrop() - .into(ivPublicationCover) - - tvPublicationTitle.text = publication.title - tvPublicationContent.text = publication.content + is FeedWrapper.Idea -> bindIdeaData() + is FeedWrapper.News -> bindNewsData(publication) + } + } - ivIdea.isVisible = true - projectCard.isVisible = false + private fun bindCommonData(publication: FeedWrapper) { + with(binding) { + tvPublicationTitle.text = publication.title + tvPublicationContent.text = publication.content + tvPublicationAuthorName.text = publication.author.name + tvCommentsCount.text = publication.commentsCount.toString() + tvLikesCount.text = publication.likesCount.toString() - val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person - val imageType = ImageLoadingType.ImageDrawable(placeholderResId) - publicationAuthorAvatar.loadImage(imageType) + val initials = publication.author.name + .split(' ') + .map { it.first().uppercaseChar() } + .joinToString(separator = "", limit = 2) + publicationAuthorAvatar.text = initials.ifBlank { "?" } - tvPublicationAuthorName.text = publication.author.name - tvCommentsCount.text = publication.commentsCount.toString() - tvLikesCount.text = publication.likesCount.toString() - } + publication.attachments?.firstOrNull()?.let { attachment -> + Glide + .with(itemView) + .load(attachment.filePath) + .placeholder(R.drawable.news_sample) + .centerCrop() + .into(ivPublicationCover) } + } + } - is FeedWrapper.News -> { - binding.apply { - Glide - .with(itemView) - .load("https://example.com/news_image") - .placeholder(R.drawable.news_sample) - .centerCrop() - .into(ivPublicationCover) - - tvPublicationTitle.text = publication.title - tvPublicationContent.text = publication.content - - ivIdea.isVisible = false - projectCard.isVisible = true - - Glide - .with(itemView) - .load("https://example.com/project_logo") - .placeholder(R.drawable.ic_placeholder_logo) - .centerCrop() - .transform(RoundedCorners(radius)) - .into(ivProjectLogo) + private fun bindIdeaData() { + with(binding) { + ivIdea.isVisible = true + projectCard.isVisible = false + } + } - tvProjectName.text = "News Project" - tvProjectDirection.text = "News Direction" + private fun bindNewsData(publication: FeedWrapper.News) { + with(binding) { + ivIdea.isVisible = false + projectCard.isVisible = true - val placeholderResId = com.innoprog.android.uikit.R.drawable.ic_person - val imageType = ImageLoadingType.ImageDrawable(placeholderResId) - publicationAuthorAvatar.loadImage(imageType) + Glide + .with(itemView) + .load("https://example.com/project_logo") + .placeholder(R.drawable.ic_placeholder_logo) + .centerCrop() + .transform(RoundedCorners(radius)) + .into(ivProjectLogo) - tvPublicationAuthorName.text = publication.author.name - tvCommentsCount.text = publication.commentsCount.toString() - tvLikesCount.text = publication.likesCount.toString() - } - } + tvProjectName.text = "News Project" + tvProjectDirection.text = "IT" } } -} +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_news.xml b/app/src/main/res/layout/item_news.xml index a9b32dcf..464f6873 100644 --- a/app/src/main/res/layout/item_news.xml +++ b/app/src/main/res/layout/item_news.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_begin="16dp" /> + app:layout_constraintGuide_end="395dp" /> - + app:layout_constraintTop_toTopOf="@+id/tvPublicationAuthorName" /> + tools:text="Julia Anisimova" /> Date: Mon, 8 Jul 2024 17:12:06 +0300 Subject: [PATCH 30/40] after detekt --- .../profiledetails/data/impl/ChipsProfileRepoImpl.kt | 2 +- .../profile/profiledetails/domain/models/FeedWrapper.kt | 6 +++--- .../profile/profiledetails/presentation/ProfileViewModel.kt | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index 9e84a4a4..1ad48dae 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -54,7 +54,7 @@ class ChipsProfileRepoImpl @Inject constructor( override suspend fun getFavorites(pageSize: Int): Flow>> { return getResult>( - getResponse = {network.doRequest(RequestByProfile.GetFavorites(pageSize)) }, + getResponse = { network.doRequest(RequestByProfile.GetFavorites(pageSize)) }, mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } ) } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt index 3cd5f883..2147f0c4 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWrapper.kt @@ -17,7 +17,7 @@ sealed interface FeedWrapper { override val content: String, val publishedAt: String, override val likesCount: Int, - override val commentsCount: Int, + override val commentsCount: Int, override val attachments: List, val isLiked: Boolean, val isFavorite: Boolean @@ -27,8 +27,8 @@ sealed interface FeedWrapper { val id: String, override val author: Author, val projectId: String, - override val title: String, - override val content: String, + override val title: String, + override val content: String, val publishedAt: String, override val likesCount: Int, override val commentsCount: Int, diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 6ba52fa5..4f834b19 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import javax.inject.Inject - class ProfileViewModel @Inject constructor( private val getProfileUseCase: GetProfileUseCase, private val getProfileCompanyUseCase: GetProfileCompanyUseCase, From e69674c542dad5349050af342111e4b958904910 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Tue, 9 Jul 2024 20:25:03 +0300 Subject: [PATCH 31/40] refactor avatar profile --- .../data/impl/ProfileInfoRepoImpl.kt | 19 ++++---- .../data/network/ProfileRetrofitClient.kt | 2 +- .../presentation/ProfileFragment.kt | 5 +++ .../presentation/ProfileViewModel.kt | 44 ++++--------------- app/src/main/res/layout/fragment_profile.xml | 9 +++- 5 files changed, 31 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index be2706d3..ac2d0f84 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -25,21 +25,20 @@ class ProfileInfoRepoImpl @Inject constructor( ) : ProfileInfoRepo { override suspend fun loadProfile(): Flow> = flow { - val apiResponse = network.doRequest(RequestByProfile.GetProfile) - - if (apiResponse is ProfileResponse && apiResponse.resultCode == ApiConstants.SUCCESS_CODE) { - emit(Resource.Success(apiResponse.mapToDomainUserData())) + val response = network.doRequest(RequestByProfile.GetProfile) + if (response is ProfileResponse && response.resultCode == ApiConstants.SUCCESS_CODE) { + emit(Resource.Success(response.mapToDomainUserData())) roomDB.profileDao().saveProfile( ProfileEntity( - userId = apiResponse.userId, - name = apiResponse.name, - about = apiResponse.about, - communicationChannels = apiResponse.communicationChannels, - authorities = apiResponse.authorities + userId = response.userId, + name = response.name, + about = response.about, + communicationChannels = response.communicationChannels, + authorities = response.authorities ) ) } else { - emit(Resource.Error(getErrorType(apiResponse.resultCode))) + emit(Resource.Error(getErrorType(response.resultCode))) } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 90499c33..7479637c 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -92,4 +92,4 @@ class ProfileRetrofitClient @Inject constructor( private const val PAGE_SIZE = 50 } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index b71b9f29..a929185f 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -193,6 +193,11 @@ class ProfileFragment : BaseFragment() { private fun fillViews(profile: Profile) { binding.name.text = profile.name binding.description.text = profile.about + val initials = profile.name + .split(' ') + .map { it.first().uppercaseChar() } + .joinToString(separator = "", limit = 2) + binding.avatar.text = initials.ifBlank { "?" } } private fun fillViewsCompany(company: ProfileCompany) { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 4f834b19..4158ff24 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -4,12 +4,14 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.innoprog.android.base.BaseViewModel import com.innoprog.android.BuildConfig +import com.innoprog.android.base.BaseViewModel import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile +import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.util.ErrorType import com.innoprog.android.util.Resource import kotlinx.coroutines.Dispatchers @@ -33,43 +35,15 @@ class ProfileViewModel @Inject constructor( val chipsUiState: LiveData = _chipsUiState fun loadProfile() { - viewModelScope.launch(Dispatchers.IO) { - runCatching { - getProfileUseCase.getProfile().collect { response -> - when (response) { - is Resource.Success -> { - _uiState.postValue(ProfileScreenState.Content(response.data)) - } - - is Resource.Error -> { - _uiState.postValue(ProfileScreenState.Error(response.errorType)) - } - } - } - }.onFailure { - _uiState.postValue(ProfileScreenState.Error(type = ErrorType.NO_CONNECTION)) - } - } + runSafelyUseCase ( + getUseCaseFlow = { getProfileUseCase.getProfile() } + ) { _uiState.postValue(ProfileScreenState.Content(it)) } } fun loadProfileCompany() { - viewModelScope.launch(Dispatchers.IO) { - runCatching { - getProfileCompanyUseCase.getProfileCompany().collect { response -> - when (response) { - is Resource.Success -> { - _uiStateCompany.postValue(ProfileCompanyScreenState.Content(response.data)) - } - - is Resource.Error -> { - _uiStateCompany.postValue(ProfileCompanyScreenState.Error(response.errorType)) - } - } - } - }.onFailure { - _uiStateCompany.postValue(ProfileCompanyScreenState.Error(type = ErrorType.NO_CONNECTION)) - } - } + runSafelyUseCase ( + getUseCaseFlow = { getProfileCompanyUseCase.getProfileCompany() } + ) { _uiStateCompany.postValue(ProfileCompanyScreenState.Content(it)) } } fun loadChipAll(authorId: String) { diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 936f14b3..dd5fddce 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -28,12 +28,17 @@ android:padding="@dimen/padding_16" app:layout_constraintTop_toBottomOf="@id/topbar_profile"> - + android:background="@drawable/shape_avatar" + android:textAlignment="gravity" + android:gravity="center" + android:scaleX="1.0" + android:textSize="40sp" + android:text="AM" /> Date: Wed, 10 Jul 2024 08:10:51 +0300 Subject: [PATCH 32/40] fix client --- .../data/network/ProfileRetrofitClient.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 7479637c..81186b50 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -20,9 +20,16 @@ class ProfileRetrofitClient @Inject constructor( return withContext(Dispatchers.IO) { try { val response = getResponse(dto) - response.body()?.let { + if (response.isSuccessful) { + val body = response.body() + if (body != null) { + Response().apply { resultCode = response.code() } + } else { + Response().apply { resultCode = ApiConstants.INTERNAL_SERVER_ERROR } + } + } else { Response().apply { resultCode = response.code() } - } ?: Response().apply { resultCode = response.code() } + } } catch (exception: HttpException) { Response().apply { resultCode = exception.code() } } catch (exception: IOException) { @@ -35,7 +42,7 @@ class ProfileRetrofitClient @Inject constructor( } } - private suspend fun getResponse(dto: Any): retrofit2.Response { + private suspend fun getResponse(dto: Any): retrofit2.Response<*> { return when (dto) { is RequestByProfile.GetProfile -> { service.loadProfile() From ef50d2c0910748f58b08c33421d766c18c771510 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 10 Jul 2024 08:22:35 +0300 Subject: [PATCH 33/40] fix client --- .../profiledetails/data/network/ProfileRetrofitClient.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 81186b50..f3174e77 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -21,12 +21,7 @@ class ProfileRetrofitClient @Inject constructor( try { val response = getResponse(dto) if (response.isSuccessful) { - val body = response.body() - if (body != null) { - Response().apply { resultCode = response.code() } - } else { - Response().apply { resultCode = ApiConstants.INTERNAL_SERVER_ERROR } - } + Response().apply { resultCode = response.code() } } else { Response().apply { resultCode = response.code() } } From ceca8baf37eac09ce3dd0613d764ce7fc95dfa2e Mon Sep 17 00:00:00 2001 From: Cdarius Date: Wed, 10 Jul 2024 13:38:53 +0300 Subject: [PATCH 34/40] Fix news view, fix get response in ProfileRetrofitClient, fix show placeholder logic, refactoring --- .../data/network/ProfileRetrofitClient.kt | 57 ++++++++++++------- .../presentation/ProfileFragment.kt | 52 +++++++---------- .../presentation/ProfileViewModel.kt | 19 ++++--- .../adapter/PublicationsViewHolder.kt | 4 +- app/src/main/res/layout/fragment_profile.xml | 19 ++----- app/src/main/res/layout/item_news.xml | 2 +- 6 files changed, 75 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index f3174e77..d9fc0012 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -19,12 +19,7 @@ class ProfileRetrofitClient @Inject constructor( override suspend fun doRequest(dto: Any): Response { return withContext(Dispatchers.IO) { try { - val response = getResponse(dto) - if (response.isSuccessful) { - Response().apply { resultCode = response.code() } - } else { - Response().apply { resultCode = response.code() } - } + getResponse(dto) } catch (exception: HttpException) { Response().apply { resultCode = exception.code() } } catch (exception: IOException) { @@ -37,39 +32,61 @@ class ProfileRetrofitClient @Inject constructor( } } - private suspend fun getResponse(dto: Any): retrofit2.Response<*> { + private suspend fun getResponse(dto: Any): Response { return when (dto) { - is RequestByProfile.GetProfile -> { - service.loadProfile() - } + is RequestByProfile.GetProfile -> mapToResponse(service.loadProfile()) { it } is RequestByProfile.GetProfileCompany -> { - service.loadProfileCompany() + mapToResponse(service.loadProfileCompany()) { it } } is RequestByProfile.GetAll -> { - service.getAll(authorId = dto.authorId) + mapToResponse(service.getAll(dto.authorId)) { ChipsResponse(it) } } is RequestByProfile.GetProjects -> { - service.getProjects(type = PublicationType.NEWS.value, authorId = dto.authorId) + mapToResponse( + service.getProjects( + type = PublicationType.NEWS.value, + authorId = dto.authorId + ) + ) { ChipsResponse(it) } } is RequestByProfile.GetIdeas -> { - service.getIdeas(type = PublicationType.IDEA.value, authorId = dto.authorId) + mapToResponse( + service.getIdeas( + type = PublicationType.IDEA.value, + authorId = dto.authorId + ) + ) { ChipsResponse(it) } } is RequestByProfile.GetLikes -> { - service.getLikes(pageSize = PAGE_SIZE) + mapToResponse(service.getLikes(pageSize = PAGE_SIZE)) { + ChipsResponse(it) + } } is RequestByProfile.GetFavorites -> { - service.getFavorites(pageSize = PAGE_SIZE) + mapToResponse(service.getFavorites(pageSize = PAGE_SIZE)) { + ChipsResponse(it) + } } - else -> { - throw IllegalArgumentException("Unsupported request type") - } + else -> throw IllegalArgumentException("Unsupported request type") + } + } + + private inline fun mapToResponse( + response: retrofit2.Response, + mapToResponse: (D) -> R + ): Response { + val body = response.body() + return if (response.isSuccessful && body != null) { + mapToResponse(body).apply { resultCode = response.code() } + } else { + Response().apply { resultCode = response.code() } } } @@ -84,14 +101,12 @@ class ProfileRetrofitClient @Inject constructor( is HttpException -> exception.code() is IOException -> ApiConstants.NO_INTERNET_CONNECTION_CODE is JsonParseException -> ApiConstants.BAD_REQUEST_CODE - is SocketTimeoutException -> ApiConstants.NO_INTERNET_CONNECTION_CODE else -> ApiConstants.INTERNAL_SERVER_ERROR } return createErrorResponse(errorCode) } companion object { - private const val PAGE_SIZE = 50 } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index a929185f..0a8466ca 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -85,7 +85,6 @@ class ProfileFragment : BaseFragment() { viewModel.uiStateCompany.observe(viewLifecycleOwner) { stateCompany -> renderCompany(stateCompany) } - viewModel.chipsUiState.observe(viewLifecycleOwner) { stateChips -> renderChips(stateChips) } @@ -150,44 +149,26 @@ class ProfileFragment : BaseFragment() { @SuppressLint("NotifyDataSetChanged") private fun renderChips(chipsScreenState: ChipsScreenState) { + if (chipsScreenState !is ChipsScreenState.Error) { + publications.clear() + } when (chipsScreenState) { - is ChipsScreenState.All -> { - showContent() - publications.clear() - publications.addAll(chipsScreenState.content) - publicationsAdapter.notifyDataSetChanged() - } + is ChipsScreenState.All -> publications.addAll(chipsScreenState.content) - is ChipsScreenState.Projects -> { - showContent() - publications.clear() - publications.addAll(chipsScreenState.projects) - publicationsAdapter.notifyDataSetChanged() - } + is ChipsScreenState.Projects -> publications.addAll(chipsScreenState.projects) - is ChipsScreenState.Ideas -> { - showContent() - publications.clear() - publications.addAll(chipsScreenState.ideas) - publicationsAdapter.notifyDataSetChanged() - } + is ChipsScreenState.Ideas -> publications.addAll(chipsScreenState.ideas) - is ChipsScreenState.Liked -> { - showContent() - publications.clear() - publications.addAll(chipsScreenState.liked) - publicationsAdapter.notifyDataSetChanged() - } + is ChipsScreenState.Liked -> publications.addAll(chipsScreenState.liked) - is ChipsScreenState.Favorites -> { - showContent() - publications.clear() - publications.addAll(chipsScreenState.favorites) - publicationsAdapter.notifyDataSetChanged() - } + is ChipsScreenState.Favorites -> publications.addAll(chipsScreenState.favorites) is ChipsScreenState.Error -> showPlaceholder() } + if (chipsScreenState !is ChipsScreenState.Error) { + publicationsAdapter.notifyDataSetChanged() + showContent() + } } private fun fillViews(profile: Profile) { @@ -227,8 +208,13 @@ class ProfileFragment : BaseFragment() { private fun showContent() { with(binding) { - recyclerContent.isVisible = true - showPlaceholder() + if (publicationsAdapter.publications.isEmpty()) { + placeholderText.isVisible = true + recyclerContent.isVisible = false + } else { + placeholderText.isVisible = false + recyclerContent.isVisible = true + } } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index 4158ff24..d8df5761 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -35,14 +35,16 @@ class ProfileViewModel @Inject constructor( val chipsUiState: LiveData = _chipsUiState fun loadProfile() { - runSafelyUseCase ( - getUseCaseFlow = { getProfileUseCase.getProfile() } + runSafelyUseCase( + getUseCaseFlow = { getProfileUseCase.getProfile() }, + onFailure = { error -> _uiState.postValue(ProfileScreenState.Error(error)) } ) { _uiState.postValue(ProfileScreenState.Content(it)) } } fun loadProfileCompany() { - runSafelyUseCase ( - getUseCaseFlow = { getProfileCompanyUseCase.getProfileCompany() } + runSafelyUseCase( + getUseCaseFlow = { getProfileCompanyUseCase.getProfileCompany() }, + onFailure = { _uiStateCompany.postValue(ProfileCompanyScreenState.Error(it)) } ) { _uiStateCompany.postValue(ProfileCompanyScreenState.Content(it)) } } @@ -78,7 +80,8 @@ class ProfileViewModel @Inject constructor( private inline fun runSafelyUseCase( crossinline getUseCaseFlow: suspend () -> Flow>, - crossinline onSuccess: (D) -> Unit + noinline onFailure: ((ErrorType) -> Unit)? = null, + crossinline onSuccess: (D) -> Unit, ) { viewModelScope.launch(Dispatchers.IO) { runCatching { @@ -86,7 +89,8 @@ class ProfileViewModel @Inject constructor( when (result) { is Resource.Success -> onSuccess(result.data) is Resource.Error -> { - _chipsUiState.postValue(ChipsScreenState.Error(result.errorType)) + onFailure?.invoke(result.errorType) + ?: _chipsUiState.postValue(ChipsScreenState.Error(result.errorType)) } } } @@ -95,7 +99,8 @@ class ProfileViewModel @Inject constructor( Log.v(TAG, "error -> ${error.localizedMessage}") error.printStackTrace() } - _chipsUiState.postValue(ChipsScreenState.Error(type = ErrorType.NO_CONNECTION)) + onFailure?.invoke(ErrorType.UNKNOWN_ERROR) + ?: _chipsUiState.postValue(ChipsScreenState.Error(ErrorType.UNKNOWN_ERROR)) } } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt index fcf08328..76cc1f0a 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt @@ -17,7 +17,7 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : bindCommonData(publication) when (publication) { is FeedWrapper.Idea -> bindIdeaData() - is FeedWrapper.News -> bindNewsData(publication) + is FeedWrapper.News -> bindNewsData() } } @@ -53,7 +53,7 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : } } - private fun bindNewsData(publication: FeedWrapper.News) { + private fun bindNewsData() { with(binding) { ivIdea.isVisible = false projectCard.isVisible = true diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index dd5fddce..03098eba 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -38,7 +38,7 @@ android:gravity="center" android:scaleX="1.0" android:textSize="40sp" - android:text="AM" /> + tools:text="AM" /> @@ -98,7 +98,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:gravity="center" - android:text="@string/description" + tools:text="@string/description" android:textColor="@color/text_secondary" /> @@ -140,16 +140,8 @@ - - - - diff --git a/app/src/main/res/layout/item_news.xml b/app/src/main/res/layout/item_news.xml index 464f6873..7b00e634 100644 --- a/app/src/main/res/layout/item_news.xml +++ b/app/src/main/res/layout/item_news.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_end="395dp" /> + app:layout_constraintGuide_begin="@dimen/margin_16" /> Date: Wed, 10 Jul 2024 14:45:30 +0300 Subject: [PATCH 35/40] add project --- .../data/impl/ChipsProfileRepoImpl.kt | 25 ++++++++++++++++++- .../data/network/RequestByProfile.kt | 1 + .../profiledetails/domain/ChipsProfileRepo.kt | 2 ++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index 1ad48dae..953c5f80 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -1,5 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl +import com.innoprog.android.feature.feed.newsfeed.domain.models.NewsWithProject import com.innoprog.android.feature.profile.profiledetails.data.dto.model.mapToDomain import com.innoprog.android.feature.profile.profiledetails.data.network.ChipsResponse import com.innoprog.android.feature.profile.profiledetails.data.network.RequestByProfile @@ -31,7 +32,18 @@ class ChipsProfileRepoImpl @Inject constructor( ): Flow>> { return getResult>( getResponse = { network.doRequest(RequestByProfile.GetProjects(type, userId)) }, - mapToDomain = { response -> response.results.map { item -> item.mapToDomain() as FeedWrapper.News } } + mapToDomain = { response -> + response.results.map { item -> + val news = item.mapToDomain() as FeedWrapper.News + val projectId = news.projectId + if (projectId != null) { + val projectResponse = network.doRequest(RequestByProfile.GetProject(projectId)) + val project = projectResponse.body()?.results?.firstOrNull()?.let { it.mapToDomain() } + news.project = project + } + news + } + } ) } @@ -59,6 +71,17 @@ class ChipsProfileRepoImpl @Inject constructor( ) } + override suspend fun getProject(id: String): Flow> { + return getResult( + getResponse = { network.doRequest(RequestByProfile.GetProject(id)) }, + mapToDomain = { response -> + val project = response.results.firstOrNull()?.let { it.mapToDomain() } + val newsWithProject = NewsWithProject(project) + newsWithProject + } + ) + } + private inline fun getResult( crossinline getResponse: suspend () -> Response, crossinline mapToDomain: (Data) -> Domain diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt index 928b08dc..bde9a17b 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt @@ -8,4 +8,5 @@ sealed interface RequestByProfile { class GetIdeas(val type: String, val authorId: String) : RequestByProfile class GetLikes(val pageSize: Int) : RequestByProfile class GetFavorites(val pageSize: Int) : RequestByProfile + class GetProject(val id: String) : RequestByProfile } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt index bacdbdad..7410d348 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt @@ -1,5 +1,6 @@ package com.innoprog.android.feature.profile.profiledetails.domain +import com.innoprog.android.feature.feed.newsfeed.domain.models.NewsWithProject import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow @@ -10,4 +11,5 @@ interface ChipsProfileRepo { suspend fun getIdeas(type: String, userId: String): Flow>> suspend fun getLikes(pageSize: Int): Flow>> suspend fun getFavorites(pageSize: Int): Flow>> + suspend fun getProject(id: String): Flow> } From 9656b8e50c59cedc1bb4f147a31a760cb96b5167 Mon Sep 17 00:00:00 2001 From: Cdarius Date: Wed, 10 Jul 2024 21:32:58 +0300 Subject: [PATCH 36/40] Add get project by id request, add feedWithProject model --- .../data/dto/model/ProjectDto.kt | 27 +++++++ .../data/impl/ChipsProfileRepoImpl.kt | 73 ++++++++++--------- .../profiledetails/data/network/ProfileApi.kt | 5 ++ .../data/network/RequestByProfile.kt | 2 +- .../profiledetails/domain/ChipsProfileRepo.kt | 14 ++-- .../domain/models/FeedWithProject.kt | 8 ++ 6 files changed, 84 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/ProjectDto.kt create mode 100644 app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWithProject.kt diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/ProjectDto.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/ProjectDto.kt new file mode 100644 index 00000000..e7472c5f --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/dto/model/ProjectDto.kt @@ -0,0 +1,27 @@ +package com.innoprog.android.feature.profile.profiledetails.data.dto.model + +import com.google.gson.annotations.SerializedName +import com.innoprog.android.feature.feed.newsfeed.domain.models.Project +import com.innoprog.android.network.data.NetworkModel +import com.innoprog.android.network.data.Response + +@NetworkModel +class ProjectDto( + @SerializedName("id") + val id: String, + @SerializedName("name") + val name: String, + @SerializedName("area") + val area: String, + @SerializedName("logoFilePath") + val logoUrl: String +) : Response() + +fun ProjectDto.mapToDomain(): Project { + return Project( + id = id, + name = name, + area = area, + logoUrl = logoUrl + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt index 953c5f80..622dfe83 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ChipsProfileRepoImpl.kt @@ -1,10 +1,12 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl -import com.innoprog.android.feature.feed.newsfeed.domain.models.NewsWithProject +import com.innoprog.android.feature.profile.profiledetails.data.dto.model.FeedDto +import com.innoprog.android.feature.profile.profiledetails.data.dto.model.ProjectDto import com.innoprog.android.feature.profile.profiledetails.data.dto.model.mapToDomain import com.innoprog.android.feature.profile.profiledetails.data.network.ChipsResponse import com.innoprog.android.feature.profile.profiledetails.data.network.RequestByProfile import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.network.data.ApiConstants import com.innoprog.android.network.data.NetworkClient @@ -19,72 +21,71 @@ class ChipsProfileRepoImpl @Inject constructor( private val network: NetworkClient ) : ChipsProfileRepo { - override suspend fun getAll(authorId: String): Flow>> { - return getResult>( + override suspend fun getAll(authorId: String): Flow>> { + return getResult>( getResponse = { network.doRequest(RequestByProfile.GetAll(authorId)) }, - mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } + mapToDomain = { response -> mapToFeedWithProject(response.results) } ) } override suspend fun getProjects( type: String, userId: String - ): Flow>> { - return getResult>( + ): Flow>> { + return getResult>( getResponse = { network.doRequest(RequestByProfile.GetProjects(type, userId)) }, - mapToDomain = { response -> - response.results.map { item -> - val news = item.mapToDomain() as FeedWrapper.News - val projectId = news.projectId - if (projectId != null) { - val projectResponse = network.doRequest(RequestByProfile.GetProject(projectId)) - val project = projectResponse.body()?.results?.firstOrNull()?.let { it.mapToDomain() } - news.project = project - } - news - } - } + mapToDomain = { response -> mapToFeedWithProject(response.results) } ) } override suspend fun getIdeas( type: String, userId: String - ): Flow>> { - return getResult>( + ): Flow>> { + return getResult>( getResponse = { network.doRequest(RequestByProfile.GetIdeas(type, userId)) }, - mapToDomain = { response -> response.results.map { item -> item.mapToDomain() as FeedWrapper.Idea } } + mapToDomain = { response -> mapToFeedWithProject(response.results) } ) } - override suspend fun getLikes(pageSize: Int): Flow>> { - return getResult>( + override suspend fun getLikes(pageSize: Int): Flow>> { + return getResult>( getResponse = { network.doRequest(RequestByProfile.GetLikes(pageSize)) }, - mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } + mapToDomain = { response -> mapToFeedWithProject(response.results) } ) } - override suspend fun getFavorites(pageSize: Int): Flow>> { - return getResult>( + override suspend fun getFavorites(pageSize: Int): Flow>> { + return getResult>( getResponse = { network.doRequest(RequestByProfile.GetFavorites(pageSize)) }, - mapToDomain = { response -> response.results.map { item -> item.mapToDomain() } } + mapToDomain = { response -> mapToFeedWithProject(response.results) } ) } - override suspend fun getProject(id: String): Flow> { - return getResult( - getResponse = { network.doRequest(RequestByProfile.GetProject(id)) }, - mapToDomain = { response -> - val project = response.results.firstOrNull()?.let { it.mapToDomain() } - val newsWithProject = NewsWithProject(project) - newsWithProject + private suspend fun mapToFeedWithProject(publicationList: List): List { + return publicationList.map { item -> + val publication = item.mapToDomain() + if (publication is FeedWrapper.News) { + val projectResponse = runCatching { + network.doRequest( + RequestByProfile.GetProjectById(id = publication.projectId) + ) + }.getOrNull() + val project = if (projectResponse is ProjectDto) { + projectResponse.mapToDomain() + } else { + null + } + FeedWithProject(publication, project) + } else { + FeedWithProject(publication, null) } - ) + } } private inline fun getResult( crossinline getResponse: suspend () -> Response, - crossinline mapToDomain: (Data) -> Domain + crossinline mapToDomain: suspend (Data) -> Domain ): Flow> { return flow { val response = getResponse() diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index a617fd62..a3ab8e80 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,8 +1,10 @@ package com.innoprog.android.feature.profile.profiledetails.data.network import com.innoprog.android.feature.profile.profiledetails.data.dto.model.FeedDto +import com.innoprog.android.feature.profile.profiledetails.data.dto.model.ProjectDto import retrofit2.Response import retrofit2.http.GET +import retrofit2.http.Path import retrofit2.http.Query interface ProfileApi { @@ -39,4 +41,7 @@ interface ProfileApi { suspend fun getFavorites( @Query("pageSize") pageSize: Int ): Response> + + @GET("/v1/projects/{projectId}") + suspend fun getProjectById(@Path("projectId") id: String): Response } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt index bde9a17b..4ecab404 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/RequestByProfile.kt @@ -8,5 +8,5 @@ sealed interface RequestByProfile { class GetIdeas(val type: String, val authorId: String) : RequestByProfile class GetLikes(val pageSize: Int) : RequestByProfile class GetFavorites(val pageSize: Int) : RequestByProfile - class GetProject(val id: String) : RequestByProfile + class GetProjectById(val id: String) : RequestByProfile } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt index 7410d348..a49f8f3f 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsProfileRepo.kt @@ -1,15 +1,13 @@ package com.innoprog.android.feature.profile.profiledetails.domain -import com.innoprog.android.feature.feed.newsfeed.domain.models.NewsWithProject -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsProfileRepo { - suspend fun getAll(authorId: String): Flow>> - suspend fun getProjects(type: String, userId: String): Flow>> - suspend fun getIdeas(type: String, userId: String): Flow>> - suspend fun getLikes(pageSize: Int): Flow>> - suspend fun getFavorites(pageSize: Int): Flow>> - suspend fun getProject(id: String): Flow> + suspend fun getAll(authorId: String): Flow>> + suspend fun getProjects(type: String, userId: String): Flow>> + suspend fun getIdeas(type: String, userId: String): Flow>> + suspend fun getLikes(pageSize: Int): Flow>> + suspend fun getFavorites(pageSize: Int): Flow>> } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWithProject.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWithProject.kt new file mode 100644 index 00000000..89247a39 --- /dev/null +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/models/FeedWithProject.kt @@ -0,0 +1,8 @@ +package com.innoprog.android.feature.profile.profiledetails.domain.models + +import com.innoprog.android.feature.feed.newsfeed.domain.models.Project + +class FeedWithProject( + val feedWrapper: FeedWrapper, + val project: Project? +) \ No newline at end of file From 631d1364ff090df16f50544342f169ed15d5404a Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 10 Jul 2024 22:21:59 +0300 Subject: [PATCH 37/40] bind FeedWithProject --- .../data/network/ProfileRetrofitClient.kt | 5 +++++ .../profiledetails/domain/ChipsInteractor.kt | 12 ++++++------ .../domain/impl/ChipsInteractorImpl.kt | 12 ++++++------ .../presentation/ChipsScreenState.kt | 12 ++++++------ .../presentation/ProfileViewModel.kt | 15 +++++++++------ 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index d9fc0012..9848a155 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -74,6 +74,11 @@ class ProfileRetrofitClient @Inject constructor( } } + is RequestByProfile.GetProjectById -> { + mapToResponse(service.getProjectById(dto.id)) { + it + } + } else -> throw IllegalArgumentException("Unsupported request type") } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt index 494a3bd5..e82349e5 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/ChipsInteractor.kt @@ -1,13 +1,13 @@ package com.innoprog.android.feature.profile.profiledetails.domain -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow interface ChipsInteractor { - suspend fun getAll(authorId: String): Flow>> - suspend fun getProjects(type: String, userId: String): Flow>> - suspend fun getIdeas(type: String, userId: String): Flow>> - suspend fun getLikes(pageSize: Int): Flow>> - suspend fun getFavorites(pageSize: Int): Flow>> + suspend fun getAll(authorId: String): Flow>> + suspend fun getProjects(type: String, userId: String): Flow>> + suspend fun getIdeas(type: String, userId: String): Flow>> + suspend fun getLikes(pageSize: Int): Flow>> + suspend fun getFavorites(pageSize: Int): Flow>> } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt index c048f7cd..20a6d7bf 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/domain/impl/ChipsInteractorImpl.kt @@ -2,29 +2,29 @@ package com.innoprog.android.feature.profile.profiledetails.domain.impl import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.ChipsProfileRepo -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.util.Resource import kotlinx.coroutines.flow.Flow import javax.inject.Inject class ChipsInteractorImpl @Inject constructor(private val repo: ChipsProfileRepo) : ChipsInteractor { - override suspend fun getAll(authorId: String): Flow>> { + override suspend fun getAll(authorId: String): Flow>> { return repo.getAll(authorId) } - override suspend fun getProjects(type: String, userId: String): Flow>> { + override suspend fun getProjects(type: String, userId: String): Flow>> { return repo.getProjects(type, userId) } - override suspend fun getIdeas(type: String, userId: String): Flow>> { + override suspend fun getIdeas(type: String, userId: String): Flow>> { return repo.getIdeas(type, userId) } - override suspend fun getLikes(pageSize: Int): Flow>> { + override suspend fun getLikes(pageSize: Int): Flow>> { return repo.getLikes(pageSize) } - override suspend fun getFavorites(pageSize: Int): Flow>> { + override suspend fun getFavorites(pageSize: Int): Flow>> { return repo.getFavorites(pageSize) } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt index b42a8480..44401b96 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ChipsScreenState.kt @@ -1,18 +1,18 @@ package com.innoprog.android.feature.profile.profiledetails.presentation -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.util.ErrorType sealed interface ChipsScreenState { - class All(val content: List) : ChipsScreenState + class All(val content: List) : ChipsScreenState - class Projects(val projects: List) : ChipsScreenState + class Projects(val projects: List) : ChipsScreenState - class Ideas(val ideas: List) : ChipsScreenState + class Ideas(val ideas: List) : ChipsScreenState - class Liked(val liked: List) : ChipsScreenState + class Liked(val liked: List) : ChipsScreenState - class Favorites(val favorites: List) : ChipsScreenState + class Favorites(val favorites: List) : ChipsScreenState class Error(val type: ErrorType) : ChipsScreenState } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index d8df5761..b3027695 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -9,7 +9,7 @@ import com.innoprog.android.base.BaseViewModel import com.innoprog.android.feature.profile.profiledetails.domain.ChipsInteractor import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileCompanyUseCase import com.innoprog.android.feature.profile.profiledetails.domain.GetProfileUseCase -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany import com.innoprog.android.util.ErrorType @@ -35,6 +35,7 @@ class ProfileViewModel @Inject constructor( val chipsUiState: LiveData = _chipsUiState fun loadProfile() { + runSafelyUseCase( getUseCaseFlow = { getProfileUseCase.getProfile() }, onFailure = { error -> _uiState.postValue(ProfileScreenState.Error(error)) } @@ -49,37 +50,38 @@ class ProfileViewModel @Inject constructor( } fun loadChipAll(authorId: String) { - runSafelyUseCase>( + runSafelyUseCase>( getUseCaseFlow = { chipsInteractor.getAll(authorId) } ) { _chipsUiState.postValue(ChipsScreenState.All(it)) } } fun loadChipProjects(type: String, authorId: String) { - runSafelyUseCase>( + runSafelyUseCase>( getUseCaseFlow = { chipsInteractor.getProjects(type, authorId) } ) { _chipsUiState.postValue(ChipsScreenState.Projects(it)) } } fun loadChipIdeas(type: String, authorId: String) { - runSafelyUseCase>( + runSafelyUseCase>( getUseCaseFlow = { chipsInteractor.getIdeas(type, authorId) } ) { _chipsUiState.postValue(ChipsScreenState.Ideas(it)) } } fun loadChipLiked(pageSize: Int) { - runSafelyUseCase>( + runSafelyUseCase>( getUseCaseFlow = { chipsInteractor.getLikes(pageSize) } ) { _chipsUiState.postValue(ChipsScreenState.Liked(it)) } } fun loadChipFavorites(pageSize: Int) { - runSafelyUseCase>( + runSafelyUseCase>( getUseCaseFlow = { chipsInteractor.getFavorites(pageSize) } ) { _chipsUiState.postValue(ChipsScreenState.Favorites(it)) } } private inline fun runSafelyUseCase( crossinline getUseCaseFlow: suspend () -> Flow>, + noinline onFailure: ((ErrorType) -> Unit)? = null, crossinline onSuccess: (D) -> Unit, ) { @@ -106,6 +108,7 @@ class ProfileViewModel @Inject constructor( } companion object { + private val TAG = ProfileViewModel::class.simpleName } } From 8863801e0c6182c23f7c803a1cacffa76edcc996 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 10 Jul 2024 22:43:02 +0300 Subject: [PATCH 38/40] bind FeedWithProject at ui --- .../presentation/ProfileFragment.kt | 10 +++--- .../adapter/PublicationsRecyclerAdapter.kt | 6 ++-- .../adapter/PublicationsViewHolder.kt | 31 ++++++++++--------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 0a8466ca..30406949 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -15,6 +15,7 @@ import com.innoprog.android.di.AppComponentHolder import com.innoprog.android.di.ScreenComponent import com.innoprog.android.feature.feed.newsfeed.domain.models.PublicationType import com.innoprog.android.feature.profile.profiledetails.di.DaggerProfileComponent +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany @@ -24,11 +25,11 @@ class ProfileFragment : BaseFragment() { override val viewModel by injectViewModel() private val publicationsAdapter: PublicationsRecyclerAdapter by lazy { PublicationsRecyclerAdapter(publications) { publication -> - when (publication) { + when (publication.feedWrapper) { is FeedWrapper.Idea -> { val action = ProfileFragmentDirections.actionProfileFragmentToIdeaDetailsFragment( - publication.id + publication.feedWrapper.id ) findNavController().navigate(action) } @@ -36,15 +37,16 @@ class ProfileFragment : BaseFragment() { is FeedWrapper.News -> { val action = ProfileFragmentDirections.actionProfileFragmentToNewsDetailsFragment( - publication.id + publication.feedWrapper.id ) findNavController().navigate(action) } } } } + private var user: Profile? = null - private var publications: ArrayList = arrayListOf() + private var publications: ArrayList = arrayListOf() override fun diComponent(): ScreenComponent { return DaggerProfileComponent diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt index 03ce10ee..055af841 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsRecyclerAdapter.kt @@ -4,11 +4,11 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.innoprog.android.databinding.ItemNewsBinding -import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject class PublicationsRecyclerAdapter( - var publications: ArrayList, - private val onPublicationClick: (FeedWrapper) -> Unit + var publications: ArrayList, + private val onPublicationClick: (FeedWithProject) -> Unit ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PublicationsViewHolder { diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt index 76cc1f0a..37e51df3 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/adapter/PublicationsViewHolder.kt @@ -6,6 +6,7 @@ import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.innoprog.android.R import com.innoprog.android.databinding.ItemNewsBinding +import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWithProject import com.innoprog.android.feature.profile.profiledetails.domain.models.FeedWrapper class PublicationsViewHolder(private val binding: ItemNewsBinding) : @@ -13,29 +14,29 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : private val radius = binding.root.resources.getDimensionPixelSize(R.dimen.corner_radius_8) - fun bind(publication: FeedWrapper) { + fun bind(publication: FeedWithProject) { bindCommonData(publication) - when (publication) { + when (publication.feedWrapper) { is FeedWrapper.Idea -> bindIdeaData() - is FeedWrapper.News -> bindNewsData() + is FeedWrapper.News -> bindNewsData(publication) } } - private fun bindCommonData(publication: FeedWrapper) { + private fun bindCommonData(publication: FeedWithProject) { with(binding) { - tvPublicationTitle.text = publication.title - tvPublicationContent.text = publication.content - tvPublicationAuthorName.text = publication.author.name - tvCommentsCount.text = publication.commentsCount.toString() - tvLikesCount.text = publication.likesCount.toString() + tvPublicationTitle.text = publication.feedWrapper.title + tvPublicationContent.text = publication.feedWrapper.content + tvPublicationAuthorName.text = publication.feedWrapper.author.name + tvCommentsCount.text = publication.feedWrapper.commentsCount.toString() + tvLikesCount.text = publication.feedWrapper.likesCount.toString() - val initials = publication.author.name + val initials = publication.feedWrapper.author.name .split(' ') .map { it.first().uppercaseChar() } .joinToString(separator = "", limit = 2) publicationAuthorAvatar.text = initials.ifBlank { "?" } - publication.attachments?.firstOrNull()?.let { attachment -> + publication.feedWrapper.attachments?.firstOrNull()?.let { attachment -> Glide .with(itemView) .load(attachment.filePath) @@ -53,21 +54,21 @@ class PublicationsViewHolder(private val binding: ItemNewsBinding) : } } - private fun bindNewsData() { + private fun bindNewsData(publication: FeedWithProject) { with(binding) { ivIdea.isVisible = false projectCard.isVisible = true Glide .with(itemView) - .load("https://example.com/project_logo") + .load(publication.project?.logoUrl) .placeholder(R.drawable.ic_placeholder_logo) .centerCrop() .transform(RoundedCorners(radius)) .into(ivProjectLogo) - tvProjectName.text = "News Project" - tvProjectDirection.text = "IT" + tvProjectName.text = publication.project?.name + tvProjectDirection.text = publication.project?.area } } } \ No newline at end of file From 40ebd3a2c315a9b19dfe85642ca1031e5675aaff Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 10 Jul 2024 22:50:18 +0300 Subject: [PATCH 39/40] fix after detekt --- .../data/network/ProfileRetrofitClient.kt | 27 +++++++++---------- .../presentation/ProfileViewModel.kt | 1 - 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt index 9848a155..dbf4706e 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileRetrofitClient.kt @@ -36,12 +36,13 @@ class ProfileRetrofitClient @Inject constructor( return when (dto) { is RequestByProfile.GetProfile -> mapToResponse(service.loadProfile()) { it } - is RequestByProfile.GetProfileCompany -> { + is RequestByProfile.GetProfileCompany -> mapToResponse(service.loadProfileCompany()) { it } - } - is RequestByProfile.GetAll -> { - mapToResponse(service.getAll(dto.authorId)) { ChipsResponse(it) } + is RequestByProfile.GetAll -> mapToResponse(service.getAll(dto.authorId)) { + ChipsResponse( + it + ) } is RequestByProfile.GetProjects -> { @@ -53,32 +54,27 @@ class ProfileRetrofitClient @Inject constructor( ) { ChipsResponse(it) } } - is RequestByProfile.GetIdeas -> { + is RequestByProfile.GetIdeas -> mapToResponse( service.getIdeas( type = PublicationType.IDEA.value, authorId = dto.authorId ) ) { ChipsResponse(it) } - } - is RequestByProfile.GetLikes -> { + is RequestByProfile.GetLikes -> mapToResponse(service.getLikes(pageSize = PAGE_SIZE)) { ChipsResponse(it) } - } - is RequestByProfile.GetFavorites -> { + is RequestByProfile.GetFavorites -> mapToResponse(service.getFavorites(pageSize = PAGE_SIZE)) { ChipsResponse(it) - } - } - is RequestByProfile.GetProjectById -> { - mapToResponse(service.getProjectById(dto.id)) { - it } - } + + is RequestByProfile.GetProjectById -> mapToResponse(service.getProjectById(dto.id)) { it } + else -> throw IllegalArgumentException("Unsupported request type") } } @@ -112,6 +108,7 @@ class ProfileRetrofitClient @Inject constructor( } companion object { + private const val PAGE_SIZE = 50 } } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt index b3027695..9de22eeb 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileViewModel.kt @@ -35,7 +35,6 @@ class ProfileViewModel @Inject constructor( val chipsUiState: LiveData = _chipsUiState fun loadProfile() { - runSafelyUseCase( getUseCaseFlow = { getProfileUseCase.getProfile() }, onFailure = { error -> _uiState.postValue(ProfileScreenState.Error(error)) } From d3173f028846f034db0b3daeefe4dc88b87c6c91 Mon Sep 17 00:00:00 2001 From: NadezhdaSakal Date: Wed, 10 Jul 2024 23:43:04 +0300 Subject: [PATCH 40/40] add arguments --- .../editingprofile/data/impl/EditProfileInfoRepoImpl.kt | 3 +-- .../profiledetails/data/impl/ProfileInfoRepoImpl.kt | 8 ++++---- .../profile/profiledetails/data/network/ProfileApi.kt | 2 ++ .../profiledetails/presentation/ProfileFragment.kt | 9 +++++++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt index 2985383b..51dba1be 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/editingprofile/data/impl/EditProfileInfoRepoImpl.kt @@ -85,9 +85,8 @@ class EditProfileInfoRepoImpl @Inject constructor( } private fun getErrorType(code: Int): ErrorType = when (code) { - ApiConstants.NO_CONNECTION -> ErrorType.NO_CONNECTION + ApiConstants.NO_INTERNET_CONNECTION_CODE -> ErrorType.NO_CONNECTION ApiConstants.BAD_REQUEST_CODE -> ErrorType.BAD_REQUEST - ApiConstants.CAPTCHA_REQUIRED -> ErrorType.CAPTCHA_REQUIRED ApiConstants.NOT_FOUND -> ErrorType.NOT_FOUND else -> ErrorType.UNEXPECTED } diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt index ac2d0f84..a19e9777 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/impl/ProfileInfoRepoImpl.kt @@ -1,13 +1,13 @@ package com.innoprog.android.feature.profile.profiledetails.data.impl import com.innoprog.android.db.RoomDB +import com.innoprog.android.feature.profile.common.ProfileCompanyResponse +import com.innoprog.android.feature.profile.common.ProfileResponse import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileCompanyEntity import com.innoprog.android.feature.profile.profiledetails.data.db.ProfileEntity -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileCompanyResponse -import com.innoprog.android.feature.profile.profiledetails.data.network.ProfileResponse import com.innoprog.android.feature.profile.profiledetails.data.network.RequestByProfile -import com.innoprog.android.feature.profile.profiledetails.data.network.mapToDomainCompany -import com.innoprog.android.feature.profile.profiledetails.data.network.mapToDomainUserData +import com.innoprog.android.feature.profile.common.mapToDomainCompany +import com.innoprog.android.feature.profile.common.mapToDomainUserData import com.innoprog.android.feature.profile.profiledetails.domain.ProfileInfoRepo import com.innoprog.android.feature.profile.profiledetails.domain.models.Profile import com.innoprog.android.feature.profile.profiledetails.domain.models.ProfileCompany diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt index a3ab8e80..57f92c90 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/data/network/ProfileApi.kt @@ -1,5 +1,7 @@ package com.innoprog.android.feature.profile.profiledetails.data.network +import com.innoprog.android.feature.profile.common.ProfileCompanyResponse +import com.innoprog.android.feature.profile.common.ProfileResponse import com.innoprog.android.feature.profile.profiledetails.data.dto.model.FeedDto import com.innoprog.android.feature.profile.profiledetails.data.dto.model.ProjectDto import retrofit2.Response diff --git a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt index 30406949..7a61bb78 100644 --- a/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt +++ b/app/src/main/java/com/innoprog/android/feature/profile/profiledetails/presentation/ProfileFragment.kt @@ -46,6 +46,7 @@ class ProfileFragment : BaseFragment() { } private var user: Profile? = null + private var userCompany: ProfileCompany? = null private var publications: ArrayList = arrayListOf() override fun diComponent(): ScreenComponent { @@ -120,8 +121,12 @@ class ProfileFragment : BaseFragment() { private fun initTopBar() { binding.topbarProfile.setRightIconClickListener { - val direction = ProfileFragmentDirections.actionProfileFragmentToProfileBottomSheet() - findNavController().navigate(direction) + user?.let { user -> + userCompany?.let { company -> + val direction = ProfileFragmentDirections.actionProfileFragmentToProfileBottomSheet(user, company) + findNavController().navigate(direction) + } + } } }