Skip to content

Commit

Permalink
Merge pull request #230 from School-of-Company/feature/229-training-l…
Browse files Browse the repository at this point in the history
…ist-training-teacher-list-qr-code-scan

🔀 :: (#229) - 연수 프로그램 리스트, 프로그램별 교원연수 리스트 출석부 불러오기 및 연수 QR인식 기능을 구현하였습니다.
  • Loading branch information
audgns10 authored Dec 10, 2024
2 parents 7c8c61a + 39ec316 commit d21cc0d
Show file tree
Hide file tree
Showing 44 changed files with 1,155 additions and 244 deletions.
9 changes: 9 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />

<uses-feature android:name="android.hardware.camera" />

<application
android:name=".ExpoApplication"
android:allowBackup="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import com.school_of_company.home.navigation.homeDetailParticipantManagementScre
import com.school_of_company.home.navigation.homeDetailProgramParticipantScreen
import com.school_of_company.home.navigation.homeDetailProgramScreen
import com.school_of_company.home.navigation.homeSendMessageScreen
import com.school_of_company.home.navigation.navigateQrScanner
import com.school_of_company.home.navigation.navigateToHomeDetailParticipantManagement
import com.school_of_company.home.navigation.navigateToHomeDetailProgram
import com.school_of_company.home.navigation.navigateToHomeDetailProgramParticipant
import com.school_of_company.home.navigation.navigateToHomeSendMessage
import com.school_of_company.home.navigation.qrScannerScreen
import com.school_of_company.navigation.navigateToSignIn
import com.school_of_company.navigation.sigInRoute
import com.school_of_company.navigation.signInScreen
Expand Down Expand Up @@ -133,7 +135,9 @@ fun ExpoNavHost(
onModifyClick = { id ->
navController.navigateToExpoModify(id)
},
onProgramClick = navController::navigateToHomeDetailProgram
onProgramClick = { id ->
navController.navigateToHomeDetailProgram(id)
}
)

homeSendMessageScreen(
Expand All @@ -142,11 +146,14 @@ fun ExpoNavHost(

homeDetailProgramScreen(
onBackClick = navController::popBackStack,
navigateToProgramDetail = navController::navigateToHomeDetailProgramParticipant
navigateToProgramDetail = { id ->
navController.navigateToHomeDetailProgramParticipant(id)
}
)

homeDetailProgramParticipantScreen(
onBackClick = navController::popBackStack
onBackClick = navController::popBackStack,
navigateToQrScanner = navController::navigateQrScanner
)

homeDetailParticipantManagementScreen(
Expand All @@ -161,5 +168,10 @@ fun ExpoNavHost(
expoCreateScreen(
onErrorToast = makeErrorToast
)

qrScannerScreen(
onBackClick = navController::popBackStack,
onPermissionBlock = navController::popBackStack
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ fun ExpoApp(
}
) { paddingValues ->
// 네비게이션 호스트
Box(modifier = Modifier.padding(paddingValues =
paddingValues)) {
Box(modifier = Modifier.padding(paddingValues = paddingValues)) {
ExpoNavHost(appState = appState)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.school_of_company.data.di

import com.school_of_company.data.repository.attendance.AttendanceRepository
import com.school_of_company.data.repository.attendance.AttendanceRepositoryImpl
import com.school_of_company.data.repository.auth.AuthRepository
import com.school_of_company.data.repository.auth.AuthRepositoryImpl
import com.school_of_company.data.repository.expo.ExpoRepository
Expand Down Expand Up @@ -50,4 +52,9 @@ abstract class RepositoryModule {
abstract fun bindStandardRepository(
standardRepositoryImpl: StandardRepositoryImpl
) : StandardRepository

@Binds
abstract fun bindAttendanceRepository(
attendanceRepositoryImpl: AttendanceRepositoryImpl
) : AttendanceRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.school_of_company.data.repository.attendance

import com.school_of_company.model.param.attendance.TrainingQrCodeRequestParam
import kotlinx.coroutines.flow.Flow

interface AttendanceRepository {
fun trainingQrCode(trainingId: Long, body: TrainingQrCodeRequestParam) : Flow<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.school_of_company.data.repository.attendance

import com.school_of_company.model.param.attendance.TrainingQrCodeRequestParam
import com.school_of_company.network.datasource.attendance.AttendanceDataSource
import com.school_of_company.network.mapper.attendance.request.toDto
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class AttendanceRepositoryImpl @Inject constructor(
private val dataSource: AttendanceDataSource
) : AttendanceRepository {
override fun trainingQrCode(
trainingId: Long,
body: TrainingQrCodeRequestParam
): Flow<Unit> {
return dataSource.trainingQrCode(
trainingId = trainingId,
body = body.toDto()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.school_of_company.domain.usecase.attendance

import com.school_of_company.data.repository.attendance.AttendanceRepository
import com.school_of_company.model.param.attendance.TrainingQrCodeRequestParam
import javax.inject.Inject

class TrainingQrCodeRequestUseCase @Inject constructor(
private val repository: AttendanceRepository
) {
operator fun invoke(
trainingId: Long,
body: TrainingQrCodeRequestParam
) = runCatching {
repository.trainingQrCode(
trainingId = trainingId,
body = body
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.school_of_company.model.entity.training

data class TeacherTrainingProgramResponseEntity(
val id: Long,
val name: String,
val organization: String,
val position: String,
val programName: String,
val status: Boolean,
val entryTime: String,
val leaveTime: String
val entryTime: String?,
val leaveTime: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.school_of_company.model.param.attendance

data class TrainingQrCodeRequestParam (
val traineeId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.school_of_company.network.api

import com.school_of_company.network.dto.attendance.request.TrainingQrCodeRequest
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Path

interface AttendanceAPI {

@GET("/attendance/training/{trainingPro_id}")
suspend fun trainingQrCode(
@Path("trainingPro_id") trainingId: Long,
@Body body: TrainingQrCodeRequest
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.school_of_company.network.datasource.attendance

import com.school_of_company.network.dto.attendance.request.TrainingQrCodeRequest
import kotlinx.coroutines.flow.Flow

interface AttendanceDataSource {
fun trainingQrCode(trainingId: Long, body: TrainingQrCodeRequest) : Flow<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.school_of_company.network.datasource.attendance

import com.school_of_company.network.api.AttendanceAPI
import com.school_of_company.network.dto.attendance.request.TrainingQrCodeRequest
import com.school_of_company.network.util.performApiRequest
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class AttendanceDataSourceImpl @Inject constructor(
private val service: AttendanceAPI
) : AttendanceDataSource {
override fun trainingQrCode(
trainingId: Long,
body: TrainingQrCodeRequest
): Flow<Unit> =
performApiRequest { service.trainingQrCode(
body = body,
trainingId = trainingId
) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.util.Log
import com.readystatesoftware.chuck.ChuckInterceptor
import com.school_of_company.network.BuildConfig
import com.school_of_company.network.api.AttendanceAPI
import com.school_of_company.network.api.AuthAPI
import com.school_of_company.network.api.ExpoAPI
import com.school_of_company.network.api.ImageAPI
Expand Down Expand Up @@ -114,4 +115,7 @@ object NetworkModule {
fun provideStandardAPI(retrofit: Retrofit) : StandardAPI =
retrofit.create(StandardAPI::class.java)

@Provides
fun provideAttendanceAPI(retrofit: Retrofit) : AttendanceAPI =
retrofit.create(AttendanceAPI::class.java)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.school_of_company.network.di

import com.school_of_company.network.datasource.attendance.AttendanceDataSource
import com.school_of_company.network.datasource.attendance.AttendanceDataSourceImpl
import com.school_of_company.network.datasource.auth.AuthDataSource
import com.school_of_company.network.datasource.auth.AuthDataSourceImpl
import com.school_of_company.network.datasource.expo.ExpoDataSource
Expand Down Expand Up @@ -50,4 +52,9 @@ abstract class RemoteDataSourceModule {
abstract fun bindStandardRemoteDataSource(
standardDataSourceImpl: StandardDataSourceImpl
) : StandardDataSource

@Binds
abstract fun bindAttendanceRemoteDataSource(
attendanceDataSourceImpl: AttendanceDataSourceImpl
) : AttendanceDataSource
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.school_of_company.network.dto.attendance.request

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class TrainingQrCodeRequest(
@Json(name = "traineeId") val traineeId: Long
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class TeacherTrainingProgramResponse(
@Json(name = "id") val id: Long,
@Json(name = "name") val name: String,
@Json(name = "organization") val organization: String,
@Json(name = "position") val position: String,
@Json(name = "programName") val programName: String,
@Json(name = "status") val status: Boolean,
@Json(name = "entryTime") val entryTime: String,
@Json(name = "leaveTime") val leaveTime: String
@Json(name = "entryTime") val entryTime: String?,
@Json(name = "leaveTime") val leaveTime: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.school_of_company.network.mapper.attendance.request

import com.school_of_company.model.param.attendance.TrainingQrCodeRequestParam
import com.school_of_company.network.dto.attendance.request.TrainingQrCodeRequest

fun TrainingQrCodeRequestParam.toDto(): TrainingQrCodeRequest =
TrainingQrCodeRequest(traineeId = traineeId)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.school_of_company.network.dto.training.response.TeacherTrainingProgra

fun TeacherTrainingProgramResponse.toEntity(): TeacherTrainingProgramResponseEntity =
TeacherTrainingProgramResponseEntity(
id = this.id,
name = this.name,
organization = this.organization,
position = this.position,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ fun NavGraphBuilder.expoDetailScreen(
onCheckClick: () -> Unit,
onQrGenerateClick: () -> Unit,
onModifyClick: (String) -> Unit,
onProgramClick: () -> Unit
onProgramClick: (String) -> Unit
) {
composable(route = "$expoDetailRoute/{id}") { backStackEntry ->
val id = backStackEntry.arguments?.getString("id") ?: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ internal fun ExpoCreateRoute(
description = viewModel.introduce_title.value,
location = viewModel.location.value,
coverImage = (imageUpLoadUiState as ImageUpLoadUiState.Success).data.imageURL,
x = 35.14308f,
y = 126.80043f
x = 37.511734f,
y = 127.05905f
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal fun ExpoDetailRoute(
onCheckClick: () -> Unit,
onQrGenerateClick: () -> Unit,
onModifyClick: (String) -> Unit,
onProgramClick: () -> Unit,
onProgramClick: (String) -> Unit,
viewModel: ExpoViewModel = hiltViewModel()
) {
val getExpoInformationUiState by viewModel.getExpoInformationUiState.collectAsStateWithLifecycle()
Expand Down Expand Up @@ -92,7 +92,7 @@ internal fun ExpoDetailScreen(
onCheckClick: () -> Unit,
onQrGenerateClick: () -> Unit,
onModifyClick: (String) -> Unit,
onProgramClick: () -> Unit
onProgramClick: (String) -> Unit
) {
val (openDialog, isOpenDialog) = rememberSaveable { mutableStateOf(false) }
val (openQrDialog, isOpenQrDialog) = rememberSaveable { mutableStateOf(false) }
Expand Down Expand Up @@ -296,7 +296,7 @@ internal fun ExpoDetailScreen(

ExpoEnableDetailButton(
text = "프로그램",
onClick = onProgramClick,
onClick = { onProgramClick(id) },
modifier = Modifier
.fillMaxWidth()
.border(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ private fun HomeBottomSheetOptions(
indication = ripple(color = rippleColor),
interactionSource = remember { MutableInteractionSource() }
)
.padding(horizontal = 12.dp)
) {
Text(
text = text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.school_of_company.model.model.expo.ExpoRequestAndResponseModel
import com.school_of_company.model.model.standard.StandardRequestModel
import com.school_of_company.model.model.training.TrainingDtoModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
Expand Down
14 changes: 14 additions & 0 deletions feature/home/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,18 @@ dependencies {

implementation(libs.mlkit)
implementation(libs.zxing.core)

implementation(libs.swiperefresh)

implementation(libs.camera.core)
implementation(libs.camera.view)
implementation(libs.camera.camera2)
implementation(libs.camera.lifecycle)
implementation(libs.camera.extensions)

implementation(libs.accompanist.permission)

implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.play.services)

}
Loading

0 comments on commit d21cc0d

Please sign in to comment.