-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature/qr] QR코드 인식 및 사진 불러오기 기능 작업 #314
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로직 상당히 어려웠을텐데 고생많으셨습니다 👍🏻 한번 리뷰 확인해주세요
app/build.gradle.kts
Outdated
@@ -10,6 +10,7 @@ plugins { | |||
alias(libs.plugins.app.distribution) | |||
alias(libs.plugins.crashlytics) | |||
id("com.google.android.gms.oss-licenses-plugin") | |||
alias(libs.plugins.kotlin.android) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 삭제!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
삭제!!
app/build.gradle.kts
Outdated
implementation(libs.appcompat) | ||
implementation(libs.material) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 삭제!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
삭제!!
@@ -4,6 +4,7 @@ | |||
|
|||
<uses-permission android:name="android.permission.INTERNET" /> | |||
<uses-permission android:name="com.google.android.gms.permission.AD_ID" /> | |||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
예전에 사용해본 기억으로 당연히 사용하는줄 알았는데 몰랐습니다! 하위버전 대응하는 목적으로 그냥 두고 알고 있겠습니다!
app/src/main/AndroidManifest.xml
Outdated
@@ -80,7 +86,7 @@ | |||
android:exported="false" | |||
android:windowSoftInputMode="adjustResize" /> | |||
<activity | |||
android:name="com.teampophory.pophory.onboarding.OnBoardingActivity" | |||
android:name=".onboarding.OnBoardingActivity" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 리베이스 해도 이렇게 바뀌나..? 모듈 분리해서 com.teampophory.pophory 있어야 할 것 같은데
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다시 com.teampophory.pophory로 반영하겠습니다!
val modalBottomSheet = AddPhotoBottomSheet() | ||
modalBottomSheet.show(supportFragmentManager, AddPhotoBottomSheet.TAG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻
} | ||
|
||
private fun initToolbar() { | ||
binding.toolbarQr.txtToolbarTitle.text = getText(R.string.qr_toolbar_text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getText -> stringOf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getText구현 함수가 common/context 있었군요 감사합니다!
|
||
private fun configureStatusText() { | ||
val statusTextView = binding.decorateBarcodeViewQr.getStatusView() | ||
statusTextView.setTextAppearance(com.teampophory.pophory.designsystem.R.style.TextAppearance_Pophory_HeadLine03) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nonTransitiveR 굳
barcodeView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> | ||
val framingRect = barcodeView.framingRect | ||
framingRect?.let { | ||
val desiredYPosition = it.bottom + TEXT_MARGIN_TOP.dp | ||
statusTextView.y = desiredYPosition.toFloat() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이건 어케 한거누.....혹시 어떤 로직인지 알려주실?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안드를 찢어놓았다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이게 decorateBarcodeView 내부의 viewfinder(바코드 인식하는 네모부분)의 위치를 framingRect라는 애가 알고 있어서 가져오고,
decorateBarcodeView의 viewfinder의 statusTextView(바코드에 나오는 텍스트)의 위치를 viewfinder바로 아래 위치 시키는겁니다!
처음에 그릴때 바로 위치를 잡아주려고 했으나 viewfinder가 그려지기 전에 statusTextView가 먼저 자리를 잡아서 위치를 잡지 못하였고 다 그려진 후에 위치를 잡아주기위해 addOnLayoutChangeListener함수를 사용했습니다.
다른 방법를 선택하는 것이 저도 좋을 듯 싶은데 아직 방법을 잘 모르겠습니다. ㅠㅠ
val jsScript = """(function() { | ||
var imageElement = document.querySelector('img'); | ||
return imageElement ? imageElement.src : null; | ||
})();""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋinjectJS까지 했네...고생했다
그리고 var 말고 const로 해줄 수 있나?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵!!
if (uri != null) { | ||
viewModel.uiState.value = QRState.Success(uri) | ||
} else { | ||
viewModel.uiState.value = | ||
QRState.Fail(getString(R.string.qr_image_download_fail)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (uri != null) { | |
viewModel.uiState.value = QRState.Success(uri) | |
} else { | |
viewModel.uiState.value = | |
QRState.Fail(getString(R.string.qr_image_download_fail)) | |
} | |
viewModel.uiState.value = if (uri != null) { | |
QRState.Success(uri) | |
} else { | |
QRState.Fail(getString(R.string.qr_image_download_fail)) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
더 코틀린스럽고 좋은것 같습니당 ㅎㅎ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생 많으셨습니다~!! 👏
app/src/main/AndroidManifest.xml
Outdated
<activity | ||
android:name=".feature.qr.QRActivity" | ||
android:exported="true" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported false !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 걸렸다!
override fun onAttach(context: Context) { | ||
super.onAttach(context) | ||
|
||
imagePicker = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> | ||
val currentAlbumPosition = viewModel.homeState.value.currentAlbumPosition | ||
val albumItem = viewModel.homeState.value.currentAlbums?.getOrNull(currentAlbumPosition) | ||
if (uri != null && albumItem != null) { | ||
val intent = AddPhotoActivity.getIntent(context, uri.toString(), albumItem) | ||
addPhotoResultLauncher.launch(intent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onAttach에서 초기화 하는 이유가 따로 있나요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
registerForActivityResult
속에서 context를 사용하고 있는데 context가 프레그먼트에 가장 먼저 연결되는 시점인 onAttach
에서 초기화해야 문제가 없을 것 같아서 onAttach에서 진행했습니다
layoutQr.setOnClickListener { | ||
val intent = Intent(context, QRActivity::class.java) | ||
qrActivityResultLauncher.launch(intent) | ||
} | ||
layoutGallery.setOnClickListener { | ||
imagePicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맛있다
context.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unRegisterReceiver 는 어디서 하고있는지 확인해주셔야할 것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
없다면 추가 부탁드립니다~!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unRegisterReceiver가 없습니다 추가하겠습니다!
setupBarcodeScanner() | ||
} | ||
|
||
is QRState.Loading -> {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core에 있숩니다
private fun setupWebView() { | ||
webView = binding.webViewQr | ||
webView.apply { | ||
settings.apply { | ||
javaScriptEnabled = true | ||
useWideViewPort = true | ||
} | ||
webViewClient = object : WebViewClient() { | ||
override fun onPageFinished(view: WebView, url: String) { | ||
super.onPageFinished(view, url) | ||
fetchImageUrlFromWebView() | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
웹뷰를 변수에 할당하지 않아도 될 것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기존에 분리되어있던 변수를 함수화 하는과정에 지우지 않았던거 같네요 감사합니다!!
barcodeView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> | ||
val framingRect = barcodeView.framingRect | ||
framingRect?.let { | ||
val desiredYPosition = it.bottom + TEXT_MARGIN_TOP.dp | ||
statusTextView.y = desiredYPosition.toFloat() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안드를 찢어놓았다
private fun handleFailState() { | ||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(webView.url)) | ||
startActivity(browserIntent) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기 runcatching으로 묶어주세욥 ActionView로 URI 던질 때 잘못되어있으면 터집니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 올바른 url만 넘어올거라고 생각한 나...
const val FIND_IMAGE_LOGIC = """(function() { | ||
var images = document.querySelectorAll('img'); | ||
var downloadLinks = document.querySelectorAll('a[href*=".jpg"]'); | ||
var buttonImages = document.querySelectorAll('button[src*=".jpg"]'); | ||
var longestImage = null; | ||
var longestHeight = 0; | ||
|
||
// Find the tallest image from <img> tags | ||
for (var i = 0; i < images.length; i++) { | ||
if (images[i].naturalHeight > longestHeight) { | ||
longestHeight = images[i].naturalHeight; | ||
longestImage = images[i]; | ||
} | ||
} | ||
|
||
if (longestImage) { | ||
return longestImage.src; | ||
} else if (downloadLinks.length > 0) { | ||
return downloadLinks[0].href; | ||
} else if (buttonImages.length > 0) { | ||
return buttonImages[0].src; | ||
} | ||
|
||
return null; | ||
})();""" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요건 뭐에요!?!??!? 리플렉션인가요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
js 코드입니다..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge it
const val FIND_IMAGE_LOGIC = """(function() { | ||
var images = document.querySelectorAll('img'); | ||
var downloadLinks = document.querySelectorAll('a[href*=".jpg"]'); | ||
var buttonImages = document.querySelectorAll('button[src*=".jpg"]'); | ||
var longestImage = null; | ||
var longestHeight = 0; | ||
|
||
// Find the tallest image from <img> tags | ||
for (var i = 0; i < images.length; i++) { | ||
if (images[i].naturalHeight > longestHeight) { | ||
longestHeight = images[i].naturalHeight; | ||
longestImage = images[i]; | ||
} | ||
} | ||
|
||
if (longestImage) { | ||
return longestImage.src; | ||
} else if (downloadLinks.length > 0) { | ||
return downloadLinks[0].href; | ||
} else if (buttonImages.length > 0) { | ||
return buttonImages[0].src; | ||
} | ||
|
||
return null; | ||
})();""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@joonBaek12 이거 로직
이슈 코드
📸 스크린샷
구현 사진은 카카오톡방에 보내드리고 추후 더 업데이트하겠습니다.
🍀 관련 이슈
To Reviewer
아직 부족함이 많지만 열심히 머리 굴려서 완성해보았습니다. 감사합니다!