diff --git a/.idea/misc.xml b/.idea/misc.xml index 74dd639..b2c751a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/app/src/main/java/com/stable/scoi/MainActivity.kt b/app/src/main/java/com/stable/scoi/MainActivity.kt new file mode 100644 index 0000000..8eb340f --- /dev/null +++ b/app/src/main/java/com/stable/scoi/MainActivity.kt @@ -0,0 +1,22 @@ +package com.stable.scoi + +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContentView(R.layout.activity_main) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/di/RetrofitModule.kt b/app/src/main/java/com/stable/scoi/di/RetrofitModule.kt index 0cc9c8e..adbdeb5 100644 --- a/app/src/main/java/com/stable/scoi/di/RetrofitModule.kt +++ b/app/src/main/java/com/stable/scoi/di/RetrofitModule.kt @@ -4,8 +4,8 @@ import android.util.Log import com.google.gson.GsonBuilder import com.google.gson.JsonParser import com.google.gson.JsonSyntaxException -import com.stable.scoi.extension.isJsonArray -import com.stable.scoi.extension.isJsonObject +import com.stable.scoi.extention.isJsonArray +import com.stable.scoi.extention.isJsonObject import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/app/src/main/java/com/stable/scoi/extention/String.kt b/app/src/main/java/com/stable/scoi/extention/String.kt new file mode 100644 index 0000000..35ef9e7 --- /dev/null +++ b/app/src/main/java/com/stable/scoi/extention/String.kt @@ -0,0 +1,4 @@ +package com.stable.scoi.extention + +fun String?.isJsonObject(): Boolean = this?.startsWith("{") == true && this.endsWith("}") +fun String?.isJsonArray(): Boolean = this?.startsWith("[") == true && this.endsWith("]") \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/presentation/MainActivity.kt b/app/src/main/java/com/stable/scoi/presentation/MainActivity.kt index 75d147e..6708126 100644 --- a/app/src/main/java/com/stable/scoi/presentation/MainActivity.kt +++ b/app/src/main/java/com/stable/scoi/presentation/MainActivity.kt @@ -1,11 +1,13 @@ package com.stable.scoi.presentation +import android.os.Bundle import androidx.activity.viewModels import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import com.stable.scoi.R import com.stable.scoi.databinding.ActivityMainBinding import com.stable.scoi.presentation.base.BaseActivity +import com.stable.scoi.presentation.base.TransferFragment import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -16,6 +18,7 @@ class MainActivity : BaseActivity - //changeBottomNavigationView(destination.id) - //TODO navController.navigate(R.id.calendarFragment) 이런식으로 navigation 이동 +// when (destination.id) { +// +// } } } } \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/presentation/base/BaseActivity.kt b/app/src/main/java/com/stable/scoi/presentation/base/BaseActivity.kt index 3c6458f..15a78e4 100644 --- a/app/src/main/java/com/stable/scoi/presentation/base/BaseActivity.kt +++ b/app/src/main/java/com/stable/scoi/presentation/base/BaseActivity.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import com.stable.scoi.R import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/stable/scoi/presentation/base/BaseFragment.kt b/app/src/main/java/com/stable/scoi/presentation/base/BaseFragment.kt index 7c36355..700259b 100644 --- a/app/src/main/java/com/stable/scoi/presentation/base/BaseFragment.kt +++ b/app/src/main/java/com/stable/scoi/presentation/base/BaseFragment.kt @@ -52,6 +52,8 @@ abstract class BaseFragment( + FragmentTransferAmountBinding::inflate +) { + override val viewModel: TransferViewModel by viewModels() + + override fun initView() { + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/presentation/base/TransferEvent.kt b/app/src/main/java/com/stable/scoi/presentation/base/TransferEvent.kt new file mode 100644 index 0000000..1078667 --- /dev/null +++ b/app/src/main/java/com/stable/scoi/presentation/base/TransferEvent.kt @@ -0,0 +1,7 @@ +package com.stable.scoi.presentation.base + +sealed class TransferEvent : UiEvent { + object Submit: TransferEvent() + object Cancel: TransferEvent() + object Null: TransferEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/presentation/base/TransferFragment.kt b/app/src/main/java/com/stable/scoi/presentation/base/TransferFragment.kt new file mode 100644 index 0000000..b2a5766 --- /dev/null +++ b/app/src/main/java/com/stable/scoi/presentation/base/TransferFragment.kt @@ -0,0 +1,172 @@ +package com.stable.scoi.presentation.base + +import android.util.Log +import android.view.View +import androidx.core.content.ContextCompat +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.lifecycle.viewModelScope +import androidx.navigation.fragment.findNavController +import com.stable.scoi.R +import com.stable.scoi.databinding.FragmentTransferBinding +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class TransferFragment : BaseFragment( + FragmentTransferBinding::inflate +) { + override val viewModel: TransferViewModel by activityViewModels() + + override fun initView() { + //input + binding.TransferInputNameET.setOnClickListener { + viewModel.onReceiverTypeClicked() + } + + binding.TransferReceiverTypeTV.setOnClickListener { + viewModel.onReceiverTypeChange() + } + + binding.TransferInputExchangeET.isFocusable = false + binding.TransferInputExchangeET.setOnClickListener { + viewModel.setExchange() + viewModel.onExchangeClicked() + } + + binding.TransferInputNameET.text.toString() + + binding.TransferNextTV.setOnClickListener { + val name: String = binding.TransferInputNameET.text.toString() + val address: String = binding.TransferInputAddressET.text.toString() + viewModel.submitReceiver(name,address) + viewModel.onClickNextButton() + } + + + + + + //output + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.receiverType.collect { receiverType -> + when (receiverType) { + ReceiverType.Null -> { + binding.TransferInputNameET.isFocusable = false + } + ReceiverType.Individual -> { + binding.TransferInputNameET.isFocusable = true + binding.TransferInputNameET.isFocusableInTouchMode = true + binding.TransferInputNameET.requestFocus() + binding.TransferReceiverTypeTV.visibility = View.VISIBLE + binding.TransferReceiverTypeTV.text = "개인" + binding.TransferCorpNameENGET.visibility = View.GONE + binding.TransferCorpNameENGTV.visibility = View.GONE + binding.TransferCorpNameKORET.visibility = View.GONE + binding.TransferCorpNameKORTV.visibility = View.GONE + } + ReceiverType.Corporation -> { + binding.TransferInputNameET.isFocusable = true + binding.TransferInputNameET.isFocusableInTouchMode = true + binding.TransferInputNameET.requestFocus() + binding.TransferReceiverTypeTV.visibility = View.VISIBLE + binding.TransferReceiverTypeTV.text = "법인" + binding.TransferCorpNameENGET.visibility = View.VISIBLE + binding.TransferCorpNameENGTV.visibility = View.VISIBLE + binding.TransferCorpNameKORET.visibility = View.VISIBLE + binding.TransferCorpNameKORTV.visibility = View.VISIBLE + } + } + } + } + + launch { + viewModel.receiver.collect { receiver -> + if (receiver.receiverName == "") { + binding.TransferInputNameWarningTV.visibility = View.VISIBLE + } + else { + binding.TransferInputNameWarningTV.visibility = View.GONE + } + + if (receiver.receiverAddress == "") { + binding.TransferInputAddressWarningTV.visibility = View.VISIBLE + } + else { + binding.TransferInputAddressWarningTV.visibility = View.GONE + } + } + } + } + } + + viewModel.nextEvent.observe(viewLifecycleOwner) { nextEvent -> + when (nextEvent) { + TransferEvent.Submit -> { + findNavController().navigate(R.id.transfer_amount_fragment) + } + else -> Unit + } + } + + viewModel.receiverTypeEvent.observe(viewLifecycleOwner) { event -> + when (event) { + TransferEvent.Submit -> { + RecieverTypeBottomSheet().show( + parentFragmentManager, + "BottomSheet" + ) + } + else -> Unit + } + } + + viewModel.exchangeEvent.observe(viewLifecycleOwner) { exchangeEvent -> + when (exchangeEvent) { + TransferEvent.Submit -> { + ExchangeBottomSheet().show( + parentFragmentManager, + "BottomSheet" + ) + } + else -> Unit + } + } + + viewModel.exchangeType.observe(viewLifecycleOwner) { exchange -> + when (exchange) { + Exchange.Upbit -> { + binding.TransferInputExchangeWarningTV.visibility = View.GONE + binding.TransferInputExchangeET.setText("업비트") + binding.TransferInputExchangeET.setTextColor( + ContextCompat.getColor(requireContext(), R.color.black) + ) + } + Exchange.Bithumb -> { + binding.TransferInputExchangeWarningTV.visibility = View.GONE + binding.TransferInputExchangeET.setText("빗썸") + binding.TransferInputExchangeET.setTextColor( + ContextCompat.getColor(requireContext(), R.color.black) + ) + } + Exchange.Binance -> { + binding.TransferInputExchangeWarningTV.visibility = View.GONE + binding.TransferInputExchangeET.setText("Binance") + binding.TransferInputExchangeET.setTextColor( + ContextCompat.getColor(requireContext(), R.color.black) + ) + } + Exchange.Unselected -> { + binding.TransferInputExchangeWarningTV.visibility = View.VISIBLE + } + else -> Unit + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/presentation/base/TransferState.kt b/app/src/main/java/com/stable/scoi/presentation/base/TransferState.kt new file mode 100644 index 0000000..c917cb6 --- /dev/null +++ b/app/src/main/java/com/stable/scoi/presentation/base/TransferState.kt @@ -0,0 +1,6 @@ +package com.stable.scoi.presentation.base + +data class TransferState( + val isLoading: Boolean = false +) : UiState + diff --git a/app/src/main/java/com/stable/scoi/presentation/base/TransferViewModel.kt b/app/src/main/java/com/stable/scoi/presentation/base/TransferViewModel.kt new file mode 100644 index 0000000..a689de0 --- /dev/null +++ b/app/src/main/java/com/stable/scoi/presentation/base/TransferViewModel.kt @@ -0,0 +1,113 @@ +package com.stable.scoi.presentation.base + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import dagger.hilt.android.lifecycle.HiltViewModel +import jakarta.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +@HiltViewModel +class TransferViewModel @Inject constructor() : BaseViewModel( + TransferState() +) { + private val _receiverTypeEvent = MutableLiveData() + val receiverTypeEvent: LiveData = _receiverTypeEvent + + private val _exchangeEvent = MutableLiveData() + val exchangeEvent: LiveData = _exchangeEvent + + private val _exchangeType = MutableLiveData(Exchange.Null) + val exchangeType: LiveData = _exchangeType + + private val _nextEvent = MutableLiveData() + val nextEvent: LiveData = _nextEvent + + + private val _receiverType = MutableStateFlow(ReceiverType.Null) + val receiverType = _receiverType.asStateFlow() + + private val _receiver = MutableStateFlow(Receiver()) + val receiver = _receiver.asStateFlow() + + + //Event + fun onReceiverTypeClicked() { //초기 receiverType 결정 + when (receiverType.value) { + ReceiverType.Null -> { + _receiverTypeEvent.value = TransferEvent.Submit + } + else -> Unit + } + } + + + + + fun submitReceiver(receiverName: String, receiverAddress: String) { + _receiver.value = _receiver.value.copy( + receiverName, + receiverAddress, + _receiverType.value + ) + } + + + + + fun onReceiverTypeChange() { //우측 receiverType 결정 메뉴 + _receiverTypeEvent.value = TransferEvent.Submit + } + + fun onExchangeClicked() { + _exchangeEvent.value = TransferEvent.Submit + } + + fun eventCancel() { + _receiverTypeEvent.value = TransferEvent.Cancel + _exchangeEvent.value = TransferEvent.Cancel + _nextEvent.value = TransferEvent.Cancel + } + + //ReceiverType + fun setRecieverTypeIndividual() { + _receiverType.value = ReceiverType.Individual + Log.d("receiverType", receiverType.value.toString()) + } + + fun setRecieverTypeCorporation() { + _receiverType.value = ReceiverType.Corporation + Log.d("receiverType", receiverType.value.toString()) + + } + + + //ExchangeType + fun setExchangeUpbit() { + _exchangeType.value = Exchange.Upbit + } + fun setExchangeBithumb() { + _exchangeType.value = Exchange.Bithumb + } + fun setExchangeBinance() { + _exchangeType.value = Exchange.Binance + } + fun setExchange() { + _exchangeType.value = Exchange.Unselected + } + + //NextButton + fun onClickNextButton() { + if(_receiver.value.receiverName == null || + _receiver.value.receiverName == "" || + _receiver.value.receiverAddress == null || + _receiver.value.receiverAddress == "" || + _exchangeType.value == Exchange.Null || + _receiverType.value == ReceiverType.Null + ) { + Unit + } + else _nextEvent.value = TransferEvent.Submit + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stable/scoi/presentation/base/componant/ScoiButton.kt b/app/src/main/java/com/stable/scoi/presentation/base/componant/ScoiButton.kt new file mode 100644 index 0000000..31a1a5b --- /dev/null +++ b/app/src/main/java/com/stable/scoi/presentation/base/componant/ScoiButton.kt @@ -0,0 +1,54 @@ +package com.stable.scoi.presentation.base.componant + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import android.widget.TextView +import com.google.android.material.card.MaterialCardView +import com.stable.scoi.R + +class ScoiButton @JvmOverloads constructor( + mContext: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0 +) : FrameLayout(mContext, attrs, defStyle) { + + private val card: MaterialCardView + private val label: TextView + + init { + LayoutInflater.from(context).inflate(R.layout.custom_scoi_button, this, true) + card = findViewById(R.id.card) + label = findViewById(R.id.label) + + val a = context.obtainStyledAttributes(attrs, R.styleable.ScoiButton, defStyle, 0) + + try { + // 텍스트 + label.text = a.getString(R.styleable.ScoiButton_buttonText) ?: label.text + label.setTextColor( + a.getColor(R.styleable.ScoiButton_textColor, label.currentTextColor) + ) + label.setTextAppearance( + a.getResourceId(R.styleable.ScoiButton_textAppearance, R.style.l1m) + ) + + // 배경색 + card.setCardBackgroundColor( + a.getColor(R.styleable.ScoiButton_backgroundColor, resources.getColor(R.color.white)) + ) + + // 코너 + card.radius = a.getDimension(R.styleable.ScoiButton_cornerRadius, 60.toFloat()) + + // Border + card.strokeWidth = a.getDimensionPixelSize(R.styleable.ScoiButton_borderWidth, 0) + card.strokeColor = a.getColor(R.styleable.ScoiButton_borderColor, Color.TRANSPARENT) + + } finally { + a.recycle() + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bithumb_logo.xml b/app/src/main/res/drawable/bithumb_logo.xml new file mode 100644 index 0000000..675acc7 --- /dev/null +++ b/app/src/main/res/drawable/bithumb_logo.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml new file mode 100644 index 0000000..652bb02 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_down.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/ic_back.xml b/app/src/main/res/drawable/ic_back.xml new file mode 100644 index 0000000..e03d686 --- /dev/null +++ b/app/src/main/res/drawable/ic_back.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_close_small.xml b/app/src/main/res/drawable/ic_close_small.xml new file mode 100644 index 0000000..9480435 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_small.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_corporation.xml b/app/src/main/res/drawable/ic_corporation.xml new file mode 100644 index 0000000..791f61f --- /dev/null +++ b/app/src/main/res/drawable/ic_corporation.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_individual.xml b/app/src/main/res/drawable/ic_individual.xml new file mode 100644 index 0000000..c45e097 --- /dev/null +++ b/app/src/main/res/drawable/ic_individual.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_mypage.xml b/app/src/main/res/drawable/ic_mypage.xml new file mode 100644 index 0000000..bd2892e --- /dev/null +++ b/app/src/main/res/drawable/ic_mypage.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/upbit_logo.xml b/app/src/main/res/drawable/upbit_logo.xml new file mode 100644 index 0000000..15a299f --- /dev/null +++ b/app/src/main/res/drawable/upbit_logo.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0e0f315..4f9abb2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -26,17 +26,6 @@ app:layout_constraintTop_toTopOf="parent"> - diff --git a/app/src/main/res/layout/fragment_exchange_bottomsheet.xml b/app/src/main/res/layout/fragment_exchange_bottomsheet.xml new file mode 100644 index 0000000..9ab0fc3 --- /dev/null +++ b/app/src/main/res/layout/fragment_exchange_bottomsheet.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_reciever_type_bottomsheet.xml b/app/src/main/res/layout/fragment_reciever_type_bottomsheet.xml new file mode 100644 index 0000000..2dd3db6 --- /dev/null +++ b/app/src/main/res/layout/fragment_reciever_type_bottomsheet.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_transfer.xml b/app/src/main/res/layout/fragment_transfer.xml new file mode 100644 index 0000000..0e36e86 --- /dev/null +++ b/app/src/main/res/layout/fragment_transfer.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_transfer_amount.xml b/app/src/main/res/layout/fragment_transfer_amount.xml new file mode 100644 index 0000000..a7d220a --- /dev/null +++ b/app/src/main/res/layout/fragment_transfer_amount.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index f714a42..f248218 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -1,6 +1,19 @@ + android:id="@+id/main_graph" + app:startDestination="@id/tansfer_fragment"> + + + + + + \ No newline at end of file