From 00f3f2c5e89ef2f316bce39cd87c55f84b42dd1b Mon Sep 17 00:00:00 2001 From: kimmatches Date: Wed, 6 Nov 2024 11:06:58 +0900 Subject: [PATCH 01/16] =?UTF-8?q?fix=20:=20=EB=B0=94=ED=85=80=EB=B0=94=20?= =?UTF-8?q?=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20=EB=B0=8F=20=EB=8B=A4=ED=81=AC?= =?UTF-8?q?=EB=AA=A8=EB=93=9C=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20?= =?UTF-8?q?(#65)=20(#KAN-141)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mhnfe/ui/bottombar/BottomBarScreen.kt | 2 +- .../mhnfe/ui/navigation/AppNavigation.kt | 22 +++---------------- .../ui/screens/monitoring/GroupScreen.kt | 7 +++++- .../mhnfe/ui/screens/qr/QRGenerateScreen.kt | 7 +++--- .../java/com/example/mhnfe/ui/theme/Theme.kt | 7 ++---- 5 files changed, 16 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/bottombar/BottomBarScreen.kt b/app/src/main/java/com/example/mhnfe/ui/bottombar/BottomBarScreen.kt index adf36b8b..4b25c7fe 100644 --- a/app/src/main/java/com/example/mhnfe/ui/bottombar/BottomBarScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/bottombar/BottomBarScreen.kt @@ -66,7 +66,7 @@ fun BottomNavigationBar( items.forEach { item -> val isSelected = when (item) { is NavigationItem.Monitoring -> { - currentRoute == "group" // 실제 라우트 값과 매칭 + currentRoute == "monitoring/group" } is NavigationItem.Report -> { diff --git a/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt b/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt index 1fa81716..8a19beaf 100644 --- a/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt @@ -41,12 +41,12 @@ sealed class NavRoutes(val route: String) { object Group : NavRoutes("monitoring/group") object DeviceInformation : NavRoutes("device_information") object QRScanner : NavRoutes("qr_scanner") - object QRGenerate : NavRoutes("qr_generate/{userType}") { // monitoring/ 접두어 제거 + object QRGenerate : NavRoutes("qr_generate/{userType}") { fun createRoute(userType: UserType) = "qr_generate/${userType.name.lowercase()}" } } object Report : NavRoutes("report") { - object ReportDetail : NavRoutes("report_detail") + object ReportDetail : NavRoutes("report/report_detail") //추후에 화면이 추가 될 수 있기 때문에 이렇게 따로 빼서 구현 추후 화면 추가가 없을 시 삭제 } object MyPage : NavRoutes("myPage") { @@ -60,7 +60,6 @@ sealed class NavRoutes(val route: String) { fun AppNavigation() { val auth = remember { AWSMobileClient.getInstance() } val navController = rememberNavController() - val viewModel: QRViewModel = viewModel() NavHost( navController = navController, @@ -144,21 +143,6 @@ fun MainContent( startDestination = NavRoutes.Monitoring.route, modifier = Modifier.padding(innerPadding) ) { - // QR Generate 화면을 별도의 navigation block 밖으로 이동 - composable( - route = NavRoutes.Monitoring.QRGenerate.route, - arguments = listOf( - navArgument("userType") { - type = NavType.StringType - } - ) - ) { backStackEntry -> - val qrUserType = backStackEntry.arguments?.getString("userType") - QRGenerateScreen( - navController = bottomNavController, // bottomNavController 사용 - userType = UserType.fromString(qrUserType) - ) - } // Monitoring Graph navigation( @@ -187,7 +171,7 @@ fun MainContent( ) { backStackEntry -> val qrUserType = backStackEntry.arguments?.getString("userType") QRGenerateScreen( - navController = bottomNavController, + navController = bottomNavController, // bottomNavController 사용 userType = UserType.fromString(qrUserType) ) } diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt index 5a1dffb5..b3e55904 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt @@ -33,6 +33,7 @@ import com.example.mhnfe.ui.components.MainTopBar import com.example.mhnfe.ui.components.SmallButton import com.example.mhnfe.ui.navigation.NavRoutes import com.example.mhnfe.ui.theme.Typography +import com.example.mhnfe.ui.theme.mainBlack import com.example.mhnfe.ui.theme.mainGray3 @Composable @@ -83,7 +84,11 @@ fun GroupScreen( } } if (cctv.isEmpty()) { - Text(style = Typography.bodyMedium, text = "등록된 CCTV가 없습니다.") + Text( + style = Typography.bodyMedium, + text = "등록된 CCTV가 없습니다.", + color = mainBlack + ) } else { LazyColumn( modifier = Modifier.fillMaxSize(), diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRGenerateScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRGenerateScreen.kt index 6769f0e6..95cf71c6 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRGenerateScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRGenerateScreen.kt @@ -29,7 +29,7 @@ import androidx.navigation.compose.rememberNavController import com.example.mhnfe.di.UserType import com.example.mhnfe.ui.components.SubTopBar import com.example.mhnfe.ui.theme.Typography - +import com.example.mhnfe.ui.theme.mainBlack @Composable @@ -75,14 +75,15 @@ fun QRGenerateScreen( Text( textAlign = TextAlign.Center, style = Typography.bodyMedium, + color = mainBlack, text = uiState.message ) Image( bitmap = qrBitmap.asImageBitmap(), contentDescription = "QR Code", - modifier = Modifier + modifier = modifier .size(200.dp) - .border(1.dp, Color.Gray) + .border(1.dp, mainBlack) ) } } diff --git a/app/src/main/java/com/example/mhnfe/ui/theme/Theme.kt b/app/src/main/java/com/example/mhnfe/ui/theme/Theme.kt index c5dea938..e8a1600d 100644 --- a/app/src/main/java/com/example/mhnfe/ui/theme/Theme.kt +++ b/app/src/main/java/com/example/mhnfe/ui/theme/Theme.kt @@ -30,11 +30,8 @@ fun MhnFETheme( dynamicColor: Boolean = true, content: @Composable () -> Unit ) { - val colors = if (!darkTheme) { - LightColorScheme - } else { - DarkColorScheme - } + val colors = LightColorScheme // 항상 라이트 모드 색상 사용 + MaterialTheme( colorScheme = colors, content = content, From 21b7d547d4205f0312aa1f7a047c5b44b0990baf Mon Sep 17 00:00:00 2001 From: parkchanil <0114chan@gmail.com> Date: Wed, 6 Nov 2024 11:08:31 +0900 Subject: [PATCH 02/16] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#59)=20(KAN-135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 1 - .../mhnfe/ui/screens/auth/LoginScreen.kt | 137 ++++++++++++------ app/src/main/res/drawable/logo2.png | Bin 0 -> 18602 bytes 3 files changed, 90 insertions(+), 48 deletions(-) create mode 100644 app/src/main/res/drawable/logo2.png diff --git a/.idea/misc.xml b/.idea/misc.xml index e485240f..2188b52b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index 4b7ce89c..e62873b0 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -1,25 +1,32 @@ package com.example.mhnfe.ui.screens.auth +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.material3.Checkbox import androidx.compose.material3.CheckboxDefaults +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.material3.Scaffold - +import com.example.mhnfe.R import com.example.mhnfe.ui.components.MainTextBox import com.example.mhnfe.ui.components.SubTopBar import com.example.mhnfe.ui.components.middleButton +import com.example.mhnfe.ui.theme.mainBlack import com.example.mhnfe.ui.theme.mainGray import com.example.mhnfe.ui.theme.mainYellow +import com.example.mhnfe.ui.theme.mainGray3 @Composable fun LoginScreen( + modifier: Modifier = Modifier, onBackClick: () -> Unit, onLoginClick: () -> Unit ) { @@ -27,9 +34,7 @@ fun LoginScreen( var isAutoLogin by remember { mutableStateOf(false) } Scaffold( - modifier = Modifier - .statusBarsPadding() - .navigationBarsPadding(), + modifier = modifier, topBar = { SubTopBar( text = "로그인", @@ -38,63 +43,101 @@ fun LoginScreen( } ) { paddingValues -> Column( - modifier = Modifier - .fillMaxSize() + modifier = modifier .padding(paddingValues) - .padding(horizontal = 20.dp) - .padding(top = 20.dp), - verticalArrangement = Arrangement.spacedBy(16.dp), - horizontalAlignment = Alignment.CenterHorizontally // 중앙 정렬 추가 + .fillMaxSize() + .padding(horizontal = 34.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.SpaceBetween // 최상위 Column에 SpaceBetween 적용 ) { - // 입력 필드들 + // 상단부 (로고) Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(16.dp) + horizontalAlignment = Alignment.CenterHorizontally ) { - MainTextBox( - focusManager = focusManager, - hintText = "아이디" - ) + Spacer(modifier = Modifier.height(40.dp)) - MainTextBox( - focusManager = focusManager, - hintText = "비밀번호" + // 로고 이미지 + Image( + painter = painterResource(id = R.drawable.logo2), + contentDescription = "로고", + modifier = Modifier.size(250.dp), + contentScale = ContentScale.Fit ) - // 자동 로그인 체크박스 - Row( - modifier = Modifier.padding(vertical = 4.dp), - verticalAlignment = Alignment.CenterVertically + Spacer(modifier = Modifier.height(60.dp)) + + // 입력 필드들과 자동로그인을 포함하는 Column + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp), + horizontalAlignment = Alignment.Start ) { - Checkbox( - checked = isAutoLogin, - onCheckedChange = { isAutoLogin = it }, - colors = CheckboxDefaults.colors(checkedColor = mainYellow) + MainTextBox( + focusManager = focusManager, + hintText = "아이디" + ) + + MainTextBox( + focusManager = focusManager, + hintText = "비밀번호" ) - Text("자동로그인") + + // 자동 로그인 체크박스 + Row( // Column을 Row로 변경 + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.offset((-12).dp) + ) { + Checkbox( + checked = isAutoLogin, + onCheckedChange = { isAutoLogin = it }, + colors = CheckboxDefaults.colors(checkedColor = mainYellow) + ) + Text( + text = "자동로그인", + color = mainGray + ) + } } } - Spacer(modifier = Modifier.weight(1f)) - - // 로그인 버튼 - middleButton( - text = "로그인", - onClick = onLoginClick, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - // 비밀번호 찾기 텍스트 - Text( - text = "비밀번호를 잊어버리셨나요?", + // 하단부 버튼과 텍스트를 포함하는 Column + Column( modifier = Modifier - .padding(vertical = 16.dp), // fillMaxWidth 제거 - textAlign = TextAlign.Center, - color = mainGray - ) + .fillMaxWidth() + .padding(bottom = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // 로그인 버튼 + middleButton( + text = "로그인", + onClick = onLoginClick, + modifier = Modifier.fillMaxWidth() + ) + + // 비밀번호 찾기 텍스트 + Text( + text = "비밀번호를 잊어버리셨나요?", + textAlign = TextAlign.Center, + color = mainGray, - // 하단 여백 - Spacer(modifier = Modifier.height(20.dp)) + ) + } } } +} + +@Preview( + name = "Login Screen", + showBackground = true, + showSystemUi = true, + device = "spec:width=411dp,height=891dp" +) +@Composable +fun LoginScreenPreview() { + LoginScreen( + onBackClick = {}, + onLoginClick = {} + ) } \ No newline at end of file diff --git a/app/src/main/res/drawable/logo2.png b/app/src/main/res/drawable/logo2.png new file mode 100644 index 0000000000000000000000000000000000000000..46a485e9b19276511c0512c77ce1ad9e1d1defc2 GIT binary patch literal 18602 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 f`2AsJwgsEweUfwFr$5_C3+=MOUcfv;`= Date: Wed, 6 Nov 2024 11:09:29 +0900 Subject: [PATCH 03/16] =?UTF-8?q?fix:=20=EA=B3=B5=ED=86=B5=20component=20b?= =?UTF-8?q?utton=20ui=20=EC=88=98=EC=A0=95=20(#60)=20(KAN-136)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/kotlinc.xml | 2 +- .../java/com/example/mhnfe/StartScreen.kt | 6 ++-- .../com/example/mhnfe/ui/components/button.kt | 29 ++++++++++++++----- .../mhnfe/ui/screens/auth/LoginScreen.kt | 4 +-- .../mhnfe/ui/screens/auth/SignUpScreen.kt | 4 +-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index c224ad56..fdf8d994 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/app/src/main/java/com/example/mhnfe/StartScreen.kt b/app/src/main/java/com/example/mhnfe/StartScreen.kt index 6a18d79f..1e42764c 100644 --- a/app/src/main/java/com/example/mhnfe/StartScreen.kt +++ b/app/src/main/java/com/example/mhnfe/StartScreen.kt @@ -7,7 +7,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.example.mhnfe.ui.components.middleButton +import com.example.mhnfe.ui.components.MiddleButton @Composable fun StartScreen( @@ -46,14 +46,14 @@ fun StartScreen( horizontalAlignment = Alignment.CenterHorizontally ) { // 로그인 버튼 - middleButton( + MiddleButton( text = "로그인", onClick = onLoginClick, modifier = Modifier.fillMaxWidth() ) // Cam 회원 버튼 - middleButton( + MiddleButton( text = "회원가입", onClick = onSignUpClick, modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/example/mhnfe/ui/components/button.kt b/app/src/main/java/com/example/mhnfe/ui/components/button.kt index ea8d6964..33359d6b 100644 --- a/app/src/main/java/com/example/mhnfe/ui/components/button.kt +++ b/app/src/main/java/com/example/mhnfe/ui/components/button.kt @@ -4,7 +4,12 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog @@ -30,9 +35,9 @@ fun SmallButton( ) { Button( modifier = modifier - .wrapContentSize(), + .defaultMinSize(130.dp, 56.dp), shape = RoundedCornerShape(16.dp), - contentPadding = PaddingValues(vertical = 18.dp, horizontal = 40.dp), + contentPadding = PaddingValues(vertical = 18.dp), colors = ButtonDefaults.buttonColors( containerColor = Color.White ), @@ -47,16 +52,17 @@ fun SmallButton( } @Composable -fun middleButton( +fun MiddleButton( modifier: Modifier = Modifier, text: String, onClick: () -> Unit ) { Button( modifier = modifier - .wrapContentSize(), + .wrapContentHeight() + .fillMaxWidth(), shape = RoundedCornerShape(16.dp), - contentPadding = PaddingValues(vertical = 15.dp, horizontal = 140.dp), + contentPadding = PaddingValues(vertical = 15.dp), colors = ButtonDefaults.buttonColors( containerColor = mainYellow ), @@ -74,14 +80,21 @@ fun middleButton( fun NewQuizPreview(){ Column ( modifier = Modifier - .fillMaxSize(), + .fillMaxSize() + .padding(horizontal = 34.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(20.dp, alignment = Alignment.CenterVertically) ){ + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { SmallButton(text = "CCTV 추가") { } - middleButton(text = "회원가입") { } + SmallButton(text = "참여자 추가") { } + } + MiddleButton(text = "회원가입") { } } - } diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index 4b7ce89c..b49c1f07 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -14,7 +14,7 @@ import androidx.compose.material3.Scaffold import com.example.mhnfe.ui.components.MainTextBox import com.example.mhnfe.ui.components.SubTopBar -import com.example.mhnfe.ui.components.middleButton +import com.example.mhnfe.ui.components.MiddleButton import com.example.mhnfe.ui.theme.mainGray import com.example.mhnfe.ui.theme.mainYellow @@ -78,7 +78,7 @@ fun LoginScreen( Spacer(modifier = Modifier.weight(1f)) // 로그인 버튼 - middleButton( + MiddleButton( text = "로그인", onClick = onLoginClick, modifier = Modifier.align(Alignment.CenterHorizontally) diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/SignUpScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/SignUpScreen.kt index e0ec81a2..888e0297 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/SignUpScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/SignUpScreen.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.example.mhnfe.ui.components.MainTextBox import com.example.mhnfe.ui.components.SubTopBar -import com.example.mhnfe.ui.components.middleButton +import com.example.mhnfe.ui.components.MiddleButton import com.example.mhnfe.ui.theme.mainGray import androidx.compose.ui.Alignment // Import 추가 import androidx.compose.foundation.Image @@ -130,7 +130,7 @@ fun SignUpScreen( Spacer(modifier = Modifier.weight(1f)) // 하단 버튼과 텍스트 - middleButton( + MiddleButton( text = if (currentStep == 3) "완료" else "다음", onClick = { if (currentStep < 3) { From 32efed1c8d7112ce2ac4b1660c6093ce8b93197e Mon Sep 17 00:00:00 2001 From: mjkwahk Date: Wed, 6 Nov 2024 11:22:42 +0900 Subject: [PATCH 04/16] =?UTF-8?q?fix:=20kotlinc=20version=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#60)=20(KAN-136)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/kotlinc.xml | 2 +- app/src/main/java/com/example/mhnfe/ui/components/button.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d994..c224ad56 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/app/src/main/java/com/example/mhnfe/ui/components/button.kt b/app/src/main/java/com/example/mhnfe/ui/components/button.kt index 33359d6b..442d1dd0 100644 --- a/app/src/main/java/com/example/mhnfe/ui/components/button.kt +++ b/app/src/main/java/com/example/mhnfe/ui/components/button.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button From a8d697ada26fa7bd3eaeaf51aef46dd53ec2f40b Mon Sep 17 00:00:00 2001 From: parkchanil <0114chan@gmail.com> Date: Wed, 6 Nov 2024 11:56:19 +0900 Subject: [PATCH 05/16] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#59)=20(KAN-135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mhnfe/ui/screens/auth/LoginScreen.kt | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index e62873b0..2253589a 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -1,6 +1,7 @@ package com.example.mhnfe.ui.screens.auth import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.material3.Checkbox import androidx.compose.material3.CheckboxDefaults @@ -15,6 +16,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController import com.example.mhnfe.R import com.example.mhnfe.ui.components.MainTextBox import com.example.mhnfe.ui.components.SubTopBar @@ -27,7 +30,7 @@ import com.example.mhnfe.ui.theme.mainGray3 @Composable fun LoginScreen( modifier: Modifier = Modifier, - onBackClick: () -> Unit, + navController: NavController, onLoginClick: () -> Unit ) { val focusManager = LocalFocusManager.current @@ -38,7 +41,7 @@ fun LoginScreen( topBar = { SubTopBar( text = "로그인", - onBack = onBackClick + onBack = { navController.popBackStack() } ) } ) { paddingValues -> @@ -48,14 +51,14 @@ fun LoginScreen( .fillMaxSize() .padding(horizontal = 34.dp), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.SpaceBetween // 최상위 Column에 SpaceBetween 적용 + verticalArrangement = Arrangement.spacedBy(110.dp, alignment = Alignment.Top) ) { // 상단부 (로고) Column( - horizontalAlignment = Alignment.CenterHorizontally + modifier = modifier.padding(vertical = 50.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(40.dp, alignment = Alignment.CenterVertically) ) { - Spacer(modifier = Modifier.height(40.dp)) - // 로고 이미지 Image( painter = painterResource(id = R.drawable.logo2), @@ -64,12 +67,12 @@ fun LoginScreen( contentScale = ContentScale.Fit ) - Spacer(modifier = Modifier.height(60.dp)) - // 입력 필드들과 자동로그인을 포함하는 Column Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + verticalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.CenterVertically), horizontalAlignment = Alignment.Start ) { MainTextBox( @@ -83,7 +86,7 @@ fun LoginScreen( ) // 자동 로그인 체크박스 - Row( // Column을 Row로 변경 + Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.offset((-12).dp) ) { @@ -100,20 +103,16 @@ fun LoginScreen( } } - // 하단부 버튼과 텍스트를 포함하는 Column Column( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 20.dp), + modifier = modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { // 로그인 버튼 middleButton( text = "로그인", - onClick = onLoginClick, - modifier = Modifier.fillMaxWidth() + onClick = onLoginClick ) // 비밀번호 찾기 텍스트 @@ -121,6 +120,8 @@ fun LoginScreen( text = "비밀번호를 잊어버리셨나요?", textAlign = TextAlign.Center, color = mainGray, + modifier = Modifier + .clickable { navController.navigate("forgot_password") } ) } @@ -137,7 +138,8 @@ fun LoginScreen( @Composable fun LoginScreenPreview() { LoginScreen( - onBackClick = {}, + navController = rememberNavController(), onLoginClick = {} ) -} \ No newline at end of file +} + From 9aa64f0b2c1634c531e84e8ee08d94f4634cb06d Mon Sep 17 00:00:00 2001 From: parkchanil <0114chan@gmail.com> Date: Wed, 6 Nov 2024 12:46:32 +0900 Subject: [PATCH 06/16] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=8F=20=EC=82=AC=EC=A7=84=20=EC=88=98=EC=A0=95=20(#59)=20(?= =?UTF-8?q?KAN-135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index 2253589a..c2012776 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -103,6 +103,7 @@ fun LoginScreen( } } + // 하단부 버튼과 텍스트를 포함하는 Column Column( modifier = modifier.fillMaxWidth(), From 932d8dae02da3243f8d7cd930fb3d2e9f32630d0 Mon Sep 17 00:00:00 2001 From: parkchanil <0114chan@gmail.com> Date: Wed, 6 Nov 2024 12:54:17 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=8F=20=EC=82=AC=EC=A7=84=20=EC=88=98=EC=A0=95=20=EC=99=84?= =?UTF-8?q?=20(#59)=20(KAN-135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/mhnfe/ui/screens/auth/LoginScreen.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index c2012776..18b61a28 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -63,13 +63,13 @@ fun LoginScreen( Image( painter = painterResource(id = R.drawable.logo2), contentDescription = "로고", - modifier = Modifier.size(250.dp), + modifier = modifier.size(250.dp), contentScale = ContentScale.Fit ) // 입력 필드들과 자동로그인을 포함하는 Column Column( - modifier = Modifier + modifier = modifier .fillMaxWidth() .wrapContentHeight(), verticalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.CenterVertically), @@ -87,8 +87,8 @@ fun LoginScreen( // 자동 로그인 체크박스 Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.offset((-12).dp) + modifier = modifier.offset((-12).dp), + verticalAlignment = Alignment.CenterVertically ) { Checkbox( checked = isAutoLogin, @@ -106,7 +106,7 @@ fun LoginScreen( // 하단부 버튼과 텍스트를 포함하는 Column Column( - modifier = modifier.fillMaxWidth(), + modifier = modifier.fillMaxWidth().wrapContentHeight(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { @@ -121,7 +121,7 @@ fun LoginScreen( text = "비밀번호를 잊어버리셨나요?", textAlign = TextAlign.Center, color = mainGray, - modifier = Modifier + modifier = modifier .clickable { navController.navigate("forgot_password") } ) From 71b1b36a57fbeef34bef7a94ac1192cd318601c6 Mon Sep 17 00:00:00 2001 From: parkchanil <0114chan@gmail.com> Date: Wed, 6 Nov 2024 12:57:08 +0900 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20middle=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EB=8C=80=EB=AC=B8=EC=9E=90=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#5?= =?UTF-8?q?9)=20(KAN-135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index 18b61a28..36de2f96 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -21,7 +21,7 @@ import androidx.navigation.compose.rememberNavController import com.example.mhnfe.R import com.example.mhnfe.ui.components.MainTextBox import com.example.mhnfe.ui.components.SubTopBar -import com.example.mhnfe.ui.components.middleButton +import com.example.mhnfe.ui.components.MiddleButton import com.example.mhnfe.ui.theme.mainBlack import com.example.mhnfe.ui.theme.mainGray import com.example.mhnfe.ui.theme.mainYellow @@ -111,7 +111,7 @@ fun LoginScreen( verticalArrangement = Arrangement.spacedBy(16.dp) ) { // 로그인 버튼 - middleButton( + MiddleButton( text = "로그인", onClick = onLoginClick ) From 2db089a130dc19aee8e4a0857001d0d3414ff410 Mon Sep 17 00:00:00 2001 From: kimmatches Date: Wed, 6 Nov 2024 13:01:34 +0900 Subject: [PATCH 09/16] =?UTF-8?q?feat:=20CCTV=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=B6=94=EA=B0=80=20(#69)=20(#KAN-142)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/mhnfe/data/model/CCTV.kt | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt b/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt index 23e66054..edc304cc 100644 --- a/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt +++ b/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt @@ -2,7 +2,12 @@ package com.example.mhnfe.data.model data class CCTV( val id: String, - val name: String, + val deviceName: String, // 기기명 + val model: String, // 기종 + val os: String, // OS + val appVersion: String, // 앱 버전 + val batteryStatus: Int, // 배터리 상태 + val networkStatus: String // 네트워크 상태 ) //아무것도 없는거 테스트 할때 @@ -12,14 +17,29 @@ val emptyCCTVList = emptyList() val sampleCCTVList = listOf( CCTV( id = "1", - name = "주방" + deviceName = "주방", + model = "Flip5", + os = "Android 10", + appVersion = "2.3.1", + batteryStatus = 70, + networkStatus = "양호" ), CCTV( id = "2", - name = "거실" + deviceName = "거실", + model = "s24", + os = "Android 10", + appVersion = "3.0.0", + batteryStatus = 30, + networkStatus = "나쁨" ), CCTV( id = "3", - name = "방1" + deviceName = "방1", + model = "s23", + os = "Android 12", + appVersion = "1.5.2", + batteryStatus = 95, + networkStatus = "나쁨" ) ) From ef73b077c42c03587e3e6c41c7dad8e3089f5d2e Mon Sep 17 00:00:00 2001 From: dlawlstn1616 Date: Wed, 6 Nov 2024 13:37:24 +0900 Subject: [PATCH 10/16] =?UTF-8?q?fix:=20textbox=EC=9D=98=20isError,=20inpu?= =?UTF-8?q?tText=EB=A5=BC=20=EB=A7=A4=EA=B0=9C=EB=B3=80=EC=88=98=EB=A1=9C?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20(#63)=20(KAN-138)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/mhnfe/ui/components/TextBox.kt | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt b/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt index c1d101db..93b48859 100644 --- a/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt +++ b/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt @@ -48,13 +48,14 @@ import com.example.mhnfe.ui.theme.mainRed fun MainTextBox( modifier: Modifier = Modifier, focusManager: FocusManager, + isError: Boolean = false, + onIsErrorChange: (Boolean) -> Unit = {}, + inputText: String, + onInputTextChange: (String) -> Unit, hintText: String = "", // setting hint text warningText: String = "" // setting warning text ) { - var inputText by remember { mutableStateOf("") } // input text var isFocused by remember { mutableStateOf(false) } // focus state - var isError by rememberSaveable { mutableStateOf(false) } // error state - val backgroundColor = Color.White // borderColor changed by conditions @@ -71,20 +72,20 @@ fun MainTextBox( horizontalAlignment = Alignment.Start ) { BasicTextField( - modifier = Modifier + modifier = modifier .height(39.dp) .onFocusChanged { focusState -> isFocused = focusState.isFocused } .fillMaxWidth() .background(color = backgroundColor, shape = RoundedCornerShape(4.dp)) .border( - width = if (isFocused) 3.dp else 1.dp, + width = 1.dp, color = if (isFocused) mainBlack else borderColor, shape = RoundedCornerShape(4.dp) ), value = inputText, - onValueChange = { - newText -> inputText = newText + onValueChange = { newText -> + onInputTextChange(newText) }, cursorBrush = SolidColor(Color.Black), singleLine = true, @@ -99,13 +100,13 @@ fun MainTextBox( // innerTextField settings decorationBox = { innerTextField -> Row( - modifier = Modifier + modifier = modifier .fillMaxWidth() .padding(start = 8.dp, end = 8.dp), verticalAlignment = Alignment.CenterVertically ) { // Place holder - Box(modifier = Modifier.weight(1f)) { + Box(modifier = modifier.weight(1f)) { if (inputText.isEmpty() && !isFocused) { Text( text = hintText, @@ -119,11 +120,11 @@ fun MainTextBox( } // cancel button if (inputText.isNotEmpty()) { - IconButton(onClick = { inputText = "" }) { + IconButton(onClick = { onInputTextChange("") }) { Icon( imageVector = ImageVector.vectorResource(id = R.drawable.cancel_button), contentDescription = "Clear text", - modifier = Modifier.size(20.dp), + modifier = modifier.size(20.dp), tint = Color.Unspecified ) } From d22ea3d039c10a58fd8f3c50bdf073c5a393bea6 Mon Sep 17 00:00:00 2001 From: dlawlstn1616 Date: Wed, 6 Nov 2024 16:16:18 +0900 Subject: [PATCH 11/16] fix: MainTextBox parameter (#63) (KAN-138) --- .../com/example/mhnfe/ui/components/TextBox.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt b/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt index 93b48859..874093de 100644 --- a/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt +++ b/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt @@ -53,7 +53,7 @@ fun MainTextBox( inputText: String, onInputTextChange: (String) -> Unit, hintText: String = "", // setting hint text - warningText: String = "" // setting warning text +// warningText: String = "" // setting warning text ) { var isFocused by remember { mutableStateOf(false) } // focus state val backgroundColor = Color.White @@ -133,13 +133,13 @@ fun MainTextBox( } ) // Print warning text under text box - if (isError) { - Text( - text = warningText, - color = mainRed, - style = Typography.bodySmall.copy(fontSize = 12.sp) - ) - } +// if (isError) { +// Text( +// text = warningText, +// color = mainRed, +// style = Typography.bodySmall.copy(fontSize = 12.sp) +// ) +// } } } From 0518806fd17f7a9b87a76e55526f8e913e503e0c Mon Sep 17 00:00:00 2001 From: dlawlstn1616 Date: Wed, 6 Nov 2024 16:18:28 +0900 Subject: [PATCH 12/16] feat: cautionicon.xml add (#63) (KAN-138) --- app/src/main/res/drawable/cautionicon.xml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/src/main/res/drawable/cautionicon.xml diff --git a/app/src/main/res/drawable/cautionicon.xml b/app/src/main/res/drawable/cautionicon.xml new file mode 100644 index 00000000..dc780ba8 --- /dev/null +++ b/app/src/main/res/drawable/cautionicon.xml @@ -0,0 +1,9 @@ + + + From d56f4d5156485887b4ab9fe6dbf25c88dd100f92 Mon Sep 17 00:00:00 2001 From: dlawlstn1616 Date: Thu, 7 Nov 2024 10:49:24 +0900 Subject: [PATCH 13/16] =?UTF-8?q?feat:=20textbox=20error=20icon=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#63)=20(KAN-138)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/mhnfe/ui/components/TextBox.kt | 95 +++++++++++++------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt b/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt index 874093de..66d686ad 100644 --- a/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt +++ b/app/src/main/java/com/example/mhnfe/ui/components/TextBox.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions @@ -32,6 +33,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign @@ -50,10 +52,10 @@ fun MainTextBox( focusManager: FocusManager, isError: Boolean = false, onIsErrorChange: (Boolean) -> Unit = {}, - inputText: String, - onInputTextChange: (String) -> Unit, + inputText: String = "", + onInputTextChange: (String) -> Unit = {}, hintText: String = "", // setting hint text -// warningText: String = "" // setting warning text + warningText: String = "" // setting warning text ) { var isFocused by remember { mutableStateOf(false) } // focus state val backgroundColor = Color.White @@ -90,23 +92,26 @@ fun MainTextBox( cursorBrush = SolidColor(Color.Black), singleLine = true, // focus out when click enter - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), - // focus out when enter keyboardActions = KeyboardActions( onDone = { focusManager.clearFocus() } ), + keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done), // innerTextField settings decorationBox = { innerTextField -> Row( modifier = modifier .fillMaxWidth() - .padding(start = 8.dp, end = 8.dp), + .padding(start = 8.dp, end = 8.dp) + .wrapContentHeight(), + horizontalArrangement = Arrangement.spacedBy(10.dp , alignment = Alignment.Start), verticalAlignment = Alignment.CenterVertically ) { // Place holder - Box(modifier = modifier.weight(1f)) { + Box(modifier = modifier + .weight(1f) + ) { if (inputText.isEmpty() && !isFocused) { Text( text = hintText, @@ -133,29 +138,59 @@ fun MainTextBox( } ) // Print warning text under text box -// if (isError) { -// Text( -// text = warningText, -// color = mainRed, -// style = Typography.bodySmall.copy(fontSize = 12.sp) -// ) -// } + if (isError) { + Row( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight(), + horizontalArrangement = Arrangement.spacedBy(8.dp , alignment = Alignment.Start), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = modifier.size(16.dp), + painter = painterResource(id = R.drawable.cautionicon), + contentDescription = null, + tint = mainRed + ) + Text( + text = "warningText", + color = mainRed, + style = Typography.bodySmall.copy(fontSize = 12.sp) + ) + } + + } } } -//@Preview(showBackground = true) -//@Composable -//fun MainTextBoxPreview(){ -// val focusManager = LocalFocusManager.current -// -// Column ( -// modifier = Modifier -// .fillMaxSize(), -// horizontalAlignment = Alignment.CenterHorizontally, -// verticalArrangement = Arrangement.spacedBy(10.dp) -// ) { -// MainTextBox( -// focusManager = focusManager -// ) -// } -//} \ No newline at end of file +@Preview(showBackground = true) +@Composable +fun MainTextBoxPreview() { + // FocusManager를 로컬로 가져옵니다. + val focusManager = LocalFocusManager.current + var text by rememberSaveable { mutableStateOf("") } + var isError by rememberSaveable { mutableStateOf(false) } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(10.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + MainTextBox( + modifier = Modifier, + focusManager = focusManager, + isError = isError, + onIsErrorChange = { isError = it }, + inputText = text, + onInputTextChange = { newText -> + text = newText + // 예시로 오류 조건을 text 길이로 설정 + isError = newText.length > 3 + }, + hintText = "Enter text here...", + warningText = "Text must be at least 3 characters" + ) + } +} \ No newline at end of file From 946d22b2fac978cc1e0775d21fccc1484b5bfbcb Mon Sep 17 00:00:00 2001 From: kimmatches Date: Thu, 7 Nov 2024 11:12:07 +0900 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20=EA=B8=B0=EA=B8=B0=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#69)=20(KAN-142)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/mhnfe/data/model/CCTV.kt | 2 +- .../mhnfe/ui/navigation/AppNavigation.kt | 18 +- .../mhnfe/ui/screens/auth/LoginScreen.kt | 4 +- .../ui/screens/monitoring/DeviceInfoScreen.kt | 169 ++++++++++++++++++ .../ui/screens/monitoring/GroupScreen.kt | 103 +++++------ .../monitoring/MonitoringComponents.kt | 104 +++++++++++ app/src/main/res/drawable/bad_signal.xml | 13 ++ app/src/main/res/drawable/cctv_setting.xml | 27 +++ app/src/main/res/drawable/full_battery.xml | 13 ++ app/src/main/res/drawable/good_signal.xml | 13 ++ app/src/main/res/drawable/logo.png | Bin 15528 -> 18602 bytes app/src/main/res/drawable/logo2.png | Bin 18602 -> 9077 bytes app/src/main/res/drawable/low_battery.xml | 5 + app/src/main/res/drawable/medium_battery.xml | 13 ++ 14 files changed, 419 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/com/example/mhnfe/ui/screens/monitoring/DeviceInfoScreen.kt create mode 100644 app/src/main/java/com/example/mhnfe/ui/screens/monitoring/MonitoringComponents.kt create mode 100644 app/src/main/res/drawable/bad_signal.xml create mode 100644 app/src/main/res/drawable/cctv_setting.xml create mode 100644 app/src/main/res/drawable/full_battery.xml create mode 100644 app/src/main/res/drawable/good_signal.xml create mode 100644 app/src/main/res/drawable/low_battery.xml create mode 100644 app/src/main/res/drawable/medium_battery.xml diff --git a/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt b/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt index edc304cc..e68a842c 100644 --- a/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt +++ b/app/src/main/java/com/example/mhnfe/data/model/CCTV.kt @@ -41,5 +41,5 @@ val sampleCCTVList = listOf( appVersion = "1.5.2", batteryStatus = 95, networkStatus = "나쁨" - ) + ), ) diff --git a/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt b/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt index 8a19beaf..6503db12 100644 --- a/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/example/mhnfe/ui/navigation/AppNavigation.kt @@ -22,6 +22,7 @@ import com.amazonaws.mobile.client.AWSMobileClient import com.example.mhnfe.di.UserType import com.example.mhnfe.ui.bottombar.BottomNavigationBar import com.example.mhnfe.ui.screens.auth.StartUpScreen +import com.example.mhnfe.ui.screens.monitoring.DeviceInfoScreen import com.example.mhnfe.ui.screens.monitoring.GroupScreen import com.example.mhnfe.ui.screens.qr.QRGenerateScreen import com.example.mhnfe.ui.screens.qr.QRViewModel @@ -39,7 +40,9 @@ sealed class NavRoutes(val route: String) { object Monitoring : NavRoutes("monitoring") { object Group : NavRoutes("monitoring/group") - object DeviceInformation : NavRoutes("device_information") + object DeviceInformation : NavRoutes("device_information/{cctvId}") { + fun createRoute(cctvId: String) = "device_information/$cctvId" + } object QRScanner : NavRoutes("qr_scanner") object QRGenerate : NavRoutes("qr_generate/{userType}") { fun createRoute(userType: UserType) = "qr_generate/${userType.name.lowercase()}" @@ -155,8 +158,17 @@ fun MainContent( navController = bottomNavController // bottomNavController 전달 ) } - composable(NavRoutes.Monitoring.DeviceInformation.route) { - // DeviceInformationScreen + composable( + route = NavRoutes.Monitoring.DeviceInformation.route, + arguments = listOf( + navArgument("cctvId") { type = NavType.StringType } + ) + ) { backStackEntry -> + val cctvId = backStackEntry.arguments?.getString("cctvId") ?: return@composable + DeviceInfoScreen( + cctvId = cctvId, + navController = bottomNavController + ) } composable(NavRoutes.Monitoring.QRScanner.route) { // QRScannerScreen diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt index 18082894..4dea3228 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/auth/LoginScreen.kt @@ -22,10 +22,8 @@ import com.example.mhnfe.R import com.example.mhnfe.ui.components.MainTextBox import com.example.mhnfe.ui.components.SubTopBar import com.example.mhnfe.ui.components.MiddleButton -import com.example.mhnfe.ui.theme.mainBlack import com.example.mhnfe.ui.theme.mainGray import com.example.mhnfe.ui.theme.mainYellow -import com.example.mhnfe.ui.theme.mainGray3 @Composable fun LoginScreen( @@ -61,7 +59,7 @@ fun LoginScreen( ) { // 로고 이미지 Image( - painter = painterResource(id = R.drawable.logo2), + painter = painterResource(id = R.drawable.logo), contentDescription = "로고", modifier = modifier.size(250.dp), contentScale = ContentScale.Fit diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/DeviceInfoScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/DeviceInfoScreen.kt new file mode 100644 index 00000000..f976f5c8 --- /dev/null +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/DeviceInfoScreen.kt @@ -0,0 +1,169 @@ +package com.example.mhnfe.ui.screens.monitoring + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.example.mhnfe.R +import com.example.mhnfe.data.model.sampleCCTVList +import com.example.mhnfe.ui.components.SubTopBar +import com.example.mhnfe.ui.theme.Typography +import com.example.mhnfe.ui.theme.mainBlack +import com.example.mhnfe.ui.theme.mainGray2 + +@Composable +fun DeviceInfoScreen( + modifier: Modifier = Modifier, + cctvId: String, + navController: NavController, +) { + val cctv = sampleCCTVList.find { it.id == cctvId } + + Scaffold( + topBar = { + SubTopBar(text = "기기 정보", onBack = { navController.popBackStack()}) + }, + ) { innerPadding -> + if (cctv != null) { + Column( + modifier = modifier + .padding(innerPadding) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top + ) { + Column( + modifier = modifier.fillMaxWidth().wrapContentHeight().padding(vertical = 45.dp, horizontal = 34.dp), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(40.dp , alignment = Alignment.CenterVertically) + ) { + DeviceInfoCard(title = "기기 정보", label1 = "기기명", label2 = "기종", value1 = cctv.deviceName, value2 = cctv.model) + DeviceInfoCard(title = "버전 관리", label1 = "OS", label2 = "앱 버전", value1 = cctv.os, value2 = cctv.appVersion) + DeviceInfoCard(title = "연결 상태", label1 = "배터리", label2 = "네트워크 상태", value1 = cctv.batteryStatus.toString(), value2 = cctv.networkStatus) + Box( + modifier = modifier.fillMaxWidth(), + contentAlignment = Alignment.CenterEnd + ) { + Image( + painter = painterResource(id = R.drawable.logo2), + contentDescription = "로고", + modifier = modifier.size(147.dp, 168.dp), + contentScale = ContentScale.Fit + ) + } + + } + } + } else { + Column ( + modifier = modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ){ + Text( + style = Typography.bodyMedium, + text = "CCTV 정보를 찾을 수 없습니다.", + color = mainBlack + ) + } + } + } +} + +//기기 정보 UI +@Composable +private fun DeviceInfoCard( + modifier: Modifier = Modifier, + title : String, + label1: String, value1: String, + label2: String, value2: String +){ + Column( + modifier = modifier.fillMaxWidth().wrapContentHeight(), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(12.dp, alignment = Alignment.CenterVertically) + ) { + Text(title) + Column( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight() + .background(color = mainGray2, shape = RoundedCornerShape(8.dp)) + , + ) { + Row( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 13.dp, vertical = 10.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = label1, + modifier = modifier.width(120.dp) + ) + Text( + text = value1, + modifier = Modifier + .wrapContentWidth(Alignment.Start) + ) + } + HorizontalDivider(color = Color.White, thickness = 1.dp) + Row( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 13.dp, vertical = 10.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = label2, + modifier = Modifier.width(120.dp) + ) + Text( + text = value2, + modifier = modifier + .wrapContentWidth(Alignment.Start) + ) + } + } + } + +} + +@Preview(showBackground = true) +@Composable +private fun GroupScreenPreview() { + val navController = rememberNavController() + val cctv = sampleCCTVList.first() + DeviceInfoScreen(cctvId = cctv.id,navController = navController) +// GroupScreen( +// userType = UserType.VIEWER, +// navController = navController +// ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt index b3e55904..9094ec02 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/GroupScreen.kt @@ -5,18 +5,10 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row 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.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Edit -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -27,6 +19,7 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import com.example.mhnfe.data.model.CCTV +import com.example.mhnfe.data.model.emptyCCTVList import com.example.mhnfe.data.model.sampleCCTVList import com.example.mhnfe.di.UserType import com.example.mhnfe.ui.components.MainTopBar @@ -34,7 +27,7 @@ import com.example.mhnfe.ui.components.SmallButton import com.example.mhnfe.ui.navigation.NavRoutes import com.example.mhnfe.ui.theme.Typography import com.example.mhnfe.ui.theme.mainBlack -import com.example.mhnfe.ui.theme.mainGray3 + @Composable fun GroupScreen( @@ -59,6 +52,7 @@ fun GroupScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(40.dp, alignment = Alignment.CenterVertically) ) { + //마스터 화면 일 때 버튼 추가 if (userType == UserType.MASTER) { Row( modifier = modifier.fillMaxWidth().wrapContentHeight(), @@ -84,23 +78,37 @@ fun GroupScreen( } } if (cctv.isEmpty()) { - Text( - style = Typography.bodyMedium, - text = "등록된 CCTV가 없습니다.", - color = mainBlack - ) + Column ( + modifier = modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + style = Typography.bodyMedium, + text = "등록된 CCTV가 없습니다.", + color = mainBlack + ) + } } else { LazyColumn( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize(), verticalArrangement = Arrangement.spacedBy(28.dp), horizontalAlignment = Alignment.CenterHorizontally ) { items( items = cctv, - key = { it.id } // 각 아이템의 고유 키 설정 + key = { it.id } ) { cctvItem -> CCTVItemCard( cctv = cctvItem, + onClick = { + // cctv 화면으로 이동 + // navController.navigate("camera/${cctvItem.id}") + }, + onEdit = { + navController.navigate(NavRoutes.Monitoring.DeviceInformation.createRoute(cctvItem.id)) + } ) } } @@ -109,54 +117,33 @@ fun GroupScreen( } } -//예시로 만들어 놓은 것 다시만들어야함 +@Preview(showBackground = true) @Composable -private fun CCTVItemCard( - cctv: CCTV, - modifier: Modifier = Modifier, - onEdit: () -> Unit = {}, - onDelete: () -> Unit = {} -) { - Card( - modifier = modifier - .fillMaxWidth() - .height(170.dp), - elevation = CardDefaults.cardElevation( - defaultElevation = 3.dp - ), - colors = CardDefaults.cardColors( - containerColor = mainGray3 - ) - ) { - Row( - modifier = modifier - .fillMaxWidth() - .padding(16.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = cctv.name, - style = Typography.bodyMedium - ) - IconButton( - modifier = modifier.size(24.dp), - onClick = onEdit - ) { - Icon( - imageVector = Icons.Default.Edit, - contentDescription = "편집" - ) - } - } - } +private fun GroupScreenPreview() { + val navController = rememberNavController() + GroupScreen( + userType = UserType.VIEWER, + navController = navController, + cctv = sampleCCTVList + ) } @Preview(showBackground = true) @Composable -fun GroupScreenPreview() { +private fun GroupScreenPreview2() { val navController = rememberNavController() GroupScreen( userType = UserType.VIEWER, - navController = navController + navController = navController, + cctv = emptyCCTVList + ) +} +@Preview(showBackground = true) +@Composable +private fun GroupScreenPreview3() { + val navController = rememberNavController() + GroupScreen( + userType = UserType.MASTER, + navController = navController, + cctv = sampleCCTVList ) } \ No newline at end of file diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/MonitoringComponents.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/MonitoringComponents.kt new file mode 100644 index 00000000..78902acb --- /dev/null +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/MonitoringComponents.kt @@ -0,0 +1,104 @@ +package com.example.mhnfe.ui.screens.monitoring + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.example.mhnfe.R +import com.example.mhnfe.data.model.CCTV +import com.example.mhnfe.ui.theme.Typography +import com.example.mhnfe.ui.theme.mainGray3 + +@Composable +fun CCTVItemCard( + cctv: CCTV, + modifier: Modifier = Modifier, + onClick: () -> Unit, + onEdit: () -> Unit = {}, +) { + Card( + modifier = modifier + .fillMaxWidth() + .height(170.dp) + .clickable(onClick = onClick), + colors = CardDefaults.cardColors( + containerColor = mainGray3 + ), + shape = RoundedCornerShape(16.dp) + ) { + Row( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = cctv.deviceName, + style = Typography.bodyMedium + ) + Row( + modifier = modifier + .wrapContentSize(), + horizontalArrangement = Arrangement.spacedBy(6.dp, alignment = Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically + ){ + Box( + modifier = modifier.size(24.dp) + ) { + Icon( + modifier = modifier.size(20.dp, 16.dp).align(Alignment.Center), + painter = painterResource(id = if(cctv.networkStatus == "양호") R.drawable.good_signal else R.drawable.bad_signal), + contentDescription = "signal", + tint = Color.Unspecified + ) + } + Box( + modifier = modifier.size(24.dp) + ) { + Icon( + modifier = modifier.size(20.dp, 16.dp).align(Alignment.Center), + painter = painterResource( + id = when { + //배터리 양 별로 다른 아이콘 + cctv.batteryStatus >= 80 -> R.drawable.full_battery + cctv.batteryStatus >= 40 -> R.drawable.medium_battery + else -> R.drawable.low_battery + }), + contentDescription = "편집" + ) + } + IconButton( + modifier = modifier.size(24.dp), + onClick = onEdit + ) { + Icon( + modifier = modifier.size(6.dp, 20.dp), + painter = painterResource(id = R.drawable.cctv_setting), + contentDescription = "편집" + ) + } + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bad_signal.xml b/app/src/main/res/drawable/bad_signal.xml new file mode 100644 index 00000000..ddb78950 --- /dev/null +++ b/app/src/main/res/drawable/bad_signal.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/cctv_setting.xml b/app/src/main/res/drawable/cctv_setting.xml new file mode 100644 index 00000000..934e3f6b --- /dev/null +++ b/app/src/main/res/drawable/cctv_setting.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/app/src/main/res/drawable/full_battery.xml b/app/src/main/res/drawable/full_battery.xml new file mode 100644 index 00000000..87adb646 --- /dev/null +++ b/app/src/main/res/drawable/full_battery.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/good_signal.xml b/app/src/main/res/drawable/good_signal.xml new file mode 100644 index 00000000..fe37e464 --- /dev/null +++ b/app/src/main/res/drawable/good_signal.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png index 04090afc13bbbc0dcbc333f8d327919801b50008..46a485e9b19276511c0512c77ce1ad9e1d1defc2 100644 GIT binary patch literal 18602 zcmcGV^;2CvwD)m$cXuA#-QDG&MOxh5T}pu>2Ph83?Hr_daVU0x;vC$HySrZQ{R`e- z-kD_f?3K)9c9NByZ`LPq+L}t3Xk=(GFff=Z%JRA}FtB(Z*#ZUW!xDKZm-6vIbyqg_ zf`LKD|KAJ?laojCVTAS4Rg#6NouD}UctNm}(U5_GsZU0K`HTnyqb#K&FQe}dd%A`k zOfd+BxwyCWt*dPR!aeQ{hoB6{lf~wq<_xMo%qKy~PmU&lqsxbhkgkMv7R|!xU1V$N zD;FY1c0Ztu3IcR=tYzPi|76%Mo+UKPmKcA(PxI+sn{8fe)!Tp}iTV8hEu{cZ6zk-g zn=!CRjo`MnbqiYxx0^6*1<5haay$VZc*)U(2}$;y8$=G;g)wtNy`5ytKFUm`{~D?kmpq7H9Fsj@uz(5Ys% zGqPF}B|1i{%ybKK3Q46b+5yb8Yic+;ZVe*aCO;&#=FN`U|1~$Zau}UIZ~y_XpqO}) z0;TrW>R+`8;_6~c_}MxrS_dmM;=kg^(bnh}%BE2Z4`TTII7(m!VSsaD-F!{Tl=)n029m~fT?Ay05N1pJF$BEvsnxiaj^(v)B4ADC;sV$~ zk{jQ@jTfWd$JwF%rPCV2<%;2`S-4wtP$FFtNsU#AjC^Eh8d@j|sRFs~7gC2!rlECBX$* zQHJ)4F!dX=0>W!e=N>A)wr4Lw>VG9mb|*=TynOI z|MJxJoYV?44*?Ma*&&BTJO8zfjD1IpNkK2ZWg&ejBnr$n_mZ7P&wP_^3BIIDu`>A0 z=c#$sy^pLY70i5t*F^{9pL~1VE1Gw+0NCI)4ke@zLr$`GUXy<*tqZ{iMigT+==-T@ zZ=M*_lpsfb-oanS8txXey4~R_f)M(UqmJj>s|oJ6O4q~pa$hAFm6oun#OOhNp+$BJ$_kQz-oenq^$qMUD zyk6QK_`QL4j77HC;fwcORgiQFOT08)PtcPa&45-fcW@-k(}n$wAgH5~Wj^&Tgr;a; zb0cCkW3~^%==k1u9)_b~Q27&Y92wmSO2Puyecp_FJ1n8xa7)15fXrcd%ee~Am^(>a zeSTbTYodQ=>y9`-uc}Lnu=m-}!Y&$hr>E}dL*AT-^y>3i~vjluCedJ?$OY7J=MyfYEjHj1I@0+#nG-F>dnJq?l za*hF7Ijs4ma5Wt@IaT|ST93TIsnumXzrz(S`Zg&zdY9<=_ul0f&!C+(k@0oH+<=L) zzs5IyX+yM#kYX1b_*PCS{~6v3T8q2o*j@A_J{bnS0o8r^ekrP-$24203BUJkcWkr;vlJ*vQYDu_13o~Z`>G@O@{U;_a!C*UYTx?ZkN87<&I4l9@>DeuK%3S~d! zdPREM)H9s?;YIcW_oE(dKHnVj>M@ao7IFP%ZguGnH^u8fMPaUv>7+I^*MK`UO~+!K z`g$-0=JYRnBYP z&|tvDjGPu|%1|@#MaA#u?2mdczJ(|wJmDqmC@;eeLO1cdQ5aDC#YxQMo}H+cgPjWl zM>!5B7C8{&ikdA;73Gy?R^Q2CBnv}m;sk%TBaaeo5L{j<`IsArP{o>boFso+dqsLc zFnR5Up;w@zG5k*yHCXyNrG}`9Qr-H>v^tsl0(LRi!Z!JLBks$P*&`DPD?O=1OsuQI zINyvzSY#@>05nIl^M+%m4ExH~AIItJ6Q-nfL=(aeE_NqkDiZ9Yx5?Lp7m}YnQ$eRD z`)t#qKzUoUUwi}I%RNGN7xWmM(nEWY-p!yBkm)+~b@WGq^&JYtjv?i@bWDqIfl_z2 z3d3{cx%O9_8v41!AZaTTWIRp-jSG{yzIO%3SDZ$q$#*r!XDKy%`CtW zWAxpOcWWXbw9a)0U)R|X(rCX@{5n@>R|22hF8upsZ*IoXmb65&eDMtaGF6Ij>#$OM%G+ zt(syoQsSXllKemt;wcTV`F1HnCoP!IRgPVwjv8)e{C#UlJ>jg=p{}Ma*&h;SHZ>!% zJO;qXnfX{a)b{TIE|^cd);19fHMp%3@QRAo)u+E?`F-iy#3lh{MGvQ__y|k6W(c8j zXT1;*KZZB)BZF6@BZ26NY{uv zATMb>6C}J5%PikDZ;0|mcU@!(Zs6n9tF$7zmj?|lmVD;v!lOl<*>|H2u>P1F`9myD z%Bjk1nZ!-?a_r*ILdtc=#+q(edir9Ye~4c@g_SGHHlE(GD`Px2Wn6+}+W!C*|B$yj zW{YTyNk{J33;kzqHYgdBF81VU6j-FQjcOXTVlc%hPTF|4^dLF${EqrEcg$qNC@%%& z!Ff1UDmFUk#tX(fXS zi)@AyI6(Az&q6tzjANNhym(f_Ag>t(XC-asn-8kp6botg(&(L*;*!-uho?E&$6X#2+Tpcgt zM!Rhh$)&vcuqIPTS_2o?vD4oLs4^g%wy@uHx?aeDj42xNjBF+K44s+o+&n~ zO_f4bzRy*=A+g(Lm&wjbPZl(wqZxu9b(MMZ?8%p2Ens@2S26fY7N7-RZ^rTaqEQ(f zfSic{o4?%l2s%`G_NFwy`_(T{@oECJ27w9YjCjTmu7BjexK@+sO73Bfw0IPfA2PVs ziLkUpa{qz}hRH57`@_{0=whwjp}fK>-9V7=Lwma_C_MHIS#pbmIo>`DMN&H4G~AXS zok6z0=<@WFSk^}Apd?c^#qn+r@*0hASf^=*6w{^3(l^`5c{UA@Ie>g8(D#+?pv5t( zUPEifVaDgirj?kjq4h=~4uORX=3b{}8UNPNSphA)c2!`xylqxxMJ>}cSsFP!2H|t7 zm5G7QQV{61kGOx=%%luj$nOG&+I6}AChf{-ACJ;>>^YmV_A;&wttlL*X}Ya~VeVMz zHU_vfiZT*KP%9S!wtFNQQ|+CBPd}U0m$zi1<#O!aKdt0tFH4uNRgQTpOIsk|4HO!f z9X}!9kxq9QMz8)NG%k0EQz54lMdMch-7+0&VpzaYJfi1s3t0ipaSSWpAa8Il(zk#p#U@k+->Hm3G4Ghj6ky{^Pldm6r?lxvBb%yq zx4p9h4h4Vlc;-4=^qT|5+9Iwc!$4cjnsgPWCC%Y-8-;8)BzjoI5o%tcLBpD&3r1NH zSk60|oZ*YgMT%VpNn3$@bNHpe0MQEx%TLeIQ}Q}Bprxm#6r5`rLASn7MqU^sX0j;u z>)@|7D)+({ZW`e&cgJfuDmAvF$9e_L(Oemb+SH5w+=93c!Zu2>Z5;L(tPM4;qa`Ec9}4RUw-iRH705LgcLJ?w4`Kz;!5BQ?2hh@kI9+T7ibF&VE?=q}lo6LQpVZRrhY^pQm6sG1cevu8+f0WQkRET;Acm??9yf)Nb1ha0_6R90Vy zVCA0rr07%^X*+p#?m@uqoaPhrlj4W`BG^1Kx*3yIV0ab-uk)0p-qPBOb@fH9{!G2< z{%eAiL$6|zxG-HIztuQMMWRs00D}5o076x8r^TWu{#CG^vmJ&^QSj=~9qNXsagmuW zq|{Rm=GAE-&?g;I=mNkQV@TzBtJxmqubaxVi#f5U1%j!Xb1hq{Ic8u#daIwx7z_nC zhBWdgv*C*zWmLI$$nM1a6(&I++BSXzBuK@u|BdeM9|CtT9D6el86r(}19AP{mNya8 zj3h9;YS}w+E3rnBfo@^?MJ*^q($KIa7&T|hUQ5+347N0chIWR%qezg8=^)dCfxKi9 zrtJYNCCjC>$r(w|VR#*nyl-6RdT(NqOk3_EP?J`*%z%^r=0txezoTBdKOu$@Sl@e4 zu}=GI18JOwJ&3@`X_o!8_-$JmMT6#0ck0RkIwUufQ9md&+r;z4DUyR68(}EJY|r&2 z-BcrnpU0L_BfJ#$ql3o z)zlQ?hQO&9PxUaSYEB$oug0WlMVg~w|9-3Ov9;qle3F73p z_`3S`W93=>OsR@uF2!WI2uK7DF`L+2qh-I8)ioYnhJD3A3=6(_2K6Z&|0ExeNwMco z8bEvOah#R8-FlG*UW<=QHW?;yeU3u1P!fM&B0w;msA)*UWxlDFFA5<3#lYuKr}p`f zKmlq?NxEVpF9a?zuDEUYhX1{Q$wA~C#9u!(3^WWDKz!Ed#Z8m^_H(8SeKCRl&?L7h zo*n2ffBp8yn9pbTFMH719~0rHJq4mm_=wEEQNhwJG1YJQC;zbj#yHbViMoMZ(->}9 zQ*Jg|2ZbJ$XK3?3@1EIl-3{?D8C?(Xnj7dKl7#9~I<|q^uQpA2ggPrE9IwAj z|0s`E^*Rl@<%!25o*y+qs_ZwxO_vE~MVWo@=S~fdKgF?5MrUD9tM_CT1_U5ub^qY+ zM4NUX%)G}%D&e%Vf!&Gxq%(LpjDv>F#@KN!U2R6UWaHVDx652@UlM~KXxGCIYOOOj zV#Ob9l2r>Jhz%DSJftr?)UOZc9tF$QnN$quZ^-;Z>f|bL#nqMYDik6i^2b|&JlhXW zDviYslABW-)xVS^LlMb+wvqz2*r15g^vejTp*WN9uwC$=*;1EM1j&UOvGRJ_U=!!-4Og${eL;xcd#LitJb9nnHv$FhcGLTmMDtIo!E0)q6)+0$iejVepEoH>eEXGsFMs zWRj6CX{BpZ;kaO;=RJ7{>AsT6^+Lqt|4vq}VgL`{G%Q=UvYRp~4{l{#!DKdE#7!^g zt#6BmuG=HSV8>(!r4izejgCTgz6ODa8YEqwQd|hC+bK6`6>R;J&gE%wm66WaHK0uR=BDu-A|uVsGW+0w z;(t484x|293ZrA^Tl3V{TJ?8PlRDLHpVFt6k!{;Fm}gcy8oGgP(V=>M%Bls@4M774 zDOC8mX+}P2)i?zmd|IMJ@hAd$Ym*M*XK18mk64fcL=bIY{}Dx7`md|6CA4GJo12;8 z#*gGV1-xCF#2=q8?h>>d{7v4P+}%LxP*DBB&w3tFENW83XB!*0=}N=fw2m2Q%CxLC zI{z7HV+1&cL$VE@=17D?JrJ$wE9jim+49BQsIx#){(!UQv=G<3L=uHPU7I@MS>{v0fyjpQ2Y-n zxq37E<@y!5jDM9%Qr7?75ZFg|BC_%q>(q_=^Xf<$GQckdX6gyu-EYG4Z&!!NuWa2* z3!bK}!!s(9t{{5C)Spmyx#&8GHXXeIJ`W(Ie$rtk#e1E|4~U#+#1H(J*I(Mvw0;~H zi9yq!w=*=TbKesyenU%QHp2}36vUAwoa%IRo!I==??RDzyPoLmZkrzlbT+%fNTGls zZIE|n*+FT9%iQIUYfe7IS9Wyj8i8j@-N_?II$T$q%x__|kG6evw(#x_$|yaUPOytR z`w65Mewjx45>agf;$m7xz)R4w=f9E_eU-0%G?_vWpsLT0!Xj}rO$*Eap^ zNe!B;ccB|cy5wk2=b16F60Q4cAGnK^T4M}O(xyss5Dd;-3IB>Ns*EWxmQrp=bGS=7bCq-uzL>D> z_YJOSe^L^CwPm(3zylEGV44$PJ3pN2d_iHvE<)~&Wob!EfR+=?fLg?wvO^qK$XNVM z7Ix}{?4?2u7tU)giAa_8WVnm8`iDToGf&VxmN?I{Fva`tZ<|kLngM)F{Ns#OI zB{RMavtEyY=T+3eSQzr7El4n~h?LF(rW&KRW_(3PMXx-%tmAI)&khA(mmvNO%k^5$ z^;N8~Bysp0*4Pr!w~ea$%8sT0@aW6e zu-{%4vkZ1X71DgHnU);Y=*AVH{jxG1pI7k})^>K;b(HOb$)}c2aP2e=`sAbibN+jW zQ*y6PwPs_HxzNh%Ai|xmRm&tMMYh#7<7(U<4$yxLYk7Ys#M2T~~Xp?$RhNfX8zYbObnAucPWCSWM?BPt>lf*uh5 zrv`4kDB*SL)FKSU8aCR#9 zCM#XP){8vlB8u5CK=wFQ0`u>ghIs0S@(VI)5#SP?xpTPI_g1gtVp_{(V(fmI68@D7 znJVXO*m!I})f^=u@B$M8fBD%=K$+RF|6e0oS>=f0Z8^T3RM#gn|L(~D=x2^sp-whI zb6)M3pGVGXbduMm9^aF2f1mrktjaespRv)g*XkRt;R_l6R?#Cl@RHg=z1s9;Fzv-w zRz#NVF-8XGHqxTI&vBW2nY0j3Qt0-Vqa166{5mY5Yt$xC zt)HxaOwZ&xcj%`m=q&y?Ja=*^s5Fcl9v}TaJF2ct#uq-x2pEtJi#+)VzZ88k#KocP z-Tc#((bX$W?`lY{VzXcg%|}0(eqSf7X~=D&Dj$pT+q&4O4i~3oeTqn~Jj=a4%tuzG z{a(G`*OPH+32*%oC5ZzL=jlk2$K)4X5B8D=B#J`G9pB1I{9za+=?iQAxp57n*@zge}Sv@<;5a zGtst8=xwz?-kIhB<2z?hp1JVz$H+(E-cJ~oK`rDAvd%Wntc8G;V6MgV{pAv>$F-qr zl};o*sDvN3@oVjA?GJk%<`VYU`+LAI(SqKIW2jWyRLGvtQscj8~FcuZG53JxT^JNduZv|nXI z{^s!0(HqSJ!{n%zG{HR}f#bA#j@8A{q4}kKXGCM`r4S}iRHGe$g4cxs)yB&jETkEk z9L#X|!-p#~nw-Qx;>l#*yLs)8Q8JM;T0+hZ($z&tAv{qameQwtft{42i@$;0bHTEt zYm7Kfp&Ec`-^1?;pmw+Pz{#YwHf%yl~VKD#p)Zx z!H>G4aco2tB;Pt)0NTp*+H$%I=BNhzyyN%hq z!Z$u?F70S~hAJm6+y}ekwQfYnqTLl>AchlAVhl#2xJ-a)zh|wUz{3zcq+0Ir_D0#qwrCDu8aTGwR<4)JdbM#3UeS!W2YqC zXf$acCJNYR=1-13pAwUZ`4j`LZ%C_OkfrFrCrAh_M1g2aol}sJfV%mC00~hKt$mbAV3(Ng*OGz+<)xZ|!%$h%PhGA~|7B$w$p=wp<4KYq z>!qC0PP(Dtwo7|Aj?Sl_@B;FArfA~6e8DoGOq!eN2P`_ndY!# zzfmSKX%Hb7x0+p$*_1bYp|(B(x?#h|-!474LLt7nK8ro6nrKaM9WNvL8PM7k8>uGzld*%vXvNm|~j^&Fu~gaZJzM?0odgBEoJ92TEo9q<}8C6HJ= z2Zrv|Fh0#HHAhLu``eEN5^fsEnsgczRPXgFqjOYZhX0T&R95bIZ#MFol!ed+4fNQ; zwo)m#P>)s`0EV`5nv^shRA!lnWwcVDw=DWgfjNA~FHtlKn*F3Dea0ck&Yz~f_zonA z>d|2OLpFLo56tAgCEwwJgYOZwSyHr(LYR&7FAP{_K)C0bW3H4{8n5n<@S{nRnYDfZCZJOkNjL_q=09NrVTz*9#djf|xvuj5%&y!4}3p{{Mc4?m7ZW?(rsvstei66>Jo)q#;{uoNL z#tAk?n5Te*6P~=Ai#}WZDz#ke{%LfaS`c1PMA$zSZgDaF-i>qh7cJ%;L}#>RqoscD z*4luhB2PnM?n7t|F^vzm=2tP~azXsE`})V#=-))vMG8s#CVRxB(06D-NPO|5=9JHETyFBAyqGpUng5DB=f?oMzHt%Yc%5|MJn~+^j$fr%v)AKB6qd8ztg1Ma zjhOP;1WS1vnqjvQndL4OGGUbF)nJxA-whoyUdMgFDV1k0F1^IR5s3T=;ov7+L5r{7 zg6H~M-6W461fzflg7hC7->LLI!k#mxZ&QHzR z>>*N5>dXK(-49u5KD}&XW@X1e^x6j+$_;0`b90rO0z)?P70Zpc~-YQ0*t!Y zG2qVg>xx((+kt#vQ<;()HX?$FX;*j4g}s_-A6|T~>d)Rc72J>5cA}}!o2ZZ8u}X*u zB3`z&Ed`w^ZT+N&@2#Ad=((3IMGy>1D30#UC$8^MCTzNflx5D=UJ*4xipO+QzY{RX zOOS5orN~Gtw@P)&fQ|oad+--qk?68kQ`k^ss=FyB(gpjw0oXrrSoCdoCIr)6w1C&# zF7aQ7n&kJO(4aEBdf*bZ$8x)+T#XgqX1bjl`H20$^rdEtki}Gvz zE+#8x0aEY?6`#c5jM|;Z?Y3Q!vk1jiH1`YkF|yPP0K`uBlrrl-N_bGaTKJlj`7(DG z1C2tuIch#EcL4g2xWq-q+BJe!avv*)!^Uf1gFuQSR2sT^lea~Hmi{dLkJ97MLd}!?*KV48nmluqfLSDZucu+u;{3q#wguj zsTO}dhZRch*BL}aGqROeJsW1ah6t3xD6L-0L_eJ%cb;%S5KJ@-Mq0KnHgk!~Zhv)! zPXD2OVgJRJh7IRsnpF5?b^n#X-$jJe^oe_95t~+lz)8&u!TAnl`bEh{0W$0H)!LYl zxDZL=zqXj5xglV>^J2+wUyV_h^R~S-4~Bon@YpY=qjFtiL+a*#J#yKs`NUWaJxi;(v*mJE~G#_68p?l8_4{KYQ1 zzxQE@(IEP*5z6VCPLtx82J-`z*)N;o2MUnP7ez~?7xDFlJdpqW_a?EE^5cc)K*9Y% zD&qqtl1Ml^8tZ(=W=k)3oNcZJ3zm-F0!J*wUd|@NZ&f5{asRCR-e{Ki$>f^c`A&#( zBZdo9>R3zJk;ZWuM)$i#r@MMoDt74GFW&9f(l0qucVEcMbH%x&*=&8Jid8IF#UuE= zMFe%qSdgD2@CrnzQSm5xf%>8oj;P- zeXajBk;MhY{}el|0QLF`!T73yK=oRdmv=nGpGqBYOO^ za0B&*21cM9V}I?F!Ru4U{q`=G$3sVudqM(o>mdT2--`1m=*oj&0BcGxPn96UK;#IB z#PBzU{a;SdVC&51ME@J-a3vYy9G`bzq1hpcDrP7-%ZdX?^a4-wOAD6vj2ltjY1Dz)D*~u{lE~+& zQ8zU2D%3)SG-;7_xy-xx(_ZBAKVERKE$u$XW~|bi)v5oTxiw%86b>}zBD6#Q{PK`D z`NNA$>miCwffDvB6P-lIZxZ8eu)=`CNk@-#dDzq77#8dyL)LsPo8*swp4i6GVo>?h z54vbf4e3>U_iL&kPO!v6AJ8`6S3Ew$A{=8<;CS`a%mFfgj^*vis`IK8Y9Ad}Ct)!G?sxNN}Vq41X z+DGTh$b>BZ6`fA>eHLT*+R-v`Ff z#2_Ici972`-JJNeDFdvGs6jfZa1%AG&F|FK6fJ7qa@#)B$HLOZbV}=`ORY*vqI-NU zf1PP3Iy)RHVEV?cB7^ETH-ntSc{~YMYB4zy$(wp z3LJf-IB9CE^%*|KO}SNCL;EA5+DKuvp?4}!zZvY7pff>qFPJ*Z2CT&ThQUNTQZq-} zO*pe0Mf24oG`8>lOGHibFYKNXV*GCXsb?g;@zGduFg>MB|8Fqrz~eGfim>jh>2yIP zDg$EKf+s=huAmD=qf}yyABa`trQEHLc`B~7(~)NBU&2s<_n?b-2;Imc)Y$lydpOIU z%4#T$Aj2R6fya-p2gf*VAapoW|COTxJYuIOJ}aT9XF(-rYbRK};y;ADS^JwYEPEm_ zh5<9u*lstJ6qmk;?o&gfQ)>De8Hq%dWj2)W-`P8~h-U4FAx2XcbXyuP!1g7HC1ayP zl80KrGF~#tUJ@oDavJOi-xeYM`w!d7Ufm|Wxf`nNtk3!Z@CP-673=|QPM8C=tJr(d z55CbuIiC=0AlLn2i$4`pY8N2JNsa2T?Ngf zS2%IJk)o3X`BIT_90M_Gopy6QmZ}qGwrp|C*i)Qm7J}=n0+2~F8yTHUNKy& zYQ2oZVIJ|dj|F91mEpfScO-qKqA_fx$*T3+2hBT2KFvfPpance{8EC`gvN06 zqoUewmWH(SQRudh+AISK-M5-7=*YD9zb8Y_E0G!XXIb1Vn|%^$_t#rD%UUD(cHo?L z)P3XVBGtCn^R5FRtFgVlL!iBbEujhK*{oDjE;bT*7lz>34ILu?zTLL1hx~buOrU_* zEfj>pS*KT>l(PX@<~#3cMi$Mr<$;$){Li}h>S)q+ZGt~?`BGQst)O*5g~*kcd8Y_9 zZJ4Ws^Z@snMz-)QU8v%O=&2)c?7ACEV0*R< zeF7JYYCALM!0}JyfK-@&wOxk#l8?d?VS7{ZjS7YmK8n=$k6uYW$H}3HyYYuCCUho6kfb=lxQxezD#;mI?SaUMt%Haw@~&b($qB<&hdi9|?ZVL2RipmjlQLUQd8WEP zD`(ZqB)&){uU7WoZ|{o}3bvG(am{ua+kSRkzJ3T`AsT&eT1PmSa=Vu)O6_!j9d(Lqw@(IPAb8 zD1q?+=$g9&%1jBrpbUX|l<~^*8)y}L-CzRBD$yjN1So7TGclTn)C9T||A(&I9 zzhVW^o$i^sO&lhbzZ%wiXdQHZb#Z#1leDiTmKH;D+9l(@(yW7ZxI|@BOpcp(%n39^ z)$imXFwMLxPCq!X5#J-_BdLM;n1|{B7i$Am#!JaehLw)apnhZ*ZVTHIW9j@fCsArS zvzPpb9?ImE!sVekPR}ke_Y$ct*Zsr|`QeRtA=TOYN$6$Rxz74Kl-lp%@3zr@+!R1A zy-6i=pleuc=7PXmPG^;d`R1KTIV4EcjhfW0!Z9qc{HKy{r(pS6=5f#Z?N~!YNV@#e zV-}`lrcZ(Ci^%p0V|7sescEH^EFK3y%_4fn>?%;>|&!8B#wU5QH%R+NcPXU6+QRaBIsC5^$ zk2PrH^qm;ts1+aI+VrUPspoW80nlotQzS~pL3(|cqP}K82^nC8lqINUMjA-Vg5_|1 z#H>-5m^jcf(NV{F95DgfDzl)6Yd_9;Q?lw+nh$@?jNypfUSo@%iW+PO5-4qM|3O_$(U|PBVR7l+? zmKJk1~`+CXVKS?j~<&WKmvVf86 zP064jT>jlMxlzOJ^u?Q;BJ~;8Bhs-sy-*UbgUbsZObgkROBb4=LxEiMaK|6~+PoN* zB_*#6aa_TJTj$?DKcmuh@mr`5wKgW{sZgFIiPlK&rAIjUZ_btL7YK>E{H3DUm6{s| z-2te#_B`eTDGVkb@z4@}l6RCP#AiZ>xe)@D6$%ReWwpC5sFyP$yk$NW{q6gU7Dp5zKK7jGlds8Y3CX1Ei=IHCi|&#ZASLuqdw^pqHv(Eh=?j@r zh9q_I;F^o8+3%Jx9RELvBLMd`41Sz+{(-GHwT&a6H-ZLr!08h`6Xyjw6SL?n2s^%F zIK3C}wNoJ-MoMqos19*h(*j0vy8{oE_rD0|V|#yf#pX7I_BAZv>p}+8I#GbmV2WMg zuzU01VdvQ$OUi#sq8)jT*c=aos$Jn%u71)d=*HzqvuBwGv=n7<<7I3~pNg@n(V?g8 zr2QQtf5g5#9gO`SwmyRSS5-QlEcmDJ=cG*UH~aggBYJ&m_4M{FmlDplqK8qu@JqnK zT)NiK0!};^Ev;BabSxL)Kjla!q$`(olQ&^a|KhfeeMkH}xc^3U6SJn>W9_x%xy%6osgvx$1V30}LeR$>{(Rp_0erG~RPpOl-S!}nC z27vFRti~^DlHfBmCiRxVIdYJArN*ZCZ2U)i1U{Q~iJ37Ax4Fb+H&6^D-X8`Ibt6&! z^u5=!Bg{I$=>4b6UzKx4pZ6aZK~CyxQiaM7wa=|qeTS~z#y83)(K6MywKSYJ%1<)? zk(Q+c}0^3WE=a?K+X8Jpxt<}&EWfcuvA`av40h0M#p%pUt4qKQ|Yq^f1zyfn9Ul9loq4|d6F?)yGmlmek0uIZ? zCoDF@nAC^e(K%Oo-T&-!p<$!mO?w}5-H{X^+P(GRN=kKkIeYhKW|X>F0!aecL56o8 zH-A&2%s6Ahty}J+FB3oRI3Wdi@g`|KAp3vb^1L|MUr!bnyQ?57>8ZpI<+}ZXJOnnL zo8H{N?bY6Yj%CI?c;FUo)%)~Zd->Y=?%zXybe0U=2o48m1$n2Tw}RnNwR|s6;1P#Y znDdZ7tjZoKt*O!)6r$s%^QL2L99bTrNwYS z;?TuS9@?f25rU}V_khG=O||Edoyrv(-{;f4nTI=@BRk8=nve}xb`(i8JPb5^{e?js zF|9v;*ZuJQ&_ffd)L<^ptW>H3gD9_Ey2A?01oDIYP-T>aeV}0tPDgdBH^|W4Bwh*q zxvvepOxxEz!F>BeVISvvr_XDjLRKoO!=y{Oxmm;jcsdVAO-YK|{{g&GgI&!F@z%n; zWjv8vB_()Ie4e8j6#jL+WuEij*$X4B=La#zJ8p@-0Cl-I^ zkjg7xOV5$AS?V3ELL+IC0fvy*Ik7cGgTWm*o66JZs$6 zMX}D37@UHG#`9bqKtqs*vPb9zgp^vA%AFN(44Cg}qY=KFpHdis;uj1dkP@qOv*ZW$ zcEIrUalI@k7OOHCpO4Y2y9j$;MYx#w@Xa(@`FZNBgSU2M@{xUr2X8} zfSohiH3adJZovevEvypIN|VtBQOXLKc?k6$PL#N1IzKFQswpK^ZC{tg@3 zW;5I2Bbi&6^FKrXLqpbdQ5@$~thzG0ckA`E(C#sz4eD;n4(3g#1YDmsowd;Kx3$Mt zl(`&1PJu<4zeQ?j8YE+0nCzCb*dUAqOJjTUYqN86T-&k3AU^MIQ4PMH8G3nWj|FYi z@?Lzioo_4Hrhed%6W36hXj4D-jY3fP;~-gX54td&WQT7E5b=KzDbxZ1AK)kAgP!TZAx$A|Bvr@BoE zx!dtH2RR_p>d3rlc>a={!91Ijv@a=+=#I1Y!I zsB(bIIjs|`$p3(kYfrtV#=z|%-P4nAS^{VRa)=pj?o!hg3(75^xbAsDGHD zNj*)BGz7iXxY17ChY26`5wY-gV=)Ys4>TQJ1I}koReYUvFh#FZrg5Oboq*I3YHh=R zvmMJoRT>>wKiK1}{?buF7f|05A5@M%xohc4t2%$SzfB{CQynx&R}%lZB<&Mr_s%Db zYf$WZn7$aKK;LcL4ev}tJKx>ZC>_SMqvv-!k4JPZx@^FA!zzm)@T3!sf7DDTE7r#3 zrmK|DFNrkSXS0*%Q(c#PG9(sB^(rrJ%&2pv{;RtH3lbg1g*w1Rupj2k-#1CJnw+F! zREG6YKRRvC!Vi}Qb&s7wCH_sg9GBf+4u$$vb1VJk{7P7}U=Y2*{BYTjj=&xdG{m~;$`{A`CP=wPRA34XfS$Wggb2RfxoV>6|#}YoYx{ulG1a_!W2m1 zLNDIC7lU{+mY77*9tqp_vZ;T=so7$wM6`NWWp+O9SWnF$GK5xEU4ejU=sY1d`s1q= zxvfz(`H}5ct*GH~9gpyq=fCUgPk9>rx!f$Mfz1?1v_994ux$0_A_QI^+jz5Jxl-@6 zAPO~i^g@2Ube9V6*3SY*`0g7jiIT`F6Ylf7&h+u;sq@qE zv!!=KU|+>cK6vXXdp_SoFWyrovj})@60bgRJ8Xh7R*nky7zB`8ql$#s60mkJC)Ce3 zigmDfEYT#G>-@EML3kJpdT8LEAmeQWxN0$Y^U~o`t^()p_0_>*0LqXlF!Q4BmJ2Aq&QfV% z31wj{?T`VmMON$bhu8-Ez_c3{nx%>A^g&`igPlqO2BdHX0c$%rmvh;6I6uiaI4jR< z52!GixTJi1l1vZyVC0j-zaP|1;-IIG56bmP1^2Duc64iac<%9^^w845`}Q*l-0a9E zkW-xOlHv649G!|;cjx93Pt@>Y94%T&$v;OXIS1P=?A6|H_jvptJ@B@N_`87%7Nn|) zs35CNVo@C`hGJdQHJdj`r%%T38gLr!fSxbs)iVu%Jy69lG$SpI&XJ*zwgK~CGXWUvkJ-Jy z?NA)Qcuus+rhXt3ZDCbHHb3f$zIXb`@;1D6 zKUe8{grjSWQLF%eU=NdpYVl3Qtj%4!tvyz4_V-D*`3c*V9sgtLMRB4EBvvDDW@HC)puM1mpc>VCe2O7ly1H*X zSGa9S>zJ=sE){p4q%qv@~BF5LyyE&?PeJt$q7j$f)6{ z!1gwz6VTpA%1O5B2A8~tq_zDGIo9)?`yz8$*ubv<&QB*X?T)B7Dt@{(#ncV9 zM|rrvq6>;ac9yw(D>QrLk`NKTmT)EAggJUpd1{SvpW-9BRK55lq3x-~1P+vcU)5Op z9viK=8VFZpY#wf!k-JNm-y5l$MMrkh7nj|dBz28j-cyUs{+8=x{7|;UUmJ% zQgQ;+TQ8G|C?BvfK}{w8YxUKJ_v@Tk>z9Htf_|W~y?%jC)Ljkj0jQwPLJ}DcS`&W1 zl#DXF_%h{s@bYcvmme$C{NoQPLwvx@)7q%%TtN|#s%U`{{jhfO`^!C=&1#UN5_3Z< z)w5Mcb>5&w_^Zwdb`-oR$G zIukyl0S&2O5$<~q>GtqSwOJkb4U>dgD1MN7t@ zCHT`P3uV+FabNJ@^$za(>tFhmZ~0QX%FakM-xoa9iO*itNDkg!5@c?u#EmwTOf4)FZQ-7DK(SVceFeb+Y49-G!V(!>4zD)@Ry( z>1@U8+#i3sZ#Nma>n_DXgdV$8J8CMpA|^%)SEE)|;5ae>+4^!ZIqPaFqAF=tqy^k7 z{?vbFIIU6TH=^+1LTG44sAovq^DSeUV;jFE!J?mi5kM^$k#Ww-sQa>%BA&{)_W$ed f`2AsJwgsEweUfwFr$5_C3+=MOUcfv;`=F^eql0L5c>71=kV+6n6+xytoDk1q#Kb6n8Bayg0OI@s?8DgG2E`aclA7 z{_^{OdLQ0<>wUN@D|hD3oHa9N=FHyv#As_O6A{u9Vqjnpsj4XIVqjnb(GLXy9{SDl z69QZG52lB%vOGrh7~LQA9~?V54LJ;qxin4mz$vOCugE526Ev0tim!4&p4?8VK2BuT5#9H+(OA{;nDn9@C+vd~Z zH%7EW7zh3UD^|r+ka{CTtD)Nnw-?GzoeV9UwAY0JBGDx@d?4Bn?6zl|s$h7;;9m#! zzelWpCDc5NBC0F`ftPh(!V))}HtNMtN5V5t4IYh-ADhj)o^rEP*t2q1Fmtbk4Hx+f z>G)!2C?|0;sOpKOuM9uJ$WB79kw}WpMyYu8b-iP7C$9uVH zRAJ|OWHVDSe|L}|F)cu})@10KNR?du4`MQUbLH7&YSiC(XFtloqOw%Q-||KMX?O3$ z{g}z80kk#6xIHAb1Hs4LP9_>fTl)1kCQe7p1kt2`{&&RY=}1rjl^=Mj@p8?o5&n+S zQ}W^k(red2IuB7}-SHmW3F>35_?(pKiW&7BV64JkK`mq<2Z)>_Xb_n^gBtrWg7>c2 zZFyzqhe?G!RMp#!-ZLP=(Y=bG?ZYh*ne1gg;ixB;)SQ)#dM~E{d+JAvREZah>b*LR z9#Sr+7IH4Y?a^SOkm99i34A%bW`}Y|>`o0(=qF{q6QFsuqM>I{8c)lCZVZn!_D})g z{K!~uV&DOCmv1XjO<>|Kf9Y9s`rDjQvVWv@=Ji*(g_>u?f zuNqbr;x&M2d`5SH3*!F$;0V3EPi~8svz>kyoAL%a0T%y5R-|1Aee+WZ0DG}IeNG4V zI5FxD{`|jROkj6Le}PJSYHRl_u1q@ z-{_(nV24v6j`C4U7lQPmS7cV>WKsv*WX0p!FEqIAyHqlcpVWIVX>C`pys0~u*qzIC zqd^a(yT*h3q79S;IA8Uw1KKLLhYsRaAL}jtk&K!Qa9SODga<=$6S9MSv>A9 z4`x1P!@(J&mMZ;Ai5_xsFy=-$t5Qr~zaQ$&dy5635EeZ(>$3&K$fIG~KVeK02w8XO zcCP@`@;05}1s_grsalUNlqw)ZNr8hoA!3H{3Ru$%&^aMVvF};C*1nGqRtr3sabV zd==SUQj3c{Jngf@@7E)oU4q_(Oid2?mNX~2DS-s^{>&Jm-X5-aF0|O9g1;mlaDX_p zU4u8}+$>H5aHG|k{qbl{Wmu#V3dsDsWR-Ug@duY40JanG7TJm{rT)gt6i@>e-eMlt zF5{a;x$Pf|``VwhxysoD_E-?=KU8Q!m5(K)lIOkhHKPS_)(>K+b?o~_d8v37lEN}S zD$sskFZ?7zsvrNV9}7`{+?|;EwnM2M$_F}r?k!ay@-n>^lA6FOaQOzh9ngI^GQt+> z@@eP^BIm)Os9tBt2;MpMR}8e9aE<}MTi<(8Pb^hD6akD=>NA3-`=|Zh0yJlq=J^*# z_oC2#b(M4`PMGrGO&r2VypO0}CB)M`{MuS1A+F(D3lAd z_7FN2i-_wZgi={37d2|q&_^neSExcUc~NIggM5UcuwxwTO6`^lA84IvQtQS&{1 z1XWOoqT46v4~!Qtp6iid!^5lJ@)%2X{Z#REU)bCho4jR|BxE7K3o5uxun? z&7HjDxaajUW;TkFx2rR0_GC1K9y{^L4Pn2fY(Gs?Qdv$xJOie@fsi~UA*opMo=QQa z5jHz${_xmWpFlLzQb#y9Udgg(;!Z1>^8((NYBk8JA>Tx&8{5&HNf9UhJ!o#3Ju z5lqGnuCSE19wed*UDC8ZBQ%w4B``a2?cm-FDIz5MVCQ>z8Rp9PH1hHUgb~UD`q}bs zQuCOMb#*o)9+7MWvmWcHRaufNOj}_Ji;$bk#l2)}xJ zXTh7cJtX_d>+b2Dv`qEru9*5-X-#^azeRAAzzMTh<+NE)#$|N?PW!g?KQ_e3O*Hf> zBbWg1F+8uBBJhIzxz9WIz9mc<2Wp=U84(q)iocjF-Zzuv&Yz4mQI9@ zCxJZJpQO6IqRuwLAXYB(3wr3q$_!I%i?a0ta}OXh-OJy1*}%_;xrney({U6au5t<0 zI=CXib~?)aDg4Pg8>`Ix{9(OH1E*4p>1oVMHZJVFV2162=;YIBM+TN9N0RH?oKAws z5yS!2uKzO+;+TJvLj}n!2DvSI;KYKuT`_AJ{%U4{>x1R9U5Lr_)+134HWO%R2Ojq z4v1pe$7;cDdcFIFe>1|Mhh~@AV_f0-pd&iCaPbhkq7&}v&@Xdhdt$Lu6oKoI`)~oh z;|FC1F0KXdJtG08rO*0J5qSf8_rC1ufyd#fZ%3fKd0XJiM9@H9{~vUR1(x{qUDE8N zp>iOw8(^v6>y*A6_T1td-w$O?#x(zcFdOm9yw-TSQ-=QBaV<&qb$5a6j?$Q0OGr{| z&EjYq`*y(aqKsbELx+YWX=s4xd$bN=&Nv1EDCysoOx6l7@WM_8q|pwS4Wu>UkhYZ=4yGwZLw%%Rj} z)AX-ey#UD|?e}rAK=4OZg5rV0(CX8PlLd5yOi!BPsYF!Xj0K3qk2v4RHB_uZ>_taF*X;3R zSqPMAOZll!pM8whNfTW53% zp1+r}Mw{#)&9@%#LStrEnN<)mtQIz=gX;n>JQ^*HoA5ud($1&8;m7-(n|=5q({Q3a zt_>(6XfDS&Kf@^9NEj|xR1(W5mAXDL&@6ziY~(z493O1(_KLSh9;;c8M5dUKL2+B> z3p=-?HXccEU_53}Lh648l-hlKf5^OVWpsf1BatUKYI5zwe5g)#;t%~kc?hh(lzvN^ z3fRB?apo}Aer9;kpd!Lc4^`udzqqzTtn;I#dL<9UOW zWA%XO8r+_Lv2h_WFP+)J-hdGqv36BTGaRt;IZ!_u^8&XV)YH9|d)rrsqafBl7YdeK zBNVjfd;iftcZZ1ul3y^6O+Rig8ap&|3WBSAZH#1;s#hUZIB8SX@3Op-WIa*izzdu9 z9L1$bM~y8Ly8yXZI8=X9VDD~l8jK5P72QJIao@L@5~@H(q=|cG7r%U3lqDD%sF0^4 zO@IfPj;}sF64hvoO6FP3^EqU%+$(_M&@CNV(9j~lq%7r5zYs#sB)W=EiRXjNL z@1@gdZhZPU;h!uXS`#8Vx?c!Sj=SgBKHG*C*R+i%$WTh3a+ z!J|M|D`C!U5zQhi&=|FbW$_P!v4RsYfRellM>j^Ybf%KR62Uas7AzgF$ikISjH`fM z%Rg`!WhB}PS<19qAFc8v6Fcy$=4QnL$BeaQ^O->0iJR!|-y#nE^wO{iO`O89omm9m zd}0R08?rlN28n~jSqB00o|h9yMY%jwL^Fx=(Lg9`hp?bZD*N6sqNMYWPKwiHXfpNH z>)p5P9(!8*J90RO0e$aUe*VDq9%XFPrPS?wsp{z;+kx9t`5v>jeRFpYaY$ruA3D~b z?Qm$j3EQfn)9TMe$B|IUZ7X={V3a)xOFsO^)w0aZ`;F}Ig2#drb$wUR{)F^N(XrWtJ4|`l=yDXqScd=CgK{}Bb zIwlJJOO@aIYIGtcF%v((r+WOtlLprCWQ5Jylk})2r3BrMqr~r8p*T44nbYGtv3E6! zg_5JAvK@WVTnOG9r%0O4X19}W#Rh`+sl5&pdj~x=D=V7YpIeNC^7JEvNx8uS7eHvb z*?4tO!mAq=po5WWe|^ob@(U;?`Dknk+rlJk&k93iso99o?h&iU1_|odqsYoPApwC{ zm3R}CLdq2;fg2}d)rQaCvwIsa>+Rg={iqh4VBtqa3h0>x$Cv^=lbf%j5C>NpwTcRn z#K`ZVK?(7FBJ+d3f+si%TZ$X}OdIa1X(Gj_N@r$IHf854j_M*kTPrvT1-H=K3R^3o* z7aBX2Ib+fk8*WMm^~D$v*0dnY&b@41pIpQ%{r-cfx=V*%;pYSTYm6c2s~Kb1Y>l;K z%t8iIp#M`AQnRb+W8ZSx%r~Xc;0UACq_W&mEP>@ft@d4sF^k`c=mBqpe#g0aRbi)g zH0ZLM)C)k-6y6S++`fg*1x8g}h)e@8ane4O!~);xBcE??FhkjM@`LIy+@D9jbhN|@ z9mi$C&wXQo1(+q4(%9y)Oy&bqs>xfG%3c|Y$x#Yr6-WX3p%WUjc~P8q-Cq&Ttx;t= zweRJSlpuX%gOs_mJ%S@x#t#eav$lACs9%@(gff0aS(Ps9^S3l&HhM_#F@(E+fd!Hs zKfw^mD2rE)Nx7s5i0oG#39Qeyu%5i4%^D9F%1itipwb2+W&UV( z^gX}oUd*Hsze}ZYs)ZelhO>wbxhoxIvP^@9)`sj5^YXu?8O=kqJ?U9JrlcqWw`rT< z<4X@Rbm?DSxuCE{u0ewgk&DPpfARal9dOM1>G^QKty-t6zVSiTxAS^~mac5#lWMc+ zjL7S|uZV+N*i1UXD5%@wRIk3=rF@W8ttF7DbtrY^-!A>JP0#9^zFzRdgY)wmnb} zkKx1^yq2^{w(fgHjT&tb;Na&%BW-AMgOtV9GFLfR;80S3wj}fdLil9lw|!vp$lFV< zFaSKocn?PCa)${}&i4BXyclYw6$@(v*sMn=DmgeAYOmUp6i>*?bgu27#J?HS&?#OR zx5{n*GL6Ao_jG2*&TVeS3V>7EAYlAElf|rK#pld|c;W{iis;Qzk&{VOP!a$9sw#yd zI)iWMc*$mrRp3nwR5a#MQ6Y*og23eF@E%cLx&{h(>s~JX`qOKT>OErzz8D(Dk{mk; ztw@qwAbko2H(j>&^IL4P5RDwPXUtC0-AR>PE?#n=!Bls!vM{mO3&+n$fm<7Q-3)eV z69^$C@T>RXhIq!#YvN^~ALZ;A9h+nN?TF((j|*6-!lp;iFBS~>Vl8s*`v>#fxY?p8sf_QkW@-);lNmU3n8SX`XEQF@ej8(^CA}^+))7Z#p3Z6Qxs^rH+$aNaPde3 zyZ!2ko(P+5TSc$aG;luJ&5X~ck9pS&#Pdbo27NU1&Yvor2tRh|QW^Qon9{s$>TVhm z&-sPJW^5p42)dLmpnq3N9e4@xf7dS+!DO}Ra4TE&{Oxa*>E@T{nbFiX)!2?~`I%3L zhmObIkkNR^42_>Qw-sGL=wN;zV@wjhMLvR!5S)HZ;zeToxWfb&cE|BzGgN`Kwa1^x zPpsQ!y};?QkZ`yvt9lq*AsYyO_* z_{bBtJ+TKfeUv~Lhr6IE4>gL8)^zain5!V?l1-Y;VCKg?Rr7uGD@aZ01;ia|MGsY} zEhZKefYprS%QsBBNxa@1#e*pc-2ZtMn_ErtY3`w!m zDW$Q(cFI{ukYC>?l!YoM#rPy7&v?nwKua3a<7pU^c51XI8DRajMqMrNx@e*f3-s}Q zcBx~()ubA4{AvF=IX7E{rD9PDjK&?Pd-T;#lsj3gRzq&jL?1;uGFXNNc3ZW$71DR5 zfl+e2c`qmaXL%Yno`*a!On@#%{ zJ03rLKf{&pSjHP%bF?FYUCdu~c)xGBPg+&s_Q;VYY}!*XgqOOL(G0sVZ#43VwRc3z z$H@$AeH6=y7L=NYsFXC6^Y@?Gnf2%2Gd%xJp%%kzx(Vaci=+#qBByNNkHdvuV_B&V zI75AwYJkStx{jAR`WpI?>S*Mhx4F!R6!1OEZb{x6G0n=psZy4!)St4qMdZ$XH}HY* zTvCaNwqZGcBcVY^b}zF@RizVACz{uz*e3Qmsc*kCf9ufIxXXft7O;??tT9mcc-FlV z+LfUpHB9kvX-h=++)TMhD3TMd(G?xDl--(`KXClI3h1q&to%pl0y>egDx?dcs+4C4 zjtXg|u%HFg5JQ9Bwj?UC#90{xmv4BLB0(P=X5Grr8$BKS%P!fiT(4#`dkX4m1fDx9 zaQvE+M;T8{V6C}UnFW^r2}u0(iSiYS(O)x(a%t+=XJ1Nwd;8JaWy8&Om^40nWD_E| zH_~O2|=@6H-9yziOw9{(qy)LzR$%ZE!yZ`XvUzw(+I@aF} zBPnF%a~T&Z87iJIY`A0R6Y4Vgyri$4J!>e}n}nB>s5hH9&m=^iZ%wd9MD9@Bm4YI; zK<+A@crm}ShLW)C3+uivlls@)wm>hT$Mmsuzdn<6>q#LM9rCs<&@1HEQ3$SGIo9OS zTX3aqE)+rFtsR!3vpt#BCRPHuh19+XHjQXp4YG;ff-t{7#3%bow^Bst5ZWFei$jwu zZ#L+-gHkmxF72@MF`nLW;1s4U89GJ6F?cl{S3VQcgpQrW;$@KtNueVZNERVp6pj}_ z53IyQ@rfmdn}ZuW%!@oK-!Q^+?IT+{PkcKi)f1bUAl==nBVGHgQ3~-}85Jg5v(J@m zlf{-YT9p3?x&;S*o@^05jPc$XhmGcPwDXNxIr4!XFw#1zG%0^#$dmtONwAtpphwu& zv-~jg5O5k44wC+0qW&M0Q$|-B&l{U*Eq!fGCMfL$P!nf5D+dj)_{BmuX~q*%dYOJX zj^Kr}8%<~EyRAb9UY$c(sU=q{ee z4=#mjwCU04;wTJ||MW@|#AS#~6qmxh@!@7(&tbFIe)GCyz8QEV?+1DSBOTd#Qr_!p zGvP^JrE-@L03y7Op9GSfvq1o!Lo!L6sK0vmpvhBV}1Ht(QKgf*HPdT}RTTSw8|=)BjD;mr7kp2#UlL=5 zKGE6;8FLyT&U24}_F`P>L`!urKfWC{$^<`ws)@9f5ISIxVDG6#Ub4VHbYJA7?vkH` zXrBw|yxTB`0;Wm*H=j9XU&`3FfF{^+75F{Nn-ir` zuOAnB=8NMA8(&NUR>(rAfGomFEU92jcTr(RhpTm_D1Bt~XX?(X5uKMP(R*65W2k!q zQ^;l)w35cp*X_hoT{n{fuR9uzE1tjLQizoW)%w^~{TbgKp1;S4$nQw6O8>h5)|EFg z#yl6zTAf3(_${^83_D;3)ZX-o%w#X%s27wa8L#-1HOYE*@UEr))qRlVh3L2Mkml!8 z*&cKD&9J@>jE?WK9C^zLrF-{*D6SbC%`z{&-+}Q!6%Ra@5ACg83`|~zFmdB5vgc7_ zX0+PiXH|BnuMMmyuXUKiwj1(UJ@(powN0$ZJBA-?Ag?az0Ki<*K%=X#q?y)-?#bCsV`73bXo z8tw7(nLTy|4@6NJwcu zadvjH(82rc9-6!Lp$3_M+ytk4pFMK!!`%aMJsr8`q#=LaxF`Ao-+57U`=NuhZ*dxr zM^{;W`=eWhC&!kGS`famQNJ|ZS!1Hu$Bi|Tc-Dm9k^*+ldE)tY^p-^D-y*;WgYe0d&cgGk9RUITyn&1J@G4Ee4(rIGLP@pX1Q z#fhCzjQFH4Z8I0W7&tatO)9BG9|?BdLTOUq;%7@dTh>f1%%>r-Vs8W@(Bz5rV8?Jt zM=6uxb7v06$9yq$-^{A9-vYg%GI3H*>Q==G!Q}5|dXartoi;RI(ZNAGDi078rI;C@ zILW64t>qej=%|pFyt?hpw#XwfqAP!Edck$Kfl1=rtJvJ$pJ9y&vCVk~?y~whcvbV| zq7Kdp1`#_$%6wYS$^B2_1$ekTx0}R(tKVOki}pSRNGtb$*Zv1Y!k|KK)$ z6TRvS0?`NCB?GIk`tKaSLpxs5=wg5YQKGOOW?L0BJ0fvpvynAKioFkMKgfuYfc9{p zmTozXC9VPnW!3X5arI+5vom|flfC?r&`pr1?(A4vUg1&5+!KCmF-_Lv=jh{0+VxSF zp1zZCVu6ueKwQo?0j~$KORh>yOcHO*C@t1!DRc}qvE=X={er0T3;G#N6zOhiv2}IX zf_QtM{M+{<(0}|Ld89jD&_MeO;@=F7`8(JIo}=nivO!Hl3UC>us>=??!@U&R$wWD% zbJql`F#2YFPPjdAnq{5vVxH18E)gIrM2RiWT)atwcsEsg;t=hw^bw35@gp2H>ls+KS_zw1X>dYV zy%-@!SH6yJPhLOeose8UjwE%-@GwRD^;$w?dO)uEzLhCe4o=f7dIruJ);9=@vFSPd z=muSjQmj6?O!4qqk8>%slU9Aj^a!22UjF_w@URC{Ey(hN(R-`Nsqsky0edrfYxU3x zoTI@Pj{3b*Mi;`+^q??;SKS^`g#&P_p%?h}%$sMIzY)&ObIH$^OT!*cthx$d?T49+ zCAd8f)|_~L)CPNa`YPC->FkSr+^H-gjO$ai;cY}z38#Vmg+u3bixz5nQaw~@PO>|+ z>kqA+BJZ>Wv-X@frk1`qU57vBSzd^#QjY9@p&MX0Nb@z}`e=!@eI$@c9V~|VXPZ`b zINrQ#0;?B`ycyC0$ynXydZuc<#0}N#$djOq3g#wp0ymTu~QT~%0$;8Ln|J+!LENur|P;XQ(TVG@T`}7$qqqG6)I)z}c ziymA{t!%!bb*>1C$R{CFxxSgiUi9{{5x!H#hj_epNv!?abwT*`U7lue{15C#4fNr@0`qvj6Q z{veYPpJm9Y0KM`r5iH3ebWcFx5i14S=Noc#+0Vtieteri0T2CSh0z#$`-mzWbR0^; z=p9;0$%V#|fwlTT#80J%(&i#QO=8$wZj7r+z7oP}=kNafuF&KMT(Kkoz5ne}wXuaF z;ldReXX5$jJ`KbvKT zk{7FoNVX3;B z{vH=31$?(dqyCJlSHA1yoqAnoRJw3d-R|i!834mv%hs^Y$u7bA%5!hrR+Drb@-DP$ z)~lkxjXWrdwHYtQC&{mneSo~t9aFO6Fsy@mOr8GHbccWRyAA ztVJp0T!hPl#ck39b$RV2AK|db9R)hYyYb96L^dCk4y}Smq;D@B%?1WSL#QB8U*I}y zG*io^gbY}PDrnqm@o^w9kDxW7aKbaWr&MBa>2BpG@`P@_;p+~mAI)u=+y>PH`qKW1 z`uKU$!XSW!d6Kg(DL1#rM?FsYS7=vI@hv2)W<_nY81%{*v5u-Am`!ET%!xSdr3Nv}6Vu7;!6j5;}Va?mw6s zD=gIux43f1_owPln-GV0mbS;@ynk8Pb$2y;YLH1SGG+6x`vCV}G1PkJiO21;yYIs-BF+ej0pEOWyv_^|vH?qU4}ga!at5HezL> z5QRi^G^WeEM7zhqnc{emC4N&$&A%zn&#z8LB~k+<+y$}cXNnQ?#djh)-&DkI8a6#X zb#b&MsD&zLrrwu~ug;x3i?qN_o|`#E*=#yAzC|SrsATalyTdPR0txafGxO8rV`ThK>gq;2L-(Hu*8Tq~ zg8lz1sA1z`jeIW5P@G?h?-X7#$tnwgX|BBzn{YVF?MlzSz*S<&e98J+)lcI?yrP6Jo{TEPc<@G}maDBv#quVG zdvTFD^j7Q}r3&N2@4GeyyOpkv4wHqV&TGe@u#vA#NZh(;Z8N3*{b5!0A4W7ep*8g0 zA9}te`sZ%3&#Htkeeb4fuh;n-VBCpi)pqg{dI{T7RJsYyMneNP%ul2(Bjjt*@W~u1 z+hzEJUzLK^V4G30==__$y1Yc93pb}?@fXVUA5m{iM!%eC4K7{cpNF`0S}-YFY+g#e zj>DDhI}q!BeBkhA^B{Cgs&c+?g^~d}DM{DyLq7Du`LpozC5?G801c8_Wwn~2I0G$= zYeRJBO>0C#9rD}XZui~4F^#UR+3CxLIQ|OAtm+x(RInm7>ynK)c>C?uj4k%kQjb=p zJl%2L?3_NB&>w%l^w&3Ynw(%MoaEkTYItOey^Es^xAoqK`VpL~pR7c#^e((d+14zi zFCEeKqhYr%t}`jG+UBzhW%@PUt`_aXlMu}|rT!)4UoM&nI5Gc6mr&c`kiNR^!IMtP z1r&Hef@L3blTZ=n4eEXpO zzCUWcE2Sl| z@qdm!O$@o{>{dx|dS2w-UH!HiKwoc9U)+jrP!aMyNTOHZT7JrCv#T70EbrDVDH1IM z?MRQP3$>UI!KKB9(@*RK&7>ja1_|p3!*<4~p%86f|VXrH~iQ6R(qH-oYk* zBR(lhJr_XyNs|oYT-0;0*z9_DG1%0}x8YO_`q~m4^hg>oFzA18Al>u~-N%DS|Ia)}>eiMu0W5*TkNQzE>s*7nz$sxa+hNjhf zP)Zpg^BUmU(XaI{Yk|;@hKsiR(0Ps7i(53WZ1;!Ibl1O^05j6pZEDzNLb@c0Qy_+J zQdU-=Y3;ZH;e37c%2G>_*5#ZCmh%QnpbSm)7x9;E#36WFV&Xjxll?mJGwC~32?z^2??b+GOg)dH2b-ZRW(GdlR3!DcdAr9 zEsYT1Ge_gMjQb%&$;s~&_A!}O8DPvmoqR=~3vXK}Sx=L-NBxv~d+oGEVOG~SPj`uA zqGG&df7o}o)xH{<8S86KJoN)7nq8Y z?)*AJm7kY(KK2{k^}Tx3kpA=b^D&PIsTZSOBFkefi%D!=@iUw%qpOtS|D= zxeNj)Z&~|u_zpNir1NLJC@k)ehLV`Kh|m&q-X|krPe{?2v}^)SJl&6|P1^VeZ+%cC zMf~k%N6etCNY-A5vcVK!h%|yCKFF%;yDW`AF(8=_w3iAdB*3GxnekJE{KQVmsG~CeL24&A_b(JNsiRifGC7`R65;bt1pd z*b=`CL}#;~wpTlh`fpuk=ppSTdln`}z~~idtl?%L%Ufah52+XmUttxn0zXyi5hu#U zXwbcsf}siS-a;}zs<5`d5g;c2p5Cu~kE3~Ae7v-(tzSHQpBBxup*i^=eKdRX=bmyy z4-AOqRuSUWiQt@A(KoS4q$0wzKU#>?;kf0#x$>=BFTv<*?7+$_*D<|29i zY4emb*os-($S=Lu(_prdTp<;nN)y23FgeIO8Y$^z zSjis)#AuMq)j*vywD$gx7#)bbilmSoIGXlBcI|X$z=hDV!Q*X4GWtcFFm)?V_6}st zLCgLn1wohA5p_7i}u-oo$8IZ+H0#-ieu9ckJFpp1mZW31_ z=iQJYTF$f2Em!yYLj@|Vpkr3{jxfa;is!Dj@|qupp0IKcEY?UoX$=h_p4AFB$mB0} zMn{0p8KV{=VGYxc^<_?1k}QfvnF={rFYlgdU=rdznt2j1r_rvz;T=lZMmcoaY_iA9 zPvh_z#|JVppuY%Bbu*Jl>5YyV+Qz~*hmw?keH5^b4(-U#JR^o~`;R=g(d^51(H&9b zXA{2YE$-j?AGB7bgoO8G2SVq|28iMd-+}7hW+(DR!cmh zqlJM9oh7mFF0{M*@xlW7+FzE2f;9e|7c}aIW7FkTr~K?6(ROgHcBUW0w+NOMRMpy) z==2S1R9-`xz!i?4kuX-u*MQk8I9YiqPO@A@#V34WKf3_#}eXdm8@dt znC(knkJ}v*q5APi2d{?Ii+I8z<20c~C3>6md%O96TAVVdXxz*q?V0P<%g)_tdGKa7ojJpoI|pnvWYsP3R3JDRj!7T#2jTkA92Q0+Z(woowmTI zPj#tQ?Ts|UHJAG-717x_16daxTr@9CgmB!gT~$&C%8x9V=X3My*Xox1Mw?QtK$$Mu zO~HyYh+E&1tyGdLt8OZB5G^ECD4%08~`3oLeV)v{(@0oHQb8MAbDPV%jmv=k@b$C`I+=O4Q zBA3F*2c7Fg$|PT}UD-)XcMn7z*lb7b+w{wnZ-o6_-SMa{n)q2$PQri}iKgw_Oay7G zK_~1gg>R$t{(T5cCwDXRo#xLeHri}mVF4UJ!~3CU1yZ8C@I0#O;D7Xs_wITbgL~Lu z=9ImK9m<%ZxNQuKG7Z#;Q?eDqaOR)o?X7~FsoGSBj*z?8O{?gG@Fc5u%lAkVw?Sf( z7}6ZYzo+O9&(!h6l{_%RWe%&Ic{xvdh2iJ`?@GRZ@q+Ob`s-V{eERC^?$5#keNR@p zx;{Q>c)BrK)!Pc#M}0jFlxPuUf9ExzGEP!kQ2jca8`$%b0dKpl_m?dL&@-v|)~dP1 zub-1dhaD(R#WD=)Y_0%R5_YlA2Y`$M7VfwQzPnwd%37}^@4rrv#oeINzc>piGtkXG zW<38j@n>E6I)`L4Nwhud(JbBG#}n|d>_k)Ys4GB zB~q`gr5(9Sc9)fBq;xYfv-E=_ZUgx=J5D>PrcT6-1mvZr`-llj`*%GKOAvDkza$@vW;R>{$M zIDkZ9dak1{$qKH5TD}}HPROeg0C&KaVzcvR$y;J1cuskQ)#i`k`Vk=ZAv0U_+?zh+J`qTA}W1kz|n_KelnVzXHmeqz!u8JyYd7V-OM3#QqY z&Pz_u{sZq9+=#4Le4N+4I1|2~o(DGf0oLxB1{g7M%#W1Bv86Vu#bVXIBExtje& z4#Rr~)3DE#kvxc~1jD8M(5u7%H@68y>7L}wRcs48hHR?EXf{}<5^eK7z4 diff --git a/app/src/main/res/drawable/logo2.png b/app/src/main/res/drawable/logo2.png index 46a485e9b19276511c0512c77ce1ad9e1d1defc2..33ce68a9adf3b8707a686bc837caaf73ab480e34 100644 GIT binary patch literal 9077 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 nu#;9%00000NkvXXu0mjfhA5V$ literal 18602 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 f`2AsJwgsEweUfwFr$5_C3+=MOUcfv;`= + + + + diff --git a/app/src/main/res/drawable/medium_battery.xml b/app/src/main/res/drawable/medium_battery.xml new file mode 100644 index 00000000..9d110634 --- /dev/null +++ b/app/src/main/res/drawable/medium_battery.xml @@ -0,0 +1,13 @@ + + + From b291e7c4b73f2a221521a0dc62f7f02c8711dd9e Mon Sep 17 00:00:00 2001 From: dlawlstn1616 Date: Thu, 7 Nov 2024 15:01:53 +0900 Subject: [PATCH 15/16] feat: QRScanningScreen UI fin --- .../mhnfe/ui/screens/qr/QRScanningScreen.kt | 204 ++++++++++++++++++ .../ui/screens/qr/QRScanningViewModel.kt | 29 +++ 2 files changed, 233 insertions(+) create mode 100644 app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningScreen.kt create mode 100644 app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningViewModel.kt diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningScreen.kt new file mode 100644 index 00000000..ed8dc3ed --- /dev/null +++ b/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningScreen.kt @@ -0,0 +1,204 @@ +package com.example.mhnfe.ui.screens.qr + +import android.annotation.SuppressLint +import androidx.activity.ComponentActivity +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageProxy +import androidx.camera.core.Preview as CameraPreview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.viewinterop.AndroidView +import androidx.compose.ui.zIndex +import androidx.core.content.ContextCompat +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.example.mhnfe.ui.components.SubTopBar +import com.example.mhnfe.ui.theme.Typography +import com.example.mhnfe.ui.theme.mainBlack +import com.example.mhnfe.ui.theme.mainGray +import com.example.mhnfe.ui.theme.mainGray2 +import com.example.mhnfe.ui.theme.mainRed +import com.google.zxing.* +import com.google.zxing.common.HybridBinarizer +import java.util.EnumMap + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Composable +fun QRScanningScreen( + modifier: Modifier = Modifier, + navController: NavController, + viewModel: QRScanningViewModel = viewModel() +) { + val context = LocalContext.current + val scanner = MultiFormatReader().apply { + val hints: MutableMap = EnumMap(DecodeHintType::class.java) + hints[DecodeHintType.POSSIBLE_FORMATS] = listOf(BarcodeFormat.QR_CODE) + setHints(hints) + } + + var isScanning by remember { mutableStateOf(true) } // 스캔 상태 변수 추가 + Scaffold( + topBar = { + SubTopBar( + text = "QR 촬영", + onBack = { + navController.popBackStack() + } + ) + } + ) {innerPadding -> + BoxWithConstraints( + modifier = modifier + .padding(innerPadding) + .fillMaxSize() + ) { + val screenWidth = maxWidth + val scanBoxSize = screenWidth * 0.6f // adjust the size of the scanning area here + + AndroidView( + factory = { ctx -> + val previewView = PreviewView(ctx) + val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx) + cameraProviderFuture.addListener({ + val cameraProvider = cameraProviderFuture.get() + val preview = CameraPreview.Builder().build().also { + it.setSurfaceProvider(previewView.surfaceProvider) + } + val imageAnalysis = ImageAnalysis.Builder().build().also { + it.setAnalyzer(ContextCompat.getMainExecutor(ctx)) { imageProxy -> + if (isScanning) { // 스캔이 가능할 때만 실행 + val result = scanQRCode(imageProxy, scanner) + imageProxy.close() + if (result != null) { + println("QR Code found: ${result.text}") + // QR 코드 인식 성공 시 ViewModel 호출 + viewModel.onQRCodeScanned(result.text) + // 화면 전환 + //navController.navigate("") + isScanning = false // 스캔 중지 + } else { + imageProxy.close() + } + } else { + imageProxy.close() // 스캔이 멈췄을 경우 이미지 프록시 닫기 + } + } + } + + try { + cameraProvider.unbindAll() + cameraProvider.bindToLifecycle( + context as ComponentActivity, + CameraSelector.DEFAULT_BACK_CAMERA, + preview, + imageAnalysis + ) + } catch (exc: Exception) { + // Handle exceptions + } + }, ContextCompat.getMainExecutor(ctx)) + previewView + }, + modifier = modifier.fillMaxSize() + ) + + Text( + modifier = modifier + .align(Alignment.TopCenter) + .padding(top = 200.dp) // 상단에 여백을 주어 텍스트가 화면 위에 표시되도록 + .zIndex(1f), // 텍스트가 다른 요소들 위로 오도록 설정 + text = "기기에서 QR 촬영을 완료해 주세요.", + color = mainBlack, + style = Typography.bodyMedium, + ) + + Box( + modifier = modifier + .matchParentSize() + .background(mainGray2.copy(alpha = 0.6f)) + ) + + // Scanning area box with a clear cutout + Box( + modifier = modifier + .size(scanBoxSize) + .align(Alignment.Center) + .drawBehind { + // Draw a rounded clear rectangle to create a cutout effect + drawRoundRect( + color = Color.Transparent, + topLeft = Offset(0f, 0f), + size = Size(size.width, size.height), + cornerRadius = CornerRadius(x = 12.dp.toPx(), y = 12.dp.toPx()), + blendMode = BlendMode.Clear + ) + } + .border(2.dp, MaterialTheme.colorScheme.onPrimary, RoundedCornerShape(12.dp)) + ) + } + } +} + +private fun scanQRCode(imageProxy: ImageProxy, scanner: MultiFormatReader): Result? { + val data = imageProxy.planes[0].buffer.let { buffer -> + val data = ByteArray(buffer.capacity()) + buffer.get(data) + buffer.clear() + data + } + val source = PlanarYUVLuminanceSource( + data, + imageProxy.width, + imageProxy.height, + 0, + 0, + imageProxy.width, + imageProxy.height, + false + ) + val binaryBitmap = BinaryBitmap(HybridBinarizer(source)) + return try { + scanner.decodeWithState(binaryBitmap) + } catch (e: Exception) { + null // QR Code not found + } +} + +//@Preview(showBackground = true) +//@Composable +//private fun QRScanningScreenPreview() { +// val navController = rememberNavController() // Navigation Controller 미리보기용 +// val viewModel = remember { QRScanningViewModel() } // ViewModel 미리보기용 +// +// QRScanningScreen( +// modifier = Modifier.fillMaxSize(), +// navController = navController, +// viewModel = viewModel +// ) +//} \ No newline at end of file diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningViewModel.kt b/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningViewModel.kt new file mode 100644 index 00000000..c65711d9 --- /dev/null +++ b/app/src/main/java/com/example/mhnfe/ui/screens/qr/QRScanningViewModel.kt @@ -0,0 +1,29 @@ +package com.example.mhnfe.ui.screens.qr + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch + +class QRScanningViewModel : ViewModel() { + private var _qrCodeResult: String? = null + val qrCodeResult: String? + get() = _qrCodeResult + + private var _showMessage: String? = null + val showMessage: String? + get() = _showMessage + + fun onQRCodeScanned(result: String) { + // QR 코드가 스캔되었을 때 호출되는 메소드 + _qrCodeResult = result + _showMessage = "QR 코드가 인식되었습니다: $result" // 메시지 설정 + + // 필요한 추가 작업 수행 + } + + fun resetQRCodeResult() { + // QR 코드 결과를 초기화하는 메소드 + _qrCodeResult = null + _showMessage = null // 메시지 초기화 + } +} \ No newline at end of file From 3980180f781a194fe7326f27a790054fc52257bf Mon Sep 17 00:00:00 2001 From: ywonchae1 Date: Thu, 7 Nov 2024 15:55:07 +0900 Subject: [PATCH 16/16] =?UTF-8?q?fix:=20Jira=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/1-test-issue-form.yml | 9 -- .../ISSUE_TEMPLATE/2-feature-issue-form.yml | 9 -- .github/ISSUE_TEMPLATE/3-fix-issue-form.yml | 9 -- .../ISSUE_TEMPLATE/4-refactor-issue-form.yml | 9 -- .github/workflows/close-jira-issue.yml | 72 ------------ .github/workflows/create-jira-issue.yml | 108 ------------------ 6 files changed, 216 deletions(-) delete mode 100644 .github/workflows/close-jira-issue.yml delete mode 100644 .github/workflows/create-jira-issue.yml diff --git a/.github/ISSUE_TEMPLATE/1-test-issue-form.yml b/.github/ISSUE_TEMPLATE/1-test-issue-form.yml index 7c5b5282..fc895f11 100644 --- a/.github/ISSUE_TEMPLATE/1-test-issue-form.yml +++ b/.github/ISSUE_TEMPLATE/1-test-issue-form.yml @@ -5,15 +5,6 @@ title: '⚙️ 이슈 제목' assignees: - octocat body: - - type: input - id: parentKey - attributes: - label: '🎫 Parent Ticket Number' - description: '상위 작업의 Ticket Number를 기입해주세요' - placeholder: 'KAN-24' - validations: - required: true - - type: textarea id: description attributes: diff --git a/.github/ISSUE_TEMPLATE/2-feature-issue-form.yml b/.github/ISSUE_TEMPLATE/2-feature-issue-form.yml index 3ab544a3..4c5c473e 100644 --- a/.github/ISSUE_TEMPLATE/2-feature-issue-form.yml +++ b/.github/ISSUE_TEMPLATE/2-feature-issue-form.yml @@ -5,15 +5,6 @@ title: '🐶 이슈 제목' assignees: - octocat body: - - type: input - id: parentKey - attributes: - label: '🎫 Parent Ticket Number' - description: '상위 작업의 Ticket Number를 기입해주세요' - placeholder: 'KAN-24' - validations: - required: true - - type: textarea id: description attributes: diff --git a/.github/ISSUE_TEMPLATE/3-fix-issue-form.yml b/.github/ISSUE_TEMPLATE/3-fix-issue-form.yml index 29f65c63..f01a9494 100644 --- a/.github/ISSUE_TEMPLATE/3-fix-issue-form.yml +++ b/.github/ISSUE_TEMPLATE/3-fix-issue-form.yml @@ -5,15 +5,6 @@ title: '🍎 이슈 제목' assignees: - octocat body: - - type: input - id: parentKey - attributes: - label: '🎫 Parent Ticket Number' - description: '상위 작업의 Ticket Number를 기입해주세요' - placeholder: 'KAN-24' - validations: - required: true - - type: textarea id: description attributes: diff --git a/.github/ISSUE_TEMPLATE/4-refactor-issue-form.yml b/.github/ISSUE_TEMPLATE/4-refactor-issue-form.yml index e54cea20..7004ce3b 100644 --- a/.github/ISSUE_TEMPLATE/4-refactor-issue-form.yml +++ b/.github/ISSUE_TEMPLATE/4-refactor-issue-form.yml @@ -5,15 +5,6 @@ title: '🚧 이슈 제목' assignees: - octocat body: - - type: input - id: parentKey - attributes: - label: '🎫 Parent Ticket Number' - description: '상위 작업의 Ticket Number를 기입해주세요' - placeholder: 'KAN-24' - validations: - required: true - - type: textarea id: description attributes: diff --git a/.github/workflows/close-jira-issue.yml b/.github/workflows/close-jira-issue.yml deleted file mode 100644 index fcfb3d45..00000000 --- a/.github/workflows/close-jira-issue.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Jira 이슈 닫기 -on: - issues: - types: - - closed - -jobs: - close-jira-issue: - permissions: write-all - - name: Jira 이슈 닫기 - runs-on: ubuntu-latest - steps: - - name: 원채 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'ywonchae1' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_WONCHAE_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_WONCHAE_USER_EMAIL }} - - - name: 유진 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'sseoU' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_YOUJIN_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_YOUJIN_USER_EMAIL }} - - - name: 민정 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'Kwahk' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_MINJEONG_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_MINJEONG_USER_EMAIL }} - - - name: 승연 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'kimmatches' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_SEUNGYEON_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_SEUNGYEON_USER_EMAIL }} - - - name: 찬일 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == '0114chan' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_CHANIL_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_CHANIL_USER_EMAIL }} - - - name: 진수 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'dlawlstn1616' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_JINSOO_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_JINSOO_USER_EMAIL }} - - - name: Jira 이슈 키 찾기 - id: issue-key - uses: atlassian/gajira-find-issue-key@master - with: - string: ${{ github.event.issue.title }} - - - name: Jira 이슈 완료로 이동 - uses: atlassian/gajira-transition@v3 - with: - issue: ${{ steps.issue-key.outputs.issue }} - transitionId: 31 \ No newline at end of file diff --git a/.github/workflows/create-jira-issue.yml b/.github/workflows/create-jira-issue.yml deleted file mode 100644 index 948b50ab..00000000 --- a/.github/workflows/create-jira-issue.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: Jira 이슈 생성 -on: - issues: - types: - - opened - -jobs: - create-jira-issue: - permissions: write-all - - name: Jira 이슈 생성 - runs-on: ubuntu-latest - steps: - - name: 이슈 담당자 자동 할당 - uses: pozil/auto-assign-issue@v2 - with: - assignees: ${{ github.actor }} - - - name: 원채 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'ywonchae1' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_WONCHAE_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_WONCHAE_USER_EMAIL }} - - - name: 유진 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'sseoU' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_YOUJIN_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_YOUJIN_USER_EMAIL }} - - - name: 민정 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'Kwahk' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_MINJEONG_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_MINJEONG_USER_EMAIL }} - - - name: 승연 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'kimmatches' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_SEUNGYEON_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_SEUNGYEON_USER_EMAIL }} - - - name: 찬일 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == '0114chan' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_CHANIL_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_CHANIL_USER_EMAIL }} - - - name: 진수 Jira 로그인 - uses: atlassian/gajira-login@v3 - if: github.actor == 'dlawlstn1616' - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_JINSOO_API_TOKEN }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_JINSOO_USER_EMAIL }} - - - name: Main 브랜치 체크아웃 - uses: actions/checkout@v4 - with: - ref: main - - - name: Issue Parser - uses: stefanbuck/github-issue-praser@v3 - id: issue-parser - with: - template-path: '.github/ISSUE_TEMPLATE/2-feature-issue-form.yml' - - - name: 이슈 Markdown 문법을 Jira 문법으로 변환 - uses: peter-evans/jira2md@v1 - id: md2jira - with: - input-text: | - ### Github Issue Link - - ${{ github.event.issue.html_url }} - - ${{ github.event.issue.body }} - mode: md2jira - - - name: Jira에 이슈 생성 - id: create - uses: atlassian/gajira-create@v3 - with: - project: KAN - issuetype: Task - summary: "${{ github.event.issue.title }}" - description: "${{ steps.md2jira.outputs.output-text }}" - fields: | - { - "parent": { - "key": "${{ steps.issue-parser.outputs.issueparser_parentKey }}" - } - } - - - name: 이슈 제목 수정 - uses: actions-cool/issues-helper@v3 - with: - actions: "update-issue" - title: "${{ steps.create.outputs.issue }} ${{ github.event.issue.title }}" \ No newline at end of file