Skip to content
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

Merged
merged 21 commits into from
Oct 17, 2023

Conversation

librarywon
Copy link
Contributor

@librarywon librarywon commented Oct 17, 2023

이슈 코드

📸 스크린샷

구현 사진은 카카오톡방에 보내드리고 추후 더 업데이트하겠습니다.

🍀 관련 이슈

  • 웹사이트 내부에 사진이 있는 사진관들은 대부분 대응이 가능합니다.
  • 버튼으로만 다운받는 사진관은 지원하지 않습니다.
  • 현재 확인해본 사진관으로는 (인ㅇ네컷, 포ㅇ시그니처,하ㅇ필름)이 돌아가는 것을 확인하였습니다.

To Reviewer

아직 부족함이 많지만 열심히 머리 굴려서 완성해보았습니다. 감사합니다!

@librarywon librarywon added 🦈서재원 서재원이 했다 ✨ Feature 기능 개발 labels Oct 17, 2023
@librarywon librarywon self-assigned this Oct 17, 2023
@librarywon librarywon requested a review from a team as a code owner October 17, 2023 10:42
@librarywon librarywon changed the title Feature/qr [Feature/qr] QR코드 인식 및 사진 불러오기 기능 작업 Oct 17, 2023
Copy link
Member

@l2hyunwoo l2hyunwoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로직 상당히 어려웠을텐데 고생많으셨습니다 👍🏻 한번 리뷰 확인해주세요

@@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 삭제!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삭제!!

Comment on lines 112 to 113
implementation(libs.appcompat)
implementation(libs.material)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 삭제!

Copy link
Contributor Author

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" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크린샷 2023-10-17 오후 7 43 46

이게 아마 지금 우리가 사용하고 있는 버전에서는 영향을 미치지 못할거야. 하위 버전 때문에 넣은거라면 okay

Copy link
Contributor Author

@librarywon librarywon Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예전에 사용해본 기억으로 당연히 사용하는줄 알았는데 몰랐습니다! 하위버전 대응하는 목적으로 그냥 두고 알고 있겠습니다!

@@ -80,7 +86,7 @@
android:exported="false"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="com.teampophory.pophory.onboarding.OnBoardingActivity"
android:name=".onboarding.OnBoardingActivity"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 리베이스 해도 이렇게 바뀌나..? 모듈 분리해서 com.teampophory.pophory 있어야 할 것 같은데

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다시 com.teampophory.pophory로 반영하겠습니다!

Comment on lines +60 to +61
val modalBottomSheet = AddPhotoBottomSheet()
modalBottomSheet.show(supportFragmentManager, AddPhotoBottomSheet.TAG)
Copy link
Member

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getText -> stringOf

Copy link
Contributor Author

@librarywon librarywon Oct 17, 2023

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nonTransitiveR 굳

Comment on lines +136 to +142
barcodeView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
val framingRect = barcodeView.framingRect
framingRect?.let {
val desiredYPosition = it.bottom + TEXT_MARGIN_TOP.dp
statusTextView.y = desiredYPosition.toFloat()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 어케 한거누.....혹시 어떤 로직인지 알려주실?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안드를 찢어놓았다

Copy link
Contributor Author

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함수를 사용했습니다.

다른 방법를 선택하는 것이 저도 좋을 듯 싶은데 아직 방법을 잘 모르겠습니다. ㅠㅠ

Comment on lines 156 to 159
val jsScript = """(function() {
var imageElement = document.querySelector('img');
return imageElement ? imageElement.src : null;
})();"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋinjectJS까지 했네...고생했다

그리고 var 말고 const로 해줄 수 있나?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!!

Comment on lines 168 to 173
if (uri != null) {
viewModel.uiState.value = QRState.Success(uri)
} else {
viewModel.uiState.value =
QRState.Fail(getString(R.string.qr_image_download_fail))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더 코틀린스럽고 좋은것 같습니당 ㅎㅎ

Copy link
Member

@kez-lab kez-lab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생 많으셨습니다~!! 👏

Comment on lines 21 to 23
<activity
android:name=".feature.qr.QRActivity"
android:exported="true" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exported false !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 걸렸다!

Comment on lines +39 to +47
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onAttach에서 초기화 하는 이유가 따로 있나요?!

Copy link
Contributor Author

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에서 진행했습니다

Comment on lines 84 to 90
layoutQr.setOnClickListener {
val intent = Intent(context, QRActivity::class.java)
qrActivityResultLauncher.launch(intent)
}
layoutGallery.setOnClickListener {
imagePicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맛있다

Comment on lines 68 to 70
context.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unRegisterReceiver 는 어디서 하고있는지 확인해주셔야할 것 같아요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

없다면 추가 부탁드립니다~!!

Copy link
Contributor Author

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 -> {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core에 있숩니다

Comment on lines 99 to 113
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()
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

웹뷰를 변수에 할당하지 않아도 될 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 분리되어있던 변수를 함수화 하는과정에 지우지 않았던거 같네요 감사합니다!!

Comment on lines +136 to +142
barcodeView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
val framingRect = barcodeView.framingRect
framingRect?.let {
val desiredYPosition = it.bottom + TEXT_MARGIN_TOP.dp
statusTextView.y = desiredYPosition.toFloat()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안드를 찢어놓았다

Comment on lines 184 to 187
private fun handleFailState() {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(webView.url))
startActivity(browserIntent)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요기 runcatching으로 묶어주세욥 ActionView로 URI 던질 때 잘못되어있으면 터집니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 올바른 url만 넘어올거라고 생각한 나...

Comment on lines 199 to 225
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;
})();"""
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요건 뭐에요!?!??!? 리플렉션인가요?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

js 코드입니다..

Copy link
Member

@l2hyunwoo l2hyunwoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge it

@librarywon librarywon merged commit 6304279 into develop Oct 17, 2023
@librarywon librarywon deleted the feature/qr branch October 17, 2023 12:49
Comment on lines +213 to +237
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;
})();"""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joonBaek12 이거 로직

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ Feature 기능 개발 🦈서재원 서재원이 했다
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEAT]: QR로 사진 등록하기 기능 개발
3 participants