2026/03/04

오늘의 이야기

아무런 준비도 없이 그저 떠나고 싶다는 생각이 들었던 점심 무렵 길을 나섰다.


호남고속도로 (운전중에는 사진을 활영하지 맙시다. 액티브 크루즈의 도움이 없다면 불가능.)



 


 


가고 싶었던 섬... 신안을 향해 무작정 아무 생각도 없이 오래 걸리기는 했다. 3시가 넘은 시간이 되어서야 경우 도착할 수 있었으니 말이다. 예전에는 섬이었던 신안군도 였을 것인데, 언젠가 다리로 연결되었다는 기사를 보았던 적이 있다. 다리가 너무 길어서 바람이 불면 흔들린다는 기사까지.


천사대교 가기전에



 


길어봐야 다리가 얼마나 ?  그건 안 이기는 했다. 구간단속 60km 라 더더 길게 느껴지는 다리를 건너는 것이 새롭기도 했고...


천사대교를 지나며 (구간단속60km 구간이라 크루즈의 도움을 받아 찍음)


무한의 다리


무한의 다리 (할미섬까지 연결되는 다리)



무한의 다리라고는 하나, 결국은 돌아오게 되는 걸... 돌아올 것을 왜 가는 가? 라고 묻는다면, 뭐 그래도 바다 위를 걸어 볼 수 있으니까?


 


 


등대라던데 (해질 무렵에 가면 좋을 것 같기는 하나, 숲속이라)



 


천사 대교 석양에 걸리다.



 


다시 천사 대교를 건너 돌아와 석양이 비치는 곳에서 한 컷... 이렇게 첫날을 마무리해 본다.  하루 종일 미친 듯이 운전을 하고 오기는 했는데, 왜 그랬을까 싶기도 하고. 그냥 마음 한편을 추스를 시간이 필요해 보여서, 이제 한 달 한 달이 어떻게 나에게 다가설까 궁금하기도 하고...  성인이 되고, 결혼을 하고 나서 나 혼자 길을 나서본 건 이번이 처음이고, 마지막일 될까 싶다.  


 


지금은 어느 선착장에 차을 세우고 이 밤을 지새울 준비를 해 보고 있다. 사실은 밤하늘의 별들을 보고 싶었는 데,  이 선착장은 가로등 불이 환해서 그건 좀 어렵지 않을까 하는 생각이 든다. 


 


오늘도 잘 살았으니, 파이팅, 좋은 일만 올 거다.   





오늘의 이야기


#스하리1000명프로젝트

스치니들!
내가 만든 이 앱은, 내 폰에 오는 알림 중에서 중요한 키워드가 있는 경우
등록해둔 친구에게 자동으로 전달해주는 앱이야 📲

예를 들어, 카드 결제 알림을 와이프나 자녀에게 보내주거나
이번 달 지출을 달력처럼 확인할 수도 있어!

앱을 함께 쓰려면 친구도 설치 & 로그인해줘야 해.
그래야 친구 목록에서 서로 선택할 수 있으니까~
서로 써보고 불편한 점 있으면 알려줘 🙏

👉 https://play.google.com/store/apps/details?id=com.nari.notify2kakao





오늘의 이야기

앱을 만들다가 이미지 활용을 위한 방법을 찾아보는 기회가 생겼다. 며칠간의 고민 끝에 방법이 정리가 되어 간다.


먼저 카메라에서 이미지 가져오기는 다음 링크를 참고 했음을 밝힌다.


 


https://sungbin.land/jetpack-compose-%EA%B0%A4%EB%9F%AC%EB%A6%AC-%EC%B9%B4%EB%A9%94%EB%9D%BC-%EC%97%90%EC%84%9C-%EC%82%AC%EC%A7%84-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0-cf517eaca8bd



 


Jetpack Compose 갤러리/카메라 에서 사진 가져오기


rememberLauncherForActivityResult


sungbin.land




 


다만, 가이드에서 말하는 cameraX을 활용하고 싶지는 않고, 기본 카메라 앱을 호출해서 촬영하고 그 결과 이미지만 받아오는 형태로 만들어 보고 싶었다.  그래서 이런저런 내용을 찾아보다가 저 글을 찾게 된 것이다. 감사하게도


 


결과를 이용하는 방식은 아래 코드와 같다. 다름이 있다면, 갤러리에서 이미지를 가져오는 형식은 uri 가 결과가 오고, 카메라의 결과는 bitmap으로 온다는 차이만 있음 다름이다.


// 갤러리에서 사진 가져오기
val launcher = rememberLauncherForActivityResult(contract =
ActivityResultContracts.GetContent()) { uri: Uri? ->
imageUri = uri
}
// 카메라로 사진 찍어서 가져오기
val takePhotoFromCameraLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.TakePicturePreview()) { takenPhoto ->
if (takenPhoto != null) {
val baos = ByteArrayOutputStream()
takenPhoto.compress(
Bitmap.CompressFormat.PNG,
100,
baos
)
val b: ByteArray = baos.toByteArray()
val encoded: String = Base64.encodeToString(b, Base64.DEFAULT)
editor.putString("profileImage", encoded)
editor.commit()
imageTy = false
} else {
imageTy = false
Log.e("takenPhoto", "canceled ...")
}
}

그래서 앱의 기능 구조에 맞게 uri는 이미지로 변환해 사용할 것이고, bitmap 은 그대로 저장해서 (byte type으로 전환 후) 사용할 것이기 때문에 코드 구현은 마무리가 되었다.


 


각각의 호출은 아래 예시와 같이 한다.  앞에 버튼은 갤러리를 호출하는 부분으로 image의 종류는 다 허용할 것이라서 아래 코드와 같이 구현을 하였고,  사진을 가져오는 부분은 카메라 앱을 호출하는 방식으로 구현을 하였다.


Column(
Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.End
) {
IconButton(onClick = {
imageTy = true
launcher.launch("image/*")
}) {
Icon(
imageVector = Icons.Default.PhotoAlbum,
contentDescription = "Search Profile",
tint = fontColor
)
}
IconButton(onClick = {
imageTy = true
takePhotoFromCameraLauncher.launch()
}) {
Icon(
imageVector = Icons.Default.Camera,
contentDescription = "Take a Picture",
tint = fontColor
)
}
}

 


이제 그 구현된 모습을 보자면 아래 그림과 같이 구현이 되었다.  프로필 이미지를 받아올 때 방법으로 갤러리와 카메라 버튼을 클릭하는 가에 따라서 위에서 구현된 source 가 동작을 할 것이다.


카메라앱 호출과 갤러리 호출 예시



 


실행되는 모습은 앱에서 직접 확인하시길... 아직은 upgrade 전이라서 찾아볼 수 없지만,  조만간 기능 구현이 끝나면 앱의 patch 가 실행 예정이다.


 





오늘의 이야기

 




내 주변에 이런 길들이 있다는 걸 이제야 알게 된다. 정부청사가 가까이에 있어서 얻는 것인가 싶기도 하지만, 대전에 머물게 된지도 벌써 15~6년이 넘어가는 것 같은데, 많이 변하고 있는 것 같기는 하다.


 


아파트 단지를 끼고 있어서 멀리 나가지 않아도 되고, 나름 큼직한 나무 사잇길이라 여름 햇볕도 그다지 두럽지(?)않은 길이기도 하다.  점심을 먹고 나서 걸어 보는 것도 좋고, 저녁 퇴근 후 집을 나서는 것도 좋다. 


 


하루 한번이라도 열심히 걸어서 내 몸속의 지방을 불살라 보리라...





오늘의 이야기


#스하리1000명프로젝트,
Terkadang sulit untuk berbicara dengan pekerja asing, bukan?
Saya membuat aplikasi sederhana yang membantu! Anda menulis dalam bahasa Anda, dan orang lain melihatnya dalam bahasa mereka.
Ini menerjemahkan secara otomatis berdasarkan pengaturan.
Sangat berguna untuk obrolan mudah. Lihatlah ketika Anda mendapat kesempatan!
https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416




오늘의 이야기

https://medium.com/codex/the-newer-way-to-make-network-calls-on-android-7162e2c37fe9







The newer way to make Network Calls on Android


We have used technologies such as Retrofit and Volley for far too long, and the industry has also adapted these very efficiently…


medium.com





예전에도 비슷한 한 내용을 퍼 왔던 거 같기는 한데,  다시금 보게 되어 이 글을 남겨 두고자 한다. 그래야 나중에 다시 한번 살펴보고 적용해 볼 수 있지 않을까 하는 생각이 들어서 이기도 하다.

비동기식 통신을 할 때는 여태까지 retrofit을 이용해서 하고는 있는데, 어떤 게 더 구현하기 쉬운가? 어떤 게 더 응답을 잘 받을 수 있는 가?

하는 궁금함이 밀려오는 건 어쩔 수 없는 가 보다. 이 부분도 나중에 구현을 해 보게 되면, 그 이야기를 남겨 보도록 해야겠다.





오늘의 이야기










오월의 어느 저녁  길을 나서 가다... 환하게 밝혀진 등불을 보고선, 길가...

해마다 느끼는 것이기는 하지만, 여기 이곳은 이렇게 예쁘장하게 단장을 하였다.  밤에 보는 공원의 모습은 이렇게 새롭다.

조금 더 있으면 날이 더워져 힘이 들어 갈 수 도 있을 터이지만, 이곳을 이렇게 거닐다 보면 어느 사이엔가 그 힘듬도 훨훨 날아가 버린다.

다음에 또 다시 이곳에 오는 날이 되면, 지금 보다도 더 휠씬 가벼워진 마음이 이곳에 오게 되기를 바라며...

오늘도 잘 살았으니 감사한다.





오늘의 이야기


#billcorea #운동동아리관리앱
🏸 Schneedle, aplikasi yang wajib dimiliki oleh klub bulu tangkis!
👉 Match Play – Rekam Skor & Temukan Lawan 🎉
Sempurna untuk di mana saja, sendirian, bersama teman, atau di klub! 🤝
Jika Anda suka bulu tangkis, cobalah

Buka aplikasi 👉 https://play.google.com/store/apps/details?id=com.billcorea.matchplay




오늘의 이야기



오월이 끝나갈 때쯤... 이제 유월이 소리도 없이 다가오려고 한다. 길가에 장미는 왜 이러도 많은 지...
계절의 여왕이라는 오월을 보내며... 난 또 새로운 계절 맞이 준비를 해야 할 것 같다.

장미의 이쁜 얼굴 아래 가려진 가시에 내 손이 상처를 입지 않도록 조심조심... 오늘도 난 내 길을 가려한다.

오늘도 잘 살았으니, 파이팅...





오늘의 이야기

https://medium.com/@cybercoder.naj/compose-navigation-in-3-minutes-5cff3c57c34e



 


Compose Navigation in 3 Minutes


Quick guide for navigation between composables in a Compose project


medium.com





나름대로 이제 배움을 정리해 가고 있기는 하나, 아직도 갈 길이 멀어 보이기는 하다.

오늘은 navigation 을 구현해 볼 준비를 해야 겠다. 이글을 읽어 보면서 말이다.

이전 posting 에서 구현해 보려고 했던 것들은 아직 미 완성인지라, 글로 옮겨 오기에는 무리가 있어 보인다.

잘 읽어 보고 오늘도 도전 !!!


2022.05.28 코딩으로 옮겨 보면서...


 


implementation "androidx.navigation:navigation-compose:2.5.0-rc01"

gradle 파일에 추가는 그대로 따라해 본다. 다만, 버전이 달라졌다.


 


먼저 NavigationItem class 는 그대로 따라서 만들어 보았다. 다만, 다른 건 title 을 다국어로 사용하기 위해서


values/string.xml 에 등록된 것을 사용하기 위해서 R.string.이름을 적용했다는 것이다.


sealed class NavigationItem(var route: String, var icon: Int, var title: Int) {
object Chats : NavigationItem("Chats", R.drawable.ic_baseline_chat_24, R.string.titleChatRoom)
object Profile : NavigationItem("Profile", R.drawable.ic_baseline_person_24, R.string.profileImage)
object Menus : NavigationItem("Menus", R.drawable.ic_baseline_menu_24, R.string.title_activity_setting)
}

 


이제 Mainactivity 에서 구성을 해 보겠다. 일단 onCreate 에 navController 을 선언하고 화면 하단에 appbar 을 설정해 보았다.


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

fontFamily = FontFamily(Font(R.font.poorstory_regular, FontWeight.Normal))

setContent {
val navController = rememberNavController()
MultiChat416Theme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Scaffold(
bottomBar = {
BottomNavigationBar(navController)
}
) { innerPadding ->
var paddingValues = innerPadding
Navigation(navController)
}
}
}
}
}

 


Navigation 의 구현은 아래와 같이 했는데, NavigationItem 의 route 도 string 으로 구현 되어 있으니, 그것을 이용해 아래와 같이 구현 했다.  navigation 이 찾아갈때, route 을 이용해서 찾아가니, 위치에 따라 잘 구현을 해야 한다.


그리고 아래 부분에는 navigation button 을 클릭 했을 때에 따라서 화면에 표시 하는 부분은 그대로 따라하기를 하였으며


title 의 표시 부분만 일부 수정을 해 보았다.


 


navigation 을 클릭했을 때 동작은 아래 보이는 Navigation 함수에서 처리를 하면 된다.


@Composable
fun Navigation(navController: NavHostController) {
NavHost(navController = navController, startDestination = NavigationItem.Chats.route) {
composable(route = NavigationItem.Chats.route) {
HomeScreen(navController)
}
composable(route = NavigationItem.Profile.route) {
Home2Screen(navController)
}
composable(route = NavigationItem.Menus.route) {
SecondScreen(navController, "Test...")
}
}
}

@Composable
fun BottomNavigationBar(navController: NavHostController) {
val items = listOf(
NavigationItem.Chats,
NavigationItem.Profile,
NavigationItem.Menus
)
BottomNavigation(
backgroundColor = colorResource(id = R.color.softBlue),
contentColor = Color.White
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
var context = LocalContext.current
items.forEach { item ->
BottomNavigationItem(
icon = { Icon(painterResource(id = item.icon), contentDescription = context.getString(item.title)) },
label = { Text(text = context.getString(item.title)) },
selectedContentColor = Color.White,
unselectedContentColor = Color.White.copy(0.4f),
alwaysShowLabel = true,
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}

 


bottom navigation 의 구현



 


구현이 끝난 화면의 예시는 위 그림과 같다. 이제 그 부분에 기능을 구현해 보면 될 것 같다.


 





오늘의 이야기


#스하리1000명프로젝트,
迷失在韓國?即使您不會說韓語,這個應用程式也可以幫助您輕鬆出行。
只需說出您的語言即可 - 它會翻譯、搜尋並以您的語言顯示結果。
非常適合旅行者!支援英語、日語、中文、越南語等10多種語言。
現在就試試吧!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




오늘의 이야기

네잎 크로바   오늘은 컴터를 켰더니 떠~억 네잎 크로바가 나왔다. 행운이 가득 하길 바라며... 오늘도 잘 살았으니, 감사합니다.