-
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
feat: jetpack navigation 및 바텀시트 프래그먼트 추가 #12 #15
Changes from 13 commits
5cb5fda
20f41c6
c98f524
a746161
f289e9f
6aafc86
112449f
d71499e
dbbff1d
abac61c
d1da6ff
098ca12
645bfce
c2c6d53
fcf6cc5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.woowacourse.staccato.presentation.base | ||
|
||
import android.os.Bundle | ||
import androidx.appcompat.app.AppCompatActivity | ||
import androidx.databinding.DataBindingUtil | ||
import androidx.databinding.ViewDataBinding | ||
|
||
abstract class BindingActivity<T : ViewDataBinding> : AppCompatActivity() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 빙티 덕에 BindingActivity에 대해 처음 알았는 데 앞으로 너무 유용하게 잘 활용할 수 있을 것 같네요! 감사합니다 🫶 |
||
abstract val layoutResourceId: Int | ||
private var _binding: T? = null | ||
val binding | ||
get() = requireNotNull(_binding) | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
_binding = DataBindingUtil.setContentView(this, layoutResourceId) | ||
initStartView(savedInstanceState) | ||
} | ||
|
||
abstract fun initStartView(savedInstanceState: Bundle?) | ||
|
||
override fun onDestroy() { | ||
super.onDestroy() | ||
_binding = null | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.woowacourse.staccato.presentation.base | ||
|
||
import android.os.Bundle | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import androidx.annotation.LayoutRes | ||
import androidx.databinding.DataBindingUtil | ||
import androidx.databinding.ViewDataBinding | ||
import androidx.fragment.app.Fragment | ||
|
||
abstract class BindingFragment<T : ViewDataBinding>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
@LayoutRes private val layoutRes: Int, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
) : Fragment() { | ||
private var _binding: T? = null | ||
protected val binding | ||
get() = requireNotNull(_binding) | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, | ||
container: ViewGroup?, | ||
savedInstanceState: Bundle?, | ||
): View? { | ||
_binding = DataBindingUtil.inflate(inflater, layoutRes, container, false) | ||
binding.lifecycleOwner = viewLifecycleOwner | ||
return binding.root | ||
} | ||
|
||
override fun onDestroyView() { | ||
super.onDestroyView() | ||
_binding = null | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package com.woowacourse.staccato.presentation.main | ||
|
||
import android.os.Bundle | ||
import android.widget.Toast | ||
import androidx.activity.addCallback | ||
import androidx.activity.result.contract.ActivityResultContracts | ||
import androidx.constraintlayout.widget.ConstraintLayout | ||
import androidx.navigation.NavController | ||
import androidx.navigation.NavOptions | ||
import androidx.navigation.fragment.NavHostFragment | ||
import com.google.android.material.bottomsheet.BottomSheetBehavior | ||
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED | ||
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED | ||
import com.woowacourse.staccato.R | ||
import com.woowacourse.staccato.databinding.ActivityMainBinding | ||
import com.woowacourse.staccato.presentation.base.BindingActivity | ||
import com.woowacourse.staccato.presentation.travelcreation.TravelCreationActivity | ||
import com.woowacourse.staccato.presentation.visitcreation.VisitCreationActivity | ||
|
||
class MainActivity : BindingActivity<ActivityMainBinding>() { | ||
override val layoutResourceId: Int | ||
get() = R.layout.activity_main | ||
|
||
private lateinit var behavior: BottomSheetBehavior<ConstraintLayout> | ||
private lateinit var navHostFragment: NavHostFragment | ||
private lateinit var navController: NavController | ||
|
||
private val travelCreationLauncher = | ||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> | ||
if (result.resultCode == RESULT_OK) { | ||
result.data?.let { | ||
Toast.makeText(this, "새로운 여행을 만들었어요!", Toast.LENGTH_SHORT).show() | ||
navigateTo(R.id.travelFragment, R.id.timelineFragment) | ||
} | ||
} | ||
} | ||
Comment on lines
+28
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ActivityResult를 등록하여 런처를 만드는 코드를 아래처럼 메서드로 만들어볼 수 있을 것 같아요! fun createNavigationLauncher(navigteToId: Int, popToId: Int, toastMessage: String) {
return registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
result.data?.let {
Toast.makeText(this, toastMessage, Toast.LENGTH_SHORT).show()
navigateTo(navigateToId, popToId)
}
}
}
} |
||
|
||
val travelUpdateLauncher = | ||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 액티비티를 실행시키는 중복 코드들을 줄여볼 수 있을 것 같아요! |
||
if (result.resultCode == RESULT_OK) { | ||
result.data?.let { | ||
Toast.makeText(this, "여행을 수정했어요!", Toast.LENGTH_SHORT).show() | ||
navigateTo(R.id.travelFragment, R.id.timelineFragment) | ||
} | ||
} | ||
} | ||
|
||
private val visitCreationLauncher = | ||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> | ||
if (result.resultCode == RESULT_OK) { | ||
result.data?.let { | ||
Toast.makeText(this, "새로운 방문 기록을 만들었어요!", Toast.LENGTH_SHORT).show() | ||
navigateTo(R.id.visitFragment, R.id.visitFragment) | ||
} | ||
} | ||
} | ||
|
||
val visitUpdateLauncher = | ||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> | ||
if (result.resultCode == RESULT_OK) { | ||
result.data?.let { | ||
Toast.makeText(this, "방문 기록을 수정했어요!", Toast.LENGTH_SHORT).show() | ||
navigateTo(R.id.visitFragment, R.id.visitFragment) | ||
} | ||
} | ||
} | ||
|
||
override fun initStartView(savedInstanceState: Bundle?) { | ||
setupBottomSheetController() | ||
setupBottomSheetNavigation() | ||
setupBackPressedHandler() | ||
} | ||
|
||
private fun setupBackPressedHandler() { | ||
var backPressedTime = 0L | ||
onBackPressedDispatcher.addCallback { | ||
if (behavior.state == STATE_EXPANDED) { | ||
behavior.state = STATE_COLLAPSED | ||
} else { | ||
handleBackPressedTwice(backPressedTime).also { | ||
backPressedTime = it | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun handleBackPressedTwice(backPressedTime: Long): Long { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앱 종료 전 뒤로가기를 2번 눌러야 종료되도록 처리해주신 점 너무 좋습니다 👍 |
||
val currentTime = System.currentTimeMillis() | ||
if (currentTime - backPressedTime >= 3000L) { | ||
Toast.makeText(this@MainActivity, "버튼을 한 번 더 누르면 종료됩니다.", Toast.LENGTH_SHORT) | ||
.show() | ||
} else { | ||
finish() | ||
} | ||
return currentTime | ||
} | ||
|
||
private fun setupBottomSheetController() { | ||
behavior = BottomSheetBehavior.from(binding.constraintBottomSheet) | ||
navHostFragment = | ||
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment | ||
navController = navHostFragment.navController | ||
} | ||
|
||
private fun setupBottomSheetNavigation() { | ||
binding.btnTravelCreate.setOnClickListener { | ||
TravelCreationActivity.startWithResultLauncher( | ||
this, | ||
travelCreationLauncher, | ||
) | ||
} | ||
binding.btnVisitCreate.setOnClickListener { | ||
VisitCreationActivity.startWithResultLauncher( | ||
this, | ||
visitCreationLauncher, | ||
) | ||
} | ||
binding.btnTimeline.setOnClickListener { | ||
navigateTo(R.id.timelineFragment, R.id.timelineFragment) | ||
} | ||
} | ||
|
||
private fun navigateTo( | ||
navigateToId: Int, | ||
popUpToId: Int, | ||
) { | ||
val navOptions = buildNavOptions(popUpToId) | ||
navController.navigate(navigateToId, null, navOptions) | ||
behavior.state = STATE_EXPANDED | ||
} | ||
|
||
private fun buildNavOptions(popUpToId: Int) = | ||
NavOptions.Builder() | ||
.setLaunchSingleTop(true) | ||
.setPopUpTo(popUpToId, false) | ||
.build() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.woowacourse.staccato.presentation.timeline | ||
|
||
import android.os.Bundle | ||
import android.view.View | ||
import androidx.navigation.fragment.findNavController | ||
import com.woowacourse.staccato.R | ||
import com.woowacourse.staccato.databinding.FragmentTimelineBinding | ||
import com.woowacourse.staccato.presentation.base.BindingFragment | ||
|
||
class TimelineFragment : BindingFragment<FragmentTimelineBinding>(R.layout.fragment_timeline) { | ||
override fun onViewCreated( | ||
view: View, | ||
savedInstanceState: Bundle?, | ||
) { | ||
binding.btnTimeline.setOnClickListener { | ||
findNavController().navigate(R.id.action_timelineFragment_to_travelFragment) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.woowacourse.staccato.presentation.travel | ||
|
||
import android.os.Bundle | ||
import android.view.View | ||
import androidx.navigation.fragment.findNavController | ||
import com.woowacourse.staccato.R | ||
import com.woowacourse.staccato.databinding.FragmentTravelBinding | ||
import com.woowacourse.staccato.presentation.base.BindingFragment | ||
import com.woowacourse.staccato.presentation.main.MainActivity | ||
import com.woowacourse.staccato.presentation.travelupdate.TravelUpdateActivity | ||
|
||
class TravelFragment : BindingFragment<FragmentTravelBinding>(R.layout.fragment_travel) { | ||
override fun onViewCreated( | ||
view: View, | ||
savedInstanceState: Bundle?, | ||
) { | ||
binding.btnTravelUpdate.setOnClickListener { | ||
val travelUpdateLauncher = (activity as MainActivity).travelUpdateLauncher | ||
TravelUpdateActivity.startWithResultLauncher( | ||
this.requireActivity(), | ||
travelUpdateLauncher, | ||
) | ||
// findNavController().navigate(R.id.action_travelFragment_to_travelUpdateFragment) | ||
} | ||
binding.btnVisit.setOnClickListener { | ||
findNavController().navigate(R.id.action_travelFragment_to_visitFragment) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.woowacourse.staccato.presentation.travelcreation | ||
|
||
import android.app.Activity | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.os.Bundle | ||
import androidx.activity.result.ActivityResultLauncher | ||
import com.woowacourse.staccato.R | ||
import com.woowacourse.staccato.databinding.ActivityTravelCreationBinding | ||
import com.woowacourse.staccato.presentation.base.BindingActivity | ||
|
||
class TravelCreationActivity : BindingActivity<ActivityTravelCreationBinding>() { | ||
override val layoutResourceId = R.layout.activity_travel_creation | ||
|
||
override fun initStartView(savedInstanceState: Bundle?) { | ||
binding.btnTravelCreateDone.setOnClickListener { | ||
val resultIntent = Intent() | ||
setResult(Activity.RESULT_OK, resultIntent) | ||
finish() | ||
} | ||
} | ||
|
||
companion object { | ||
fun startWithResultLauncher( | ||
context: Context, | ||
activityLauncher: ActivityResultLauncher<Intent>, | ||
) { | ||
Intent(context, TravelCreationActivity::class.java).apply { | ||
// putExtra(EXTRA_TRAVEL_ID, travelId) | ||
activityLauncher.launch(this) | ||
} | ||
} | ||
} | ||
} |
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.
위의 다른 의존성 코드처럼 주석으로 구분해주신 것 너무 좋네요! 👍