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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5c5c533
[feature/qr]: Add third party dependency
librarywon Oct 4, 2023
95034ae
[feature/qr]: bottomSheet 생성 및 기능 이전
librarywon Oct 9, 2023
bd17c3b
[feature/qr]:Add zxing-core dependency
librarywon Oct 15, 2023
3577bda
[feature/qr]:Add permission WRITE_EXTERNAL_STORAGE
librarywon Oct 15, 2023
c1cb67d
[feature/qr]: Feat qrActivityResultLauncher
librarywon Oct 15, 2023
8535085
[feature/qr]: Feat qrRead and navigate AddPhoto or Web
librarywon Oct 15, 2023
3e0b87b
[feature/qr]: Refactor extract imageDownload code
librarywon Oct 15, 2023
576944f
[feature/qr]: Chore extract string
librarywon Oct 17, 2023
b8ccdac
[feature/qr]: Feat encapsulation and UI setting
librarywon Oct 17, 2023
a3c97a0
[feature/qr]: Chore Logic extract to companion object
librarywon Oct 17, 2023
2222650
[feature/qr]: Chore remove blank and edit exported
librarywon Oct 17, 2023
e5fddae
[feature/qr]: Chore remove useless dependency
librarywon Oct 17, 2023
154728e
[feature/qr]: apply code review
librarywon Oct 17, 2023
88a8be9
[feature/qr]: Feat dismiss bottomSheet when backButton active in AddP…
librarywon Oct 17, 2023
261d516
[feature/qr]: Refactor to SingleClickListener
librarywon Oct 17, 2023
5928b34
[feature/qr]: Refactor use scope
librarywon Oct 17, 2023
bc2df6a
[feature/qr]: feat loading
librarywon Oct 17, 2023
394a5eb
[feature/qr]: chore extract string
librarywon Oct 17, 2023
299ee26
[feature/qr]: refactor viewBinding
librarywon Oct 17, 2023
721f5c4
[feature/qr]: Refactor DefaultLifecycleObserver
librarywon Oct 17, 2023
80bb168
[feature/qr]: Refactor remove legacy
librarywon Oct 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ dependencies {
implementation(libs.coil.core)
implementation(libs.bundles.retrofit)
implementation(libs.kakao.login)
implementation(libs.zxing.android.embedded)

debugImplementation(libs.bundles.flipper)

Expand Down
8 changes: 6 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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


<application
android:name=".App"
Expand All @@ -17,6 +18,9 @@
android:theme="@style/Theme.Pophory"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".feature.qr.QRActivity"
android:exported="false" />
<activity
android:name=".feature.share.ShareActivity"
android:exported="false" />
Expand Down Expand Up @@ -68,7 +72,7 @@
android:exported="false" />
<activity
android:name=".feature.home.HomeActivity"
android:exported="true" >
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
Expand Down Expand Up @@ -141,4 +145,4 @@
android:exported="false" />
</application>

</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package com.teampophory.pophory.feature.home
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
Expand All @@ -13,8 +11,8 @@ import com.teampophory.pophory.R
import com.teampophory.pophory.common.context.stringOf
import com.teampophory.pophory.common.view.viewBinding
import com.teampophory.pophory.databinding.ActivityHomeBinding
import com.teampophory.pophory.feature.home.add.AddPhotoBottomSheet
import com.teampophory.pophory.feature.home.mypage.MyPageFragment
import com.teampophory.pophory.feature.home.photo.AddPhotoActivity
import com.teampophory.pophory.feature.home.store.StoreFragment
import com.teampophory.pophory.util.dialog.DialogUtil
import dagger.hilt.android.AndroidEntryPoint
Expand All @@ -23,22 +21,6 @@ import dagger.hilt.android.AndroidEntryPoint
class HomeActivity : AppCompatActivity() {
private val binding: ActivityHomeBinding by viewBinding(ActivityHomeBinding::inflate)
private val viewModel by viewModels<HomeViewModel>()
private val addPhotoResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
viewModel.eventAlbumCountUpdate()
}
}

private val 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(this, uri.toString(), albumItem)
addPhotoResultLauncher.launch(intent)
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -75,7 +57,8 @@ class HomeActivity : AppCompatActivity() {
return@setOnClickListener
}
}
imagePicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
val modalBottomSheet = AddPhotoBottomSheet()
modalBottomSheet.show(supportFragmentManager, AddPhotoBottomSheet.TAG)
Comment on lines +60 to +61
Copy link
Member

Choose a reason for hiding this comment

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

👍🏻

}
}

Expand All @@ -92,7 +75,6 @@ class HomeActivity : AppCompatActivity() {
}
}


companion object {
@JvmStatic
fun getIntent(context: Context) = Intent(context, HomeActivity::class.java).apply {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.teampophory.pophory.feature.home.add

import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.activityViewModels
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.teampophory.pophory.R
import com.teampophory.pophory.common.view.setOnSingleClickListener
import com.teampophory.pophory.common.view.viewBinding
import com.teampophory.pophory.databinding.BottomSheetHomeAddPhotoBinding
import com.teampophory.pophory.feature.home.HomeViewModel
import com.teampophory.pophory.feature.home.photo.AddPhotoActivity
import com.teampophory.pophory.feature.qr.QRActivity

class AddPhotoBottomSheet : BottomSheetDialogFragment() {

private val binding by viewBinding(BottomSheetHomeAddPhotoBinding::bind)
private val viewModel by activityViewModels<HomeViewModel>()
private lateinit var imagePicker: ActivityResultLauncher<PickVisualMediaRequest>
private lateinit var addPhotoResultLauncher: ActivityResultLauncher<Intent>
private lateinit var qrActivityResultLauncher: ActivityResultLauncher<Intent>

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.bottom_sheet_home_add_photo, container, false)
}

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)
Comment on lines +40 to +48
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 +46 to +50
Copy link
Member

Choose a reason for hiding this comment

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

이렇게 구현되면 사진 추가 화면에서 제출 안하고 바로 뒤로가기 했을때 이 BottomSheet 그대로 보이지 않나?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

맞습니다 백버튼 누르면 RESULT_CANCELED을 발생시키고 dismiss시키는 방향으로 수정하겠습니다!


qrActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val uriString = it.data?.getStringExtra("downloaded_image_uri")
val currentAlbumPosition = viewModel.homeState.value.currentAlbumPosition
val albumItem =
viewModel.homeState.value.currentAlbums?.getOrNull(currentAlbumPosition)
if (uriString != null && albumItem != null) {
val intent = AddPhotoActivity.getIntent(context, uriString, albumItem)
addPhotoResultLauncher.launch(intent)
}
}
if (it.resultCode == RESULT_CANCELED) {
dismiss()
}
}

addPhotoResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
viewModel.eventAlbumCountUpdate()
dismiss()
} else if (it.resultCode == RESULT_CANCELED) {
dismiss()
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initListMenuViews()
}

private fun initListMenuViews() {
with(binding) {
layoutQr.setOnSingleClickListener {
val intent = Intent(context, QRActivity::class.java)
qrActivityResultLauncher.launch(intent)
}
layoutGallery.setOnSingleClickListener {
imagePicker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
}
}

companion object {
val TAG: String = AddPhotoBottomSheet::class.java.simpleName
Copy link
Member

Choose a reason for hiding this comment

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

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.

이게 const를 붙이면 뒤의 값이 constant하지 않다고 오류가 나옵니다!

}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.teampophory.pophory.feature.home.photo

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Size
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
Expand Down Expand Up @@ -83,6 +85,10 @@ class AddPhotoActivity : BindingActivity<ActivityAddPhotoBinding>(R.layout.activ
binding.btnSubmit.setOnSingleClickListener {
viewModel.onSubmit()
}
onBackPressedDispatcher.addCallback(this) {
setResult(Activity.RESULT_CANCELED)
finish()
}
}

private fun subscribeEvent() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.teampophory.pophory.feature.qr

import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Environment
import android.webkit.CookieManager
import android.webkit.URLUtil

class ImageDownloader() {
private var receiver: BroadcastReceiver? = null

fun downloadImageFromUrl(context: Context, url: String, callback: (Uri?) -> Unit) {
val request = createDownloadRequest(context, url)
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
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
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadManager = context.getSystemService<DownloadManager>()

이렇게 하셔도 됩니다.

val downloadID = downloadManager.enqueue(request)
setupDownloadCompletionReceiver(context, downloadID, callback)
}

private fun createDownloadRequest(context: Context, url: String): DownloadManager.Request {
return DownloadManager.Request(Uri.parse(url)).apply {
setMimeType("image/jpeg")
val cookies = CookieManager.getInstance().getCookie(url)
addRequestHeader("cookie", cookies)
setDescription("Downloading image...")
setTitle(URLUtil.guessFileName(url, null, "image/jpeg"))
allowScanningByMediaScanner()
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
URLUtil.guessFileName(url, null, "image/jpeg")
)
}
}

private fun setupDownloadCompletionReceiver(
context: Context,
downloadID: Long,
callback: (Uri?) -> Unit
) {
receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (downloadID == id) {
val downloadManager =
context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query().setFilterById(downloadID)
downloadManager.query(query).use { cursor ->
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
if (DownloadManager.STATUS_SUCCESSFUL == cursor.getInt(columnIndex)) {
val uriString = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
uriString?.let {
callback(Uri.parse(it))
return
}
}
}
}
callback(null)
}
}
}
context.registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}

fun unregisterReceiver(context: Context) {
receiver?.let {
context.unregisterReceiver(it)
}
}
}
Loading