diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f79ce79..b7fb28a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,12 +32,25 @@ android:exported="true" android:label="@string/app_name" android:theme="@style/Theme.Tiggle" + android:launchMode="singleTop" android:windowSoftInputMode="adjustResize"> + + + + + + + + + + diff --git a/app/src/main/java/com/ssafy/tiggle/MainActivity.kt b/app/src/main/java/com/ssafy/tiggle/MainActivity.kt index 9cf31dd..689bb38 100644 --- a/app/src/main/java/com/ssafy/tiggle/MainActivity.kt +++ b/app/src/main/java/com/ssafy/tiggle/MainActivity.kt @@ -14,14 +14,15 @@ import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.ui.platform.LocalContext import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat -import com.google.firebase.messaging.FirebaseMessaging - +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.ssafy.tiggle.presentation.navigation.NavigationGraph import com.ssafy.tiggle.presentation.ui.theme.TiggleTheme import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.MutableStateFlow /** * 메인 액티비티 @@ -29,13 +30,17 @@ import dagger.hilt.android.AndroidEntryPoint */ @AndroidEntryPoint class MainActivity : ComponentActivity() { + // 1. 딥링크 Intent를 담을 StateFlow 생성 + private val deepLinkIntent = MutableStateFlow(null) + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() - - // ✅ 디버그용: 현재 기기의 FCM 토큰 로그로 확인 - FirebaseMessaging.getInstance().token.addOnSuccessListener { - Log.d("TiggleFCM", "FCM token = $it") + + // 2. 앱 시작 시 초기 Intent가 딥링크를 포함하는지 확인 + if (intent?.data != null) { + deepLinkIntent.value = intent } setContent { @@ -43,10 +48,24 @@ class MainActivity : ComponentActivity() { // ✅ Android 13+ 알림 권한 1회 요청 RequestPostNotificationsPermissionOnce() // ⬇️ 기존 네비게이션 - NavigationGraph() + val intentState by deepLinkIntent.collectAsStateWithLifecycle() + NavigationGraph( + intent = intentState, + // 6. 딥링크 처리가 완료되면 StateFlow를 null로 비워주는 콜백 전달 + onDeepLinkHandled = { deepLinkIntent.value = null } + ) } } } + + // 4. 앱이 백그라운드에 있을 때 새 Intent를 받는 부분 + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + // 5. 새로 받은 Intent로 StateFlow를 업데이트 -> Compose에 변경 사항 알림 + if (intent.data != null) { + deepLinkIntent.value = intent + } + } } /** Android 13+에서 POST_NOTIFICATIONS 권한 1회 요청 */ diff --git a/app/src/main/java/com/ssafy/tiggle/core/fcm/TiggleMessageService.kt b/app/src/main/java/com/ssafy/tiggle/core/fcm/TiggleMessageService.kt index 0ad2d40..b10732c 100644 --- a/app/src/main/java/com/ssafy/tiggle/core/fcm/TiggleMessageService.kt +++ b/app/src/main/java/com/ssafy/tiggle/core/fcm/TiggleMessageService.kt @@ -97,6 +97,11 @@ class TiggleMessagingService : FirebaseMessagingService() { val intent = Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + // 딥링크 정보를 Intent에 추가 + if (deepLink != null) { + // URI 형태로 설정하여 NavigationGraph에서 처리할 수 있도록 함 + data = android.net.Uri.parse(deepLink) + } } val pending = PendingIntent.getActivity( this, 0, intent, diff --git a/app/src/main/java/com/ssafy/tiggle/core/utils/Formatter.kt b/app/src/main/java/com/ssafy/tiggle/core/utils/Formatter.kt index fbf0c5d..ed2a398 100644 --- a/app/src/main/java/com/ssafy/tiggle/core/utils/Formatter.kt +++ b/app/src/main/java/com/ssafy/tiggle/core/utils/Formatter.kt @@ -1,5 +1,9 @@ package com.ssafy.tiggle.core.utils +import android.annotation.SuppressLint +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException import java.util.Locale object Formatter { @@ -7,4 +11,63 @@ object Formatter { fun formatCurrency(amount: Long, locale: Locale = Locale.KOREA): String = String.format(locale, "%,d원", amount) + // ISO 8601 날짜/시간 포맷팅: "2025-08-26T01:25:21" -> "2025.08.26 01:25" + @SuppressLint("NewApi") + fun formatDateTime(isoDateTime: String): String { + return try { + val dateTime = LocalDateTime.parse(isoDateTime) + val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm") + dateTime.format(formatter) + } catch (e: DateTimeParseException) { + // 파싱 실패 시 원본 문자열 반환 + isoDateTime + } + } + + // 간단한 날짜 포맷팅: "2025-08-26T01:25:21" -> "8월 26일" + @SuppressLint("NewApi") + fun formatDateOnly(isoDateTime: String): String { + return try { + val dateTime = LocalDateTime.parse(isoDateTime) + val formatter = DateTimeFormatter.ofPattern("M월 d일", Locale.KOREA) + dateTime.format(formatter) + } catch (e: DateTimeParseException) { + // 파싱 실패 시 원본 문자열 반환 + isoDateTime + } + } + + // 시간만 포맷팅: "2025-08-26T01:25:21" -> "오전 1:25" + @SuppressLint("NewApi") + fun formatTimeOnly(isoDateTime: String): String { + return try { + val dateTime = LocalDateTime.parse(isoDateTime) + val formatter = DateTimeFormatter.ofPattern("a h:mm", Locale.KOREA) + dateTime.format(formatter) + } catch (e: DateTimeParseException) { + // 파싱 실패 시 원본 문자열 반환 + isoDateTime + } + } + + // 상대적 시간 표시: "방금", "5분 전", "3시간 전", "2일 전" 등 + @SuppressLint("NewApi") + fun formatRelativeTime(isoDateTime: String): String { + return try { + val dateTime = LocalDateTime.parse(isoDateTime) + val now = LocalDateTime.now() + val duration = java.time.Duration.between(dateTime, now) + + when { + duration.toMinutes() < 1 -> "방금" + duration.toMinutes() < 60 -> "${duration.toMinutes()}분 전" + duration.toHours() < 24 -> "${duration.toHours()}시간 전" + duration.toDays() < 7 -> "${duration.toDays()}일 전" + else -> formatDateOnly(isoDateTime) + } + } catch (e: DateTimeParseException) { + // 파싱 실패 시 원본 문자열 반환 + isoDateTime + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/AuthApiService.kt b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/AuthApiService.kt index 3acdb69..20258ff 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/AuthApiService.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/AuthApiService.kt @@ -1,8 +1,8 @@ package com.ssafy.tiggle.data.datasource.remote import com.ssafy.tiggle.data.model.BaseResponse -import com.ssafy.tiggle.data.model.LoginRequestDto -import com.ssafy.tiggle.data.model.SignUpRequestDto +import com.ssafy.tiggle.data.model.auth.request.LoginRequestDto +import com.ssafy.tiggle.data.model.auth.request.SignUpRequestDto import retrofit2.Response import retrofit2.http.Body import retrofit2.http.POST diff --git a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/DutchPayApiService.kt b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/DutchPayApiService.kt index 55bc137..c5099ba 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/DutchPayApiService.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/DutchPayApiService.kt @@ -3,13 +3,21 @@ package com.ssafy.tiggle.data.datasource.remote import com.ssafy.tiggle.data.model.BaseResponse import com.ssafy.tiggle.data.model.EmptyResponse import com.ssafy.tiggle.data.model.dutchpay.request.DutchPayRequestDto +import com.ssafy.tiggle.data.model.dutchpay.response.DutchPayRequestDetailResponseDto import retrofit2.Response import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Path interface DutchPayApiService { @POST("/api/dutchpay/requests") suspend fun createDutchPayRequest( @Body request: DutchPayRequestDto ): Response> + + @GET("/api/dutchpay/requests/{id}") + suspend fun getDutchPayRequestDetail( + @Path("id") dutchPayId: Long + ): Response> } diff --git a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UniversityApiService.kt b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UniversityApiService.kt index e571946..4e4dedf 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UniversityApiService.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UniversityApiService.kt @@ -1,8 +1,8 @@ package com.ssafy.tiggle.data.datasource.remote import com.ssafy.tiggle.data.model.BaseResponse -import com.ssafy.tiggle.data.model.DepartmentDto -import com.ssafy.tiggle.data.model.UniversityDto +import com.ssafy.tiggle.data.model.auth.response.DepartmentDto +import com.ssafy.tiggle.data.model.auth.response.UniversityDto import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path diff --git a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UserApiService.kt b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UserApiService.kt index ce74042..5765282 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UserApiService.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/datasource/remote/UserApiService.kt @@ -1,7 +1,7 @@ package com.ssafy.tiggle.data.datasource.remote import com.ssafy.tiggle.data.model.BaseResponse -import com.ssafy.tiggle.data.model.UserSummaryDto +import com.ssafy.tiggle.data.model.dutchpay.response.UserSummaryDto import retrofit2.Response import retrofit2.http.GET diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/LoginRequestDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/auth/request/LoginRequestDto.kt similarity index 60% rename from app/src/main/java/com/ssafy/tiggle/data/model/LoginRequestDto.kt rename to app/src/main/java/com/ssafy/tiggle/data/model/auth/request/LoginRequestDto.kt index 19fba05..8454409 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/LoginRequestDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/auth/request/LoginRequestDto.kt @@ -1,6 +1,6 @@ -package com.ssafy.tiggle.data.model +package com.ssafy.tiggle.data.model.auth.request data class LoginRequestDto( val email: String, val password: String -) +) \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/SignUpRequestDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/auth/request/SignUpRequestDto.kt similarity index 83% rename from app/src/main/java/com/ssafy/tiggle/data/model/SignUpRequestDto.kt rename to app/src/main/java/com/ssafy/tiggle/data/model/auth/request/SignUpRequestDto.kt index b0c070d..ab48f0f 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/SignUpRequestDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/auth/request/SignUpRequestDto.kt @@ -1,4 +1,4 @@ -package com.ssafy.tiggle.data.model +package com.ssafy.tiggle.data.model.auth.request /** * 회원가입 요청 DTO @@ -11,4 +11,4 @@ data class SignUpRequestDto( val studentId: String, val password: String, val phone: String -) +) \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/DepartmentDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/auth/response/DepartmentDto.kt similarity index 88% rename from app/src/main/java/com/ssafy/tiggle/data/model/DepartmentDto.kt rename to app/src/main/java/com/ssafy/tiggle/data/model/auth/response/DepartmentDto.kt index 2b52ea2..f815f22 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/DepartmentDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/auth/response/DepartmentDto.kt @@ -1,4 +1,4 @@ -package com.ssafy.tiggle.data.model +package com.ssafy.tiggle.data.model.auth.response import com.ssafy.tiggle.domain.entity.auth.Department @@ -20,4 +20,4 @@ data class DepartmentDto( name = name ) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/UniversityDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/auth/response/UniversityDto.kt similarity index 88% rename from app/src/main/java/com/ssafy/tiggle/data/model/UniversityDto.kt rename to app/src/main/java/com/ssafy/tiggle/data/model/auth/response/UniversityDto.kt index f3ba932..c1c19b0 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/UniversityDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/auth/response/UniversityDto.kt @@ -1,4 +1,4 @@ -package com.ssafy.tiggle.data.model +package com.ssafy.tiggle.data.model.auth.response import com.ssafy.tiggle.domain.entity.auth.University @@ -20,4 +20,4 @@ data class UniversityDto( name = name ) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/UserDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/auth/response/UserDto.kt similarity index 93% rename from app/src/main/java/com/ssafy/tiggle/data/model/UserDto.kt rename to app/src/main/java/com/ssafy/tiggle/data/model/auth/response/UserDto.kt index ea83444..97c18b7 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/UserDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/auth/response/UserDto.kt @@ -1,4 +1,4 @@ -package com.ssafy.tiggle.data.model +package com.ssafy.tiggle.data.model.auth.response import com.ssafy.tiggle.domain.entity.auth.User @@ -32,6 +32,4 @@ data class UserDto( updatedAt = updatedAt ) } -} - - +} \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/request/DutchPayRequestDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/request/DutchPayRequestDto.kt index a2dbc15..217347b 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/request/DutchPayRequestDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/request/DutchPayRequestDto.kt @@ -6,4 +6,4 @@ data class DutchPayRequestDto( val title: String, val message: String, val payMore: Boolean -) +) \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/response/DutchPayRequestDetailResponseDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/response/DutchPayRequestDetailResponseDto.kt new file mode 100644 index 0000000..b9373e5 --- /dev/null +++ b/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/response/DutchPayRequestDetailResponseDto.kt @@ -0,0 +1,16 @@ +package com.ssafy.tiggle.data.model.dutchpay.response + +data class DutchPayRequestDetailResponseDto( + val dutchpayId: Long, + val title: String, + val message: String, + val requesterName: String, + val participantCount: Int, + val totalAmount: Long, + val requestedAt: String, + val myAmount: Long, + val originalAmount: Long, + val tiggleAmount: Long, + val payMoreDefault: Boolean, + val creator: Boolean +) \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/model/UserSummaryDto.kt b/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/response/UserSummaryDto.kt similarity index 82% rename from app/src/main/java/com/ssafy/tiggle/data/model/UserSummaryDto.kt rename to app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/response/UserSummaryDto.kt index dd65087..1a63e8f 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/model/UserSummaryDto.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/model/dutchpay/response/UserSummaryDto.kt @@ -1,4 +1,4 @@ -package com.ssafy.tiggle.data.model +package com.ssafy.tiggle.data.model.dutchpay.response import com.ssafy.tiggle.domain.entity.dutchpay.UserSummary @@ -13,6 +13,4 @@ data class UserSummaryDto( id = id, name = name ) -} - - +} \ No newline at end of file diff --git a/app/src/main/java/com/ssafy/tiggle/data/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/ssafy/tiggle/data/repository/AuthRepositoryImpl.kt index b482ee3..c28d6c8 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/repository/AuthRepositoryImpl.kt @@ -5,8 +5,8 @@ import com.google.gson.Gson import com.ssafy.tiggle.data.datasource.local.AuthDataSource import com.ssafy.tiggle.data.datasource.remote.AuthApiService import com.ssafy.tiggle.data.model.BaseResponse -import com.ssafy.tiggle.data.model.LoginRequestDto -import com.ssafy.tiggle.data.model.SignUpRequestDto +import com.ssafy.tiggle.data.model.auth.request.LoginRequestDto +import com.ssafy.tiggle.data.model.auth.request.SignUpRequestDto import com.ssafy.tiggle.domain.entity.auth.UserSignUp import com.ssafy.tiggle.domain.repository.AuthRepository import javax.inject.Inject diff --git a/app/src/main/java/com/ssafy/tiggle/data/repository/DutchPayRepositoryImpl.kt b/app/src/main/java/com/ssafy/tiggle/data/repository/DutchPayRepositoryImpl.kt index 66d94b8..074f678 100644 --- a/app/src/main/java/com/ssafy/tiggle/data/repository/DutchPayRepositoryImpl.kt +++ b/app/src/main/java/com/ssafy/tiggle/data/repository/DutchPayRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.ssafy.tiggle.data.repository import com.ssafy.tiggle.data.datasource.remote.DutchPayApiService import com.ssafy.tiggle.data.model.dutchpay.request.DutchPayRequestDto import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequest +import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequestDetail import com.ssafy.tiggle.domain.repository.DutchPayRepository import javax.inject.Inject import javax.inject.Singleton @@ -21,9 +22,9 @@ class DutchPayRepositoryImpl @Inject constructor( message = request.message, payMore = request.payMore ) - + val response = dutchPayApiService.createDutchPayRequest(requestDto) - + if (response.isSuccessful) { Result.success(Unit) } else { @@ -33,4 +34,37 @@ class DutchPayRepositoryImpl @Inject constructor( Result.failure(e) } } + + override suspend fun getDutchPayRequestDetail(dutchPayId: Long): Result { + return try { + val response = dutchPayApiService.getDutchPayRequestDetail(dutchPayId) + + if (response.isSuccessful) { + val responseData = response.body()?.data + if (responseData != null) { + val detail = DutchPayRequestDetail( + dutchPayId = responseData.dutchpayId, + title = responseData.title, + message = responseData.message, + requesterName = responseData.requesterName, + participantCount = responseData.participantCount, + totalAmount = responseData.totalAmount, + requestedAt = responseData.requestedAt, + myAmount = responseData.myAmount, + originalAmount = responseData.originalAmount, + tiggleAmount = responseData.tiggleAmount, + payMoreDefault = responseData.payMoreDefault, + isCreator = responseData.creator + ) + Result.success(detail) + } else { + Result.failure(Exception("응답 데이터가 없습니다")) + } + } else { + Result.failure(Exception("더치페이 상세 조회 실패: ${response.code()}")) + } + } catch (e: Exception) { + Result.failure(e) + } + } } diff --git a/app/src/main/java/com/ssafy/tiggle/domain/entity/dutchpay/DutchPayRequestDetail.kt b/app/src/main/java/com/ssafy/tiggle/domain/entity/dutchpay/DutchPayRequestDetail.kt new file mode 100644 index 0000000..38a0cd5 --- /dev/null +++ b/app/src/main/java/com/ssafy/tiggle/domain/entity/dutchpay/DutchPayRequestDetail.kt @@ -0,0 +1,16 @@ +package com.ssafy.tiggle.domain.entity.dutchpay + +data class DutchPayRequestDetail( + val dutchPayId: Long, + val title: String, + val message: String, + val requesterName: String, + val participantCount: Int, + val totalAmount: Long, + val requestedAt: String, + val myAmount: Long, + val originalAmount: Long, + val tiggleAmount: Long, + val payMoreDefault: Boolean, + val isCreator: Boolean +) diff --git a/app/src/main/java/com/ssafy/tiggle/domain/repository/DutchPayRepository.kt b/app/src/main/java/com/ssafy/tiggle/domain/repository/DutchPayRepository.kt index 8efe0a4..62a0987 100644 --- a/app/src/main/java/com/ssafy/tiggle/domain/repository/DutchPayRepository.kt +++ b/app/src/main/java/com/ssafy/tiggle/domain/repository/DutchPayRepository.kt @@ -1,7 +1,9 @@ package com.ssafy.tiggle.domain.repository +import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequestDetail import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequest interface DutchPayRepository { suspend fun createDutchPayRequest(request: DutchPayRequest): Result + suspend fun getDutchPayRequestDetail(dutchPayId: Long): Result } diff --git a/app/src/main/java/com/ssafy/tiggle/domain/usecase/dutchpay/GetDutchPayRequestDetailUseCase.kt b/app/src/main/java/com/ssafy/tiggle/domain/usecase/dutchpay/GetDutchPayRequestDetailUseCase.kt new file mode 100644 index 0000000..2ce8b47 --- /dev/null +++ b/app/src/main/java/com/ssafy/tiggle/domain/usecase/dutchpay/GetDutchPayRequestDetailUseCase.kt @@ -0,0 +1,13 @@ +package com.ssafy.tiggle.domain.usecase.dutchpay + +import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequestDetail +import com.ssafy.tiggle.domain.repository.DutchPayRepository +import javax.inject.Inject + +class GetDutchPayRequestDetailUseCase @Inject constructor( + private val dutchPayRepository: DutchPayRepository +) { + suspend operator fun invoke(dutchPayId: Long): Result { + return dutchPayRepository.getDutchPayRequestDetail(dutchPayId) + } +} diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/navigation/NavigationGraph.kt b/app/src/main/java/com/ssafy/tiggle/presentation/navigation/NavigationGraph.kt index e5d32fd..e5f8b34 100644 --- a/app/src/main/java/com/ssafy/tiggle/presentation/navigation/NavigationGraph.kt +++ b/app/src/main/java/com/ssafy/tiggle/presentation/navigation/NavigationGraph.kt @@ -1,9 +1,12 @@ package com.ssafy.tiggle.presentation.navigation +import android.content.Intent +import android.net.Uri import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator import androidx.navigation3.runtime.NavEntry @@ -16,6 +19,7 @@ import com.ssafy.tiggle.presentation.ui.auth.signup.SignUpScreen import com.ssafy.tiggle.presentation.ui.donation.DonationHistoryScreen import com.ssafy.tiggle.presentation.ui.donation.DonationStatusScreen import com.ssafy.tiggle.presentation.ui.dutchpay.CreateDutchPayScreen +import com.ssafy.tiggle.presentation.ui.dutchpay.DutchpayRecieveScreen import com.ssafy.tiggle.presentation.ui.growth.GrowthScreen import com.ssafy.tiggle.presentation.ui.piggybank.MainAccountDetailScreen import com.ssafy.tiggle.presentation.ui.piggybank.OpenAccountMode @@ -29,10 +33,44 @@ import com.ssafy.tiggle.presentation.ui.shorts.ShortsScreen * 앱의 메인 네비게이션 */ @Composable -fun NavigationGraph() { +fun NavigationGraph( + intent: Intent?, // Nullable Intent를 받음 + onDeepLinkHandled: () -> Unit // 딥링크 처리 완료 콜백 함수 +) { val startDestination = Screen.Login val navBackStack = rememberNavBackStack(startDestination) + LaunchedEffect(intent) { + val data: Uri? = intent?.data + android.util.Log.d( + "NavigationGraph", + "LaunchedEffect triggered - intent: $intent, data: $data" + ) + + if (data != null && data.scheme == "tiggle" && data.host == "dutchpay") { + android.util.Log.d("NavigationGraph", "Deep link detected: $data") + val dutchPayId = data.lastPathSegment + android.util.Log.d("NavigationGraph", "Extracted dutchPayId: $dutchPayId") + + if (dutchPayId != null) { + try { + navBackStack.clear() + navBackStack.add(BottomScreen.PiggyBank) + navBackStack.add(Screen.DutchpayRecieve(dutchPayId.toLong())) + android.util.Log.d( + "NavigationGraph", + "Navigation successful to DutchpayRecieve($dutchPayId)" + ) + } catch (e: Exception) { + android.util.Log.e("NavigationGraph", "Error navigating to DutchpayRecieve", e) + } + } + } + onDeepLinkHandled() + } + + + Scaffold( bottomBar = { if (navBackStack.last() is BottomScreen && navBackStack.last() != BottomScreen.Shorts) @@ -116,17 +154,15 @@ fun NavigationGraph() { is Screen.OpenAccount -> NavEntry(key) { OpenAccountScreen( - mode = key.mode, onBackClick = { navBackStack.removeLastOrNull() }, onFinish = { navBackStack.removeLastOrNull() - }, + } ) } is Screen.RegisterAccount -> NavEntry(key) { RegisterAccountScreen( - isEdit = key.isEdit, onBackClick = { navBackStack.removeLastOrNull() }, onFinish = { navBackStack.removeLastOrNull() @@ -141,6 +177,11 @@ fun NavigationGraph() { ) } + is Screen.DutchpayRecieve -> NavEntry(key) { + // key에서 dutchPayId를 직접 꺼내서 화면에 전달합니다. + DutchpayRecieveScreen(dutchPayId = key.dutchPayId) + } + is Screen.MainAccountDetail -> NavEntry(key) { MainAccountDetailScreen( accountNo = key.accountNo, diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/navigation/Screen.kt b/app/src/main/java/com/ssafy/tiggle/presentation/navigation/Screen.kt index 3b88a94..caadc2e 100644 --- a/app/src/main/java/com/ssafy/tiggle/presentation/navigation/Screen.kt +++ b/app/src/main/java/com/ssafy/tiggle/presentation/navigation/Screen.kt @@ -48,5 +48,8 @@ sealed interface Screen : NavKey { @Serializable object DonationStatus : Screen + + @Serializable + data class DutchpayRecieve(val dutchPayId: Long) : Screen } diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/auth/login/LoginScreen.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/auth/login/LoginScreen.kt index 302a9c1..5971f0e 100644 --- a/app/src/main/java/com/ssafy/tiggle/presentation/ui/auth/login/LoginScreen.kt +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/auth/login/LoginScreen.kt @@ -1,6 +1,5 @@ package com.ssafy.tiggle.presentation.ui.auth.login -import android.annotation.SuppressLint import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -17,6 +16,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.withStyle @@ -64,9 +64,9 @@ fun LoginScreen( label = "이메일", placeholder = "이메일을 입력해주세요", keyboardType = KeyboardType.Email, + modifier = Modifier.fillMaxWidth(), isError = uiState.emailError != null, - errorMessage = uiState.emailError, - modifier = Modifier.fillMaxWidth() + errorMessage = uiState.emailError ) Spacer(modifier = Modifier.height(16.dp)) @@ -77,9 +77,10 @@ fun LoginScreen( label = "비밀번호", placeholder = "비밀번호를 입력해주세요", isPassword = true, + modifier = Modifier.fillMaxWidth(), isError = uiState.passwordError != null, errorMessage = uiState.passwordError, - modifier = Modifier.fillMaxWidth() + imeAction = ImeAction.Done ) // 비밀번호 찾기 diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/TiggleTextField.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/TiggleTextField.kt index 92132f9..77f1550 100644 --- a/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/TiggleTextField.kt +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/TiggleTextField.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff -import androidx.compose.ui.text.input.ImeAction import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -21,16 +20,16 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.platform.LocalFocusManager import com.ssafy.tiggle.presentation.ui.theme.TiggleBlue import com.ssafy.tiggle.presentation.ui.theme.TiggleGrayLight import com.ssafy.tiggle.presentation.ui.theme.TiggleGrayText @@ -46,10 +45,11 @@ fun TiggleTextField( placeholder: String = "", isPassword: Boolean = false, keyboardType: KeyboardType = KeyboardType.Text, + maxLines: Int = 1, modifier: Modifier = Modifier, isError: Boolean = false, errorMessage: String? = null, - maxLines: Int = 1, + imeAction: ImeAction = if (maxLines == 1) ImeAction.Next else ImeAction.Done, minLines: Int = 1 ) { var isPasswordVisible by remember { mutableStateOf(false) } @@ -106,7 +106,7 @@ fun TiggleTextField( } else null, keyboardOptions = KeyboardOptions( keyboardType = keyboardType, - imeAction = if (maxLines == 1) ImeAction.Next else ImeAction.Done + imeAction = imeAction ), singleLine = maxLines == 1, maxLines = maxLines, @@ -136,7 +136,7 @@ fun TiggleTextField( @Composable private fun TiggleTextFieldPreview() { var text by remember { mutableStateOf("") } - + TiggleTextField( value = text, onValueChange = { text = it }, @@ -150,7 +150,7 @@ private fun TiggleTextFieldPreview() { @Composable private fun TiggleTextFieldPasswordPreview() { var password by remember { mutableStateOf("") } - + TiggleTextField( value = password, onValueChange = { password = it }, @@ -164,7 +164,7 @@ private fun TiggleTextFieldPasswordPreview() { @Composable private fun TiggleTextFieldErrorPreview() { var text by remember { mutableStateOf("invalid@") } - + TiggleTextField( value = text, onValueChange = { text = it }, diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/UserPicker.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/UserPicker.kt index 184eff3..e689e39 100644 --- a/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/UserPicker.kt +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/components/UserPicker.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn @@ -101,7 +102,9 @@ fun UserPicker( colors = CardDefaults.cardColors(containerColor = Color.White), elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) ) { - LazyColumn { + LazyColumn( + modifier = Modifier.heightIn(max = 400.dp) + ) { items(filteredUsers, key = { it.id }) { user -> UserRow( user = user, diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/donation/DonationHistoryScreen.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/donation/DonationHistoryScreen.kt index 1a2fb54..b389d94 100644 --- a/app/src/main/java/com/ssafy/tiggle/presentation/ui/donation/DonationHistoryScreen.kt +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/donation/DonationHistoryScreen.kt @@ -188,7 +188,7 @@ private fun DonationHistoryItem( ) Spacer(modifier = Modifier.height(4.dp)) Text( - text = donation.donatedAt, + text = Formatter.formatDateTime(donation.donatedAt), fontSize = 12.sp, color = TiggleGrayText, style = AppTypography.bodySmall diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchPayRequestDetailUiState.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchPayRequestDetailUiState.kt new file mode 100644 index 0000000..4f40fc1 --- /dev/null +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchPayRequestDetailUiState.kt @@ -0,0 +1,9 @@ +package com.ssafy.tiggle.presentation.ui.dutchpay + +import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequestDetail + +data class DutchPayRequestDetailUiState( + val isLoading: Boolean = false, + val dutchPayDetail: DutchPayRequestDetail? = null, + val errorMessage: String? = null +) diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchPayRequestDetailViewModel.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchPayRequestDetailViewModel.kt new file mode 100644 index 0000000..caa97de --- /dev/null +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchPayRequestDetailViewModel.kt @@ -0,0 +1,50 @@ +package com.ssafy.tiggle.presentation.ui.dutchpay + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ssafy.tiggle.domain.usecase.dutchpay.GetDutchPayRequestDetailUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DutchPayRequestDetailViewModel @Inject constructor( + private val getDutchPayRequestDetailUseCase: GetDutchPayRequestDetailUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(DutchPayRequestDetailUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + fun loadDutchPayDetail(dutchPayId: Long) { + _uiState.update { it.copy(isLoading = true, errorMessage = null) } + + viewModelScope.launch { + getDutchPayRequestDetailUseCase(dutchPayId) + .onSuccess { detail -> + _uiState.update { + it.copy( + isLoading = false, + dutchPayDetail = detail, + errorMessage = null + ) + } + } + .onFailure { exception -> + _uiState.update { + it.copy( + isLoading = false, + errorMessage = exception.message ?: "더치페이 정보를 불러오는데 실패했습니다." + ) + } + } + } + } + + fun clearErrorMessage() { + _uiState.update { it.copy(errorMessage = null) } + } +} diff --git a/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchpayRecieveScreen.kt b/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchpayRecieveScreen.kt new file mode 100644 index 0000000..034a903 --- /dev/null +++ b/app/src/main/java/com/ssafy/tiggle/presentation/ui/dutchpay/DutchpayRecieveScreen.kt @@ -0,0 +1,362 @@ +package com.ssafy.tiggle.presentation.ui.dutchpay + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import com.ssafy.tiggle.core.utils.Formatter +import com.ssafy.tiggle.domain.entity.dutchpay.DutchPayRequestDetail +import com.ssafy.tiggle.presentation.ui.components.TiggleButton +import com.ssafy.tiggle.presentation.ui.components.TiggleButtonVariant +import com.ssafy.tiggle.presentation.ui.components.TiggleScreenLayout +import com.ssafy.tiggle.presentation.ui.components.TiggleSwitchRow +import com.ssafy.tiggle.presentation.ui.theme.AppTypography +import com.ssafy.tiggle.presentation.ui.theme.TiggleBlue + +@Composable +fun DutchpayRecieveScreen( + dutchPayId: Long, + onBackClick: () -> Unit = {}, + onPaymentClick: () -> Unit = {}, + viewModel: DutchPayRequestDetailViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsState() + + LaunchedEffect(dutchPayId) { + viewModel.loadDutchPayDetail(dutchPayId) + } + + TiggleScreenLayout( + onBackClick = onBackClick, + bottomButton = { + uiState.dutchPayDetail?.let { detail -> + if (!detail.isCreator) { + TiggleButton( + text = "송금하기", + onClick = onPaymentClick, + enabled = !uiState.isLoading, + isLoading = false, + variant = TiggleButtonVariant.Primary + ) + } + } + } + ) { + when { + uiState.isLoading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = TiggleBlue) + } + } + + else -> { + uiState.dutchPayDetail?.let { detail -> + DutchPayPaymentContent( + detail = detail + ) + } + } + } + } + + // 에러 다이얼로그 표시 + uiState.errorMessage?.let { errorMessage -> + AlertDialog( + onDismissRequest = { viewModel.clearErrorMessage() }, + title = { + Text("오류") + }, + text = { + Text(errorMessage) + }, + confirmButton = { + TextButton( + onClick = { viewModel.clearErrorMessage() } + ) { + Text("송금하기") + } + } + ) + } +} + +@Composable +private fun DutchPayPaymentContent( + detail: DutchPayRequestDetail +) { + var payMoreEnabled by remember { mutableStateOf(detail.payMoreDefault) } + + // 내가 낼 금액 계산 + val myPaymentAmount = if (payMoreEnabled) { + detail.originalAmount + detail.tiggleAmount + } else { + detail.originalAmount + } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(16.dp)) + + // 요청자 정보 + Text( + text = "${detail.requesterName}님이", + style = AppTypography.headlineSmall, + textAlign = TextAlign.Center + ) + Text( + text = "더치페이를 요청했습니다", + style = AppTypography.headlineSmall, + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(20.dp)) + + // 전달된 메시지 (있을 경우) + if (detail.message.isNotBlank()) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = Color.Gray.copy(alpha = 0.1f)), + elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), + shape = RoundedCornerShape(8.dp) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text( + text = "📤 전달된 메시지", + style = AppTypography.bodySmall, + color = Color.Gray + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = detail.message, + style = AppTypography.bodyMedium + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + } + + // 요청 정보 + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 1.dp), + shape = RoundedCornerShape(12.dp) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text( + text = "요청 정보", + style = AppTypography.bodyLarge.copy(fontWeight = FontWeight.Bold) + ) + + Spacer(modifier = Modifier.height(12.dp)) + + DetailRow(label = "요청자", value = detail.requesterName) + Spacer(modifier = Modifier.height(8.dp)) + DetailRow(label = "참여 인원", value = "${detail.participantCount}명") + Spacer(modifier = Modifier.height(8.dp)) + DetailRow(label = "총 금액", value = Formatter.formatCurrency(detail.totalAmount)) + Spacer(modifier = Modifier.height(8.dp)) + DetailRow(label = "요청 일시", value = Formatter.formatDateTime(detail.requestedAt)) + } + } + + Spacer(modifier = Modifier.height(20.dp)) + + // 내가 내는 금액 + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = TiggleBlue.copy(alpha = 0.1f)), + elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), + shape = RoundedCornerShape(12.dp) + ) { + Column( + modifier = Modifier.padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "내가 내는 금액", + style = AppTypography.bodyMedium, + color = Color.Gray + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = Formatter.formatCurrency(myPaymentAmount), + style = AppTypography.headlineLarge.copy( + fontSize = 32.sp, + fontWeight = FontWeight.Bold, + color = TiggleBlue + ) + ) + + Spacer(modifier = Modifier.height(16.dp)) + + HorizontalDivider(color = Color.Gray.copy(alpha = 0.2f)) + + Spacer(modifier = Modifier.height(12.dp)) + + DetailRow(label = "원래 금액", value = Formatter.formatCurrency(detail.originalAmount)) + + if (payMoreEnabled && detail.tiggleAmount > 0) { + Spacer(modifier = Modifier.height(8.dp)) + DetailRow( + label = "티끌", + value = "+${Formatter.formatCurrency(detail.tiggleAmount)}", + valueColor = TiggleBlue + ) + } + } + } + + Spacer(modifier = Modifier.height(20.dp)) + + // 돈 더내고 잔돈 기부하기 스위치 + TiggleSwitchRow( + title = "돈 더내고 잔돈 기부하기", + subtitle = "자투리 금액을 티끌 저금통에 적립", + checked = payMoreEnabled, + onCheckedChange = { payMoreEnabled = it } + ) + + Spacer(modifier = Modifier.height(40.dp)) + } +} + +@Composable +private fun DetailRow( + label: String, + value: String, + valueColor: Color = Color.Black +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Top + ) { + Text( + text = label, + style = AppTypography.bodyMedium, + color = Color.Gray, + modifier = Modifier.weight(1f) + ) + Text( + text = value, + style = AppTypography.bodyMedium.copy( + fontWeight = FontWeight.Medium + ), + color = valueColor, + textAlign = TextAlign.End, + modifier = Modifier.weight(1f) + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun PreviewDutchPayPayment() { + val sampleDetail = DutchPayRequestDetail( + dutchPayId = 9L, + title = "어제 먹은 치킨 정산", + message = "오늘 치킨 먹은 금액입니다!", + requesterName = "최지원", + participantCount = 3, + totalAmount = 50000L, + requestedAt = "2025.08.20 14:32", + myAmount = 17000L, + originalAmount = 16666L, + tiggleAmount = 334L, + payMoreDefault = true, + isCreator = false + ) + + TiggleScreenLayout( + onBackClick = {}, + bottomButton = { + TiggleButton( + text = "송금하기", + onClick = {}, + enabled = true, + isLoading = false, + variant = TiggleButtonVariant.Primary + ) + } + ) { + DutchPayPaymentContent(detail = sampleDetail) + } +} + + +@Preview(showBackground = true) +@Composable +private fun PreviewNoTiggleDutchPayPayment() { + val sampleDetail = DutchPayRequestDetail( + dutchPayId = 9L, + title = "어제 먹은 치킨 정산", + message = "오늘 치킨 먹은 금액입니다!", + requesterName = "최지원", + participantCount = 3, + totalAmount = 50000L, + requestedAt = "2025.08.20 14:32", + myAmount = 17000L, + originalAmount = 16666L, + tiggleAmount = 334L, + payMoreDefault = false, + isCreator = false + ) + + TiggleScreenLayout( + onBackClick = {}, + bottomButton = { + TiggleButton( + text = "송금하기", + onClick = {}, + enabled = true, + isLoading = false, + variant = TiggleButtonVariant.Primary + ) + } + ) { + DutchPayPaymentContent(detail = sampleDetail) + } +}