Skip to content

Commit

Permalink
Merge pull request #241 from boostcampwm-2022/feat/big_barcode
Browse files Browse the repository at this point in the history
겁나 큰 바코드 다이얼로그
  • Loading branch information
mangbaam authored Dec 18, 2022
2 parents 0cd4433 + 8bd47a8 commit ea5b79f
Show file tree
Hide file tree
Showing 17 changed files with 260 additions and 266 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.lighthouse.presentation.extension

import android.graphics.Bitmap
import android.graphics.Matrix

fun Bitmap.rotated(degrees: Float): Bitmap {
val matrix = Matrix().apply { postRotate(degrees) }
return Bitmap.createBitmap(this, 0, 0, width, height, matrix, false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ fun Int.toConcurrency(context: Context, useUnit: Boolean = true): String {
}
}

fun Int.toConcurrency(): String {
return DecimalFormat("#,###").format(this)
}

val screenWidth: Int
get() = Resources.getSystem().displayMetrics?.widthPixels ?: 0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ object Extras {

const val KEY_SELECTED_GALLERY_ITEM = "Extra.SelectedGalleryItem"
const val KEY_ORIGIN_IMAGE = "Extra.OriginImage"
const val KEY_BARCODE = "Extra.Barcode"

const val KEY_ENABLE_ASPECT_RATIO = "Extra.EnableAspectRatio"
const val KEY_ASPECT_RATIO = "Extra.AspectRatio"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.lighthouse.presentation.ui.common

import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.lighthouse.presentation.R

/**
* TextView 를 세로로 회전한 뷰
*
* @property topDown true 일 때 시계 방향 회전, false 일 때 반시계 방향 회전
*
* 코드 참고: [stackoverflow.com/a/45414489](https://stackoverflow.com/a/45414489)
*/
class VerticalTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : androidx.appcompat.widget.AppCompatTextView(context, attrs, defStyleAttr) {

var topDown: Boolean = DEFAULT_TOP_DOWN

init {
attrs?.let {
context.obtainStyledAttributes(it, R.styleable.VerticalTextView).run {
topDown = getBoolean(R.styleable.VerticalTextView_topDown, DEFAULT_TOP_DOWN)
recycle()
}
}
}

override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec)
setMeasuredDimension(measuredHeight, measuredWidth)
}

override fun onDraw(canvas: Canvas) {
if (topDown) {
canvas.translate(width.toFloat(), 0f)
canvas.rotate(90f)
} else {
canvas.translate(0f, height.toFloat())
canvas.rotate(-90f)
}
canvas.translate(
compoundPaddingLeft.toFloat(),
extendedPaddingTop.toFloat()
)
layout.draw(canvas)
}

companion object {
private const val DEFAULT_TOP_DOWN = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,40 @@ package com.lighthouse.presentation.ui.detailgifticon

import android.app.Activity
import android.content.Intent
import android.graphics.RectF
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.widget.Toast
import androidx.activity.addCallback
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.toRectF
import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.lighthouse.presentation.R
import com.lighthouse.presentation.databinding.ActivityGifticonDetailBinding
import com.lighthouse.presentation.databinding.DialogUsageHistoryBinding
import com.lighthouse.presentation.extension.getParcelable
import com.lighthouse.presentation.extension.isOnScreen
import com.lighthouse.presentation.extension.repeatOnStarted
import com.lighthouse.presentation.extension.scrollToBottom
import com.lighthouse.presentation.extension.show
import com.lighthouse.presentation.extra.Extras
import com.lighthouse.presentation.model.CroppedImage
import com.lighthouse.presentation.ui.common.dialog.OriginImageDialog
import com.lighthouse.presentation.ui.common.dialog.datepicker.SpinnerDatePicker
import com.lighthouse.presentation.ui.cropgifticon.CropGifticonActivity
import com.lighthouse.presentation.ui.detailgifticon.dialog.LargeBarcodeDialog
import com.lighthouse.presentation.ui.detailgifticon.dialog.UsageHistoryAdapter
import com.lighthouse.presentation.ui.detailgifticon.dialog.UseGifticonDialog
import com.lighthouse.presentation.ui.edit.modifygifticon.ModifyGifticonActivity
import com.lighthouse.presentation.ui.security.AuthCallback
import com.lighthouse.presentation.ui.security.AuthManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import javax.inject.Inject

@AndroidEntryPoint
Expand All @@ -66,15 +53,15 @@ class GifticonDetailActivity : AppCompatActivity() {
?: CashCardGifticonInfoFragment()
}

private lateinit var checkEditDialog: AlertDialog
private lateinit var usageHistoryDialog: AlertDialog
private lateinit var useGifticonDialog: UseGifticonDialog
private lateinit var gifticonInfoNotChangedToast: Toast

private val usageHistoryAdapter by lazy { UsageHistoryAdapter() }

private val btnUseGifticon by lazy { binding.btnUseGifticon }
private var largeBarcodeDialog: LargeBarcodeDialog? = null

private val btnMaster by lazy { binding.btnMaster }
private val chip by lazy { binding.chipScrollDownForUseButton }
private val spinnerDatePicker = SpinnerDatePicker()

@Inject
lateinit var authManager: AuthManager
Expand Down Expand Up @@ -103,29 +90,6 @@ class GifticonDetailActivity : AppCompatActivity() {
}
}

private val cropGifticon = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
// val gifticon = viewModel.gifticon.value ?: return@registerForActivityResult
// val output = getFileStreamPath("")
//
// lifecycleScope.launch {
// val croppedImage = withContext(Dispatchers.IO) {
// getCropResult(result, output)
// } ?: return@launch
// viewModel.updateGifticonCrop(GifticonCrop(gifticon.id, croppedImage.croppedRect.toRect().toDomain()))
// binding.ivProductImage.loadUriWithoutCache(croppedImage.uri)
// }
}

private val backKeyCallback by lazy {
onBackPressedDispatcher.addCallback {
if (viewModel.mode.value == GifticonDetailMode.EDIT) {
showNotSavedEditInfoDialog()
} else {
finish()
}
}
}

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

Expand All @@ -135,9 +99,9 @@ class GifticonDetailActivity : AppCompatActivity() {

setSupportActionBar(binding.tbGifticonDetail)

binding.btnUseGifticon.viewTreeObserver.addOnDrawListener {
binding.btnMaster.viewTreeObserver.addOnDrawListener {
chip.post {
chip.isVisible = btnUseGifticon.isOnScreen().not()
chip.isVisible = btnMaster.isOnScreen().not()
}
}
repeatOnStarted {
Expand All @@ -159,26 +123,6 @@ class GifticonDetailActivity : AppCompatActivity() {
}
}
}
repeatOnStarted {
viewModel.tempGifticon.collect { gifticon ->
spinnerDatePicker.setDate(gifticon?.expireAt ?: return@collect)
}
}
repeatOnStarted {
viewModel.mode.collect { mode ->
when (mode) {
GifticonDetailMode.UNUSED -> {
binding.btnUseGifticon.text = getString(R.string.gifticon_detail_unused_mode_button_text)
}
GifticonDetailMode.USED -> {
binding.btnUseGifticon.text = getString(R.string.gifticon_detail_used_mode_button_text)
}
GifticonDetailMode.EDIT -> {
binding.btnUseGifticon.text = getString(R.string.gifticon_detail_edit_mode_button_text)
}
}
}
}
repeatOnStarted {
viewModel.failure.collect {
showInvalidDialog()
Expand All @@ -202,13 +146,6 @@ class GifticonDetailActivity : AppCompatActivity() {
Toast.LENGTH_SHORT
).show()
}
is GifticonDetailEvent.OnGifticonInfoChanged -> {
if (event.before == event.after) {
showGifticonInfoNotChangedToast()
} else {
showGifticonInfoChangedSnackBar()
}
}
is GifticonDetailEvent.ExpireDateClicked -> {
showDatePickerDialog()
}
Expand All @@ -226,11 +163,8 @@ class GifticonDetailActivity : AppCompatActivity() {
is GifticonDetailEvent.ShowOriginalImage -> {
showOriginGifticonDialog(event.origin)
}
is GifticonDetailEvent.NavigateToCropGifticon -> {
gotoCropGifticon(
getFileStreamPath(event.originPath).toUri(),
event.croppedRect.toRectF()
)
is GifticonDetailEvent.ShowLargeBarcode -> {
showLargeBarcodeDialog(event.barcode)
}
else -> { // TODO(이벤트 처리)
}
Expand All @@ -245,39 +179,6 @@ class GifticonDetailActivity : AppCompatActivity() {
startActivity(intent)
}

private fun showCheckEditDialog() {
if (::checkEditDialog.isInitialized.not()) {
checkEditDialog = AlertDialog.Builder(this)
.setTitle(getString(R.string.gifticon_detail_check_edit_dialog_title))
.setPositiveButton(getString(R.string.gifticon_detail_check_edit_dialog_positive_button)) { _, _ ->
viewModel.switchMode(GifticonDetailMode.EDIT)
viewModel.startEdit()
}
.setNegativeButton(getString(R.string.gifticon_detail_check_edit_dialog_negative_button)) { dialog, _ ->
dialog.cancel()
}
.create()
}
checkEditDialog.show()
}

private val spinnerDatePicker = SpinnerDatePicker().apply {
setOnDatePickListener { year, month, dayOfMonth ->
viewModel.editExpireDate(year, month, dayOfMonth)
}
}

private fun showNotSavedEditInfoDialog() {
AlertDialog.Builder(this)
.setTitle(getString(R.string.gifticon_detail_back_in_edit_dialog_title))
.setMessage(getString(R.string.gifticon_detail_back_in_edit_dialog_message))
.setPositiveButton(getString(R.string.all_do_cancel)) { dialog, _ ->
viewModel.cancelEdit()
dialog.dismiss()
}
.show()
}

private fun showDatePickerDialog() {
spinnerDatePicker.show(supportFragmentManager)
}
Expand Down Expand Up @@ -338,71 +239,22 @@ class GifticonDetailActivity : AppCompatActivity() {
arguments = Bundle().apply {
putParcelable(Extras.KEY_ORIGIN_IMAGE, uri)
}
}.show(supportFragmentManager, OriginImageDialog::class.java.name)
}.show(supportFragmentManager)
}

private suspend fun getCropResult(result: ActivityResult, output: File): CroppedImage? {
return if (result.resultCode == Activity.RESULT_OK) {
val croppedUri = result.data?.getParcelable(Extras.KEY_CROPPED_IMAGE, Uri::class.java) ?: return null
val croppedRect = result.data?.getParcelable(Extras.KEY_CROPPED_RECT, RectF::class.java) ?: return null

withContext(Dispatchers.IO) {
FileInputStream(croppedUri.path).copyTo(
FileOutputStream(output)
)
}
CroppedImage(output.toUri(), croppedRect)
} else {
null
private fun showLargeBarcodeDialog(barcode: String) {
if (largeBarcodeDialog?.isAdded == true) {
largeBarcodeDialog?.dismiss()
}
}

private fun gotoCropGifticon(uri: Uri, croppedRect: RectF) {
val intent = Intent(this, CropGifticonActivity::class.java).apply {
putExtra(Extras.KEY_ORIGIN_IMAGE, uri)
putExtra(Extras.KEY_CROPPED_RECT, croppedRect)
}
cropGifticon.launch(intent)
}

private fun showGifticonInfoChangedSnackBar() {
Snackbar.make(
binding.clGifticonDetail,
getString(R.string.gifticon_detail_info_changed_snackbar_text),
INFO_CHANGED_SNACKBAR_DURATION_MILLI_SECOND
).apply {
animationMode = Snackbar.ANIMATION_MODE_SLIDE
setAction(getString(R.string.gifticon_detail_info_changed_snackbar_action_text)) {
viewModel.rollbackChangedGifticonInfo()
largeBarcodeDialog = LargeBarcodeDialog().apply {
arguments = Bundle().apply {
putString(Extras.KEY_BARCODE, barcode)
}
}.show()
}

private fun showGifticonInfoNotChangedToast() {
if (::gifticonInfoNotChangedToast.isInitialized.not()) {
gifticonInfoNotChangedToast =
Toast.makeText(this, getString(R.string.gifticon_detail_nothing_changed_toast), Toast.LENGTH_SHORT)
}
gifticonInfoNotChangedToast.show()
}

override fun onStart() {
super.onStart()
backKeyCallback.isEnabled = true
}

override fun onStop() {
backKeyCallback.isEnabled = false
super.onStop()
}

override fun onDestroy() {
backKeyCallback.remove()
super.onDestroy()
largeBarcodeDialog?.show(supportFragmentManager)
}

companion object {
const val INVALID_DIALOG_DEADLINE_SECOND = 5
const val INFO_CHANGED_SNACKBAR_DURATION_MILLI_SECOND = 5000
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package com.lighthouse.presentation.ui.detailgifticon

import android.graphics.Rect
import com.lighthouse.domain.model.Gifticon

sealed class GifticonDetailEvent {
object ScrollDownForUseButtonClicked : GifticonDetailEvent()
object ShareButtonClicked : GifticonDetailEvent()
object ShowAllUsedInfoButtonClicked : GifticonDetailEvent()
data class ShowOriginalImage(val origin: String) : GifticonDetailEvent()
data class ShowLargeBarcode(val barcode: String) : GifticonDetailEvent()
object EditButtonClicked : GifticonDetailEvent()
object ExistEmptyInfo : GifticonDetailEvent()
data class OnGifticonInfoChanged(val before: Gifticon, val after: Gifticon) : GifticonDetailEvent()
object ExpireDateClicked : GifticonDetailEvent()
object UseGifticonButtonClicked : GifticonDetailEvent()
object UseGifticonComplete : GifticonDetailEvent()
data class NavigateToCropGifticon(val originPath: String, val croppedRect: Rect) : GifticonDetailEvent()
}
Loading

0 comments on commit ea5b79f

Please sign in to comment.