Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
10 changes: 3 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.compose'
}

android {
Expand Down Expand Up @@ -46,10 +47,6 @@ android {
buildConfig true
}

composeOptions {
kotlinCompilerExtensionVersion '1.5.14'
}

packaging {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
Expand All @@ -72,12 +69,13 @@ dependencies {
implementation 'androidx.compose.foundation:foundation'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.compose.runtime:runtime-saveable'
implementation 'androidx.compose.runtime:runtime-livedata'

debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

implementation 'androidx.navigation:navigation-compose:2.8.5'

implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7'

implementation 'com.squareup.retrofit2:retrofit:2.11.0'
Expand All @@ -100,6 +98,4 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

implementation 'androidx.compose.runtime:runtime-livedata'
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.example.goodroad.data.network.GoodRoadApi
import com.example.goodroad.modules.auth.data.AuthApi
import com.example.goodroad.modules.review.data.ReviewApi
import com.example.goodroad.modules.user.data.UserApi
import com.example.goodroad.modules.volunteer.data.VolunteerApi

object ApiClient {

Expand Down Expand Up @@ -96,5 +97,9 @@ object ApiClient {
val routeApi: GoodRoadApi by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
retrofit().create(GoodRoadApi::class.java)
}

val volunteerApi: VolunteerApi by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
retrofit().create(VolunteerApi::class.java)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Map
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.VolunteerActivism
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
Expand All @@ -14,6 +15,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.goodroad.data.network.ApiClient
import com.example.goodroad.data.obstacle.ObstacleRepository
import com.example.goodroad.modules.volunteer.presentation.VolunteerViewModel
import com.example.goodroad.modules.volunteer.screens.HelpRequestCreateScreen
import com.example.goodroad.modules.volunteer.screens.VolunteerScreen
import com.example.goodroad.modules.volunteer.screens.UserHelpRequestsScreen
import com.example.goodroad.modules.maps.presentation.MapsViewModel
import com.example.goodroad.modules.maps.screens.MapRouteScreen
import com.example.goodroad.modules.maps.screens.ObstacleSelectScreen
Expand All @@ -26,10 +31,13 @@ import com.example.goodroad.modules.user.presentation.UserViewModel
import com.example.goodroad.modules.user.screens.UserEditScreen
import com.example.goodroad.ui.user.UserDeleteAccountScreen
import com.example.goodroad.ui.user.UserProfileScreen
import com.example.goodroad.ui.volunteer.screens.VolunteerApplicationFormScreen
import com.example.goodroad.modules.volunteer.data.VolunteerRepository

enum class BottomTab {
MAP,
REVIEWS,
HELP,
PROFILE
}

Expand All @@ -39,7 +47,10 @@ enum class OverlayScreen {
DELETE_PROFILE,
REVIEW_FORM,
REVIEW_DETAILS,
OBSTACLES
OBSTACLES,
HELP_CREATE,
HELP_MY_REQUESTS,
VOLUNTEER_APPLICATION
}

@Composable
Expand All @@ -50,6 +61,7 @@ fun UserNav(
val userApi = ApiClient.userApi
val reviewApi = ApiClient.reviewApi
val obstacleApi = ApiClient.obstacleApi
val volunteerApi = ApiClient.volunteerApi

val userFactory = object : ViewModelProvider.Factory {
override fun <T : androidx.lifecycle.ViewModel> create(modelClass: Class<T>): T {
Expand All @@ -73,9 +85,21 @@ fun UserNav(
}
}

val helpFactory = object : ViewModelProvider.Factory {
override fun <T : androidx.lifecycle.ViewModel> create(
modelClass: Class<T>
): T {

return VolunteerViewModel(
VolunteerRepository(volunteerApi)
) as T
}
}

val userViewModel: UserViewModel = viewModel(factory = userFactory)
val reviewsViewModel: ReviewsViewModel = viewModel(factory = reviewsFactory)
val mapsViewModel: MapsViewModel = viewModel(factory = mapsFactory)
val helpViewModel: VolunteerViewModel = viewModel(factory = helpFactory)

var currentTab by rememberSaveable { mutableStateOf(BottomTab.MAP) }
var overlayScreen by remember { mutableStateOf(OverlayScreen.NONE) }
Expand Down Expand Up @@ -105,6 +129,20 @@ fun UserNav(
label = { Text("Отзывы") }
)

NavigationBarItem(
selected = currentTab == BottomTab.HELP,
onClick = {
currentTab = BottomTab.HELP
overlayScreen = OverlayScreen.NONE
},
icon = {
Icon(Icons.Default.VolunteerActivism, null)
},
label = {
Text("Помощь")
}
)

NavigationBarItem(
selected = currentTab == BottomTab.PROFILE,
onClick = {
Expand Down Expand Up @@ -150,6 +188,18 @@ fun UserNav(
)
}

BottomTab.HELP -> {
VolunteerScreen(
helpViewModel = helpViewModel,
onCreateRequest = {
overlayScreen = OverlayScreen.HELP_CREATE
},
onMyRequests = {
overlayScreen = OverlayScreen.HELP_MY_REQUESTS
}
)
}

BottomTab.PROFILE -> {
UserProfileScreen(
userViewModel = userViewModel,
Expand All @@ -158,6 +208,9 @@ fun UserNav(
onLogout = onLogout,
onSelectObstacles = {
overlayScreen = OverlayScreen.OBSTACLES
},
onBecomeVolunteer = {
overlayScreen = OverlayScreen.VOLUNTEER_APPLICATION
}
)
}
Expand Down Expand Up @@ -201,9 +254,7 @@ fun UserNav(
review = review,
reviewsViewModel = reviewsViewModel,
onBack = { overlayScreen = OverlayScreen.NONE },
onEdit = {
overlayScreen = OverlayScreen.REVIEW_FORM
},
onEdit = { overlayScreen = OverlayScreen.REVIEW_FORM },
onDeleted = {
selectedReview = null
overlayScreen = OverlayScreen.NONE
Expand All @@ -222,6 +273,26 @@ fun UserNav(
)
}

OverlayScreen.HELP_CREATE -> {
HelpRequestCreateScreen(
helpViewModel = helpViewModel,
onBack = { overlayScreen = OverlayScreen.NONE },
onCreated = { overlayScreen = OverlayScreen.NONE }
)
}

OverlayScreen.HELP_MY_REQUESTS -> {
UserHelpRequestsScreen(viewModel = helpViewModel)
}

OverlayScreen.VOLUNTEER_APPLICATION -> {
VolunteerApplicationFormScreen(
viewModel = helpViewModel,
onBack = { overlayScreen = OverlayScreen.NONE },
onSubmitted = { overlayScreen = OverlayScreen.NONE }
)
}

OverlayScreen.NONE -> Unit
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.example.goodroad.ui.user

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import coil.compose.AsyncImage
import com.example.goodroad.modules.user.presentation.UserViewModel
import com.example.goodroad.ui.UserDecor
Expand All @@ -24,7 +24,8 @@ fun UserProfileScreen(
onEdit: () -> Unit,
onDelete: () -> Unit,
onLogout: () -> Unit,
onSelectObstacles: () -> Unit
onSelectObstacles: () -> Unit,
onBecomeVolunteer: () -> Unit = {}
) {
val user by userViewModel.user
val isLoading by userViewModel.isLoading
Expand Down Expand Up @@ -91,7 +92,6 @@ fun UserProfileScreen(
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {

Column(
modifier = Modifier.weight(1f)
) {
Expand All @@ -112,7 +112,6 @@ fun UserProfileScreen(
}

if (!u.photoUrl.isNullOrBlank()) {

AsyncImage(
model = u.photoUrl,
contentDescription = "Фото профиля",
Expand All @@ -121,9 +120,7 @@ fun UserProfileScreen(
.clip(CircleShape),
contentScale = ContentScale.Crop
)

} else {

Surface(
modifier = Modifier.size(90.dp),
shape = CircleShape,
Expand All @@ -148,7 +145,6 @@ fun UserProfileScreen(
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.fillMaxWidth()
) {

PrimaryButton(
text = "Выбрать препятствия",
backgroundColor = UrbanBrown,
Expand All @@ -157,6 +153,14 @@ fun UserProfileScreen(
onSelectObstacles()
}

PrimaryButton(
text = "Стать волонтёром",
backgroundColor = UrbanBrown,
contentColor = WhiteSoft
) {
onBecomeVolunteer()
}

PrimaryButton(
text = "Редактировать профиль",
onClick = onEdit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.example.goodroad.modules.volunteer.data

import com.example.goodroad.modules.volunteer.data.models.*
import okhttp3.MultipartBody
import retrofit2.http.*

interface VolunteerApi {

@GET("volunteer/menu")
suspend fun getMenu(): VolunteerMenuRespDto

@POST("volunteer/applications")
suspend fun createApplication(
@Body req: CreateVolunteerApplicationReqDto
): VolunteerApplicationRespDto

@Multipart
@POST("volunteer/applications/photos")
suspend fun uploadCertificate(
@Part file: MultipartBody.Part
): PhotoUploadRespDto

@GET("volunteer/requests/own")
suspend fun listOwnRequests(): List<HelpRequestRespDto>

@POST("volunteer/requests")
suspend fun createHelpRequest(
@Body req: HelpRequestCreateReqDto
): HelpRequestRespDto

@GET("volunteer/requests/available")
suspend fun listAvailableRequests(
@Query("latitude") latitude: Double? = null,
@Query("longitude") longitude: Double? = null
): List<HelpRequestRespDto>

@GET("volunteer/requests/my-wards")
suspend fun listMyWards(): List<HelpRequestRespDto>

@GET("volunteer/requests/{id}")
suspend fun getHelpRequest(
@Path("id") id: String
): HelpRequestRespDto

@POST("volunteer/requests/{id}/accept")
suspend fun acceptRequest(
@Path("id") id: String
): HelpRequestRespDto

@POST("volunteer/requests/{id}/withdraw")
suspend fun withdrawResponse(
@Path("id") id: String
): HelpRequestRespDto

@POST("volunteer/requests/{id}/cancel")
suspend fun cancelOwnRequest(
@Path("id") id: String
): HelpRequestRespDto

@DELETE("volunteer/requests/{id}")
suspend fun deleteOwnRequest(
@Path("id") id: String
)

@POST("volunteer/requests/{id}/route")
suspend fun setWalkRoute(
@Path("id") id: String,
@Body req: WalkRouteReqDto
): HelpRequestRespDto

@POST("volunteer/requests/{id}/start")
suspend fun startWalk(
@Path("id") id: String,
@Body req: WalkRouteReqDto? = null
): HelpRequestRespDto

@POST("volunteer/requests/{id}/finish")
suspend fun finishWalk(
@Path("id") id: String
): HelpRequestRespDto
}
Loading