Skip to content

Commit

Permalink
feat: add toolbar & bottom navigation bar (#71)
Browse files Browse the repository at this point in the history
* feat: add toolbar & navigation bar basic setting

* feat: change constraintLayout into LinearLayout to pix location & add TimelineFragment

* feat: edit toolbar navigate icon & actions for login/join Views

* feat: setting basic things for timelineFragment

* feat: add toolbar icon in TimelineFragment

* feat: create Fragments for add bottom navigation bar

* feat: edit activity_main.xml for toolbar/navbar/fragmentContainer view problem

* feat: edit margin in loginFragment

* edit bottom_nav

* feat: chained fragmentContainerView in activityMain

* feat: edit toolbar & bottom navigationbar

* feat: delete sucks itemActiceIndicator

* feat: clear doubleClicked icon focus issue

* chore: add eol

* chore: reflect review

* chore: reflect review

* chore: reflect review
  • Loading branch information
HeewonP825 authored Jan 19, 2024
1 parent 5b9f4cc commit 8def700
Show file tree
Hide file tree
Showing 40 changed files with 1,084 additions and 183 deletions.
3 changes: 2 additions & 1 deletion src/mobile/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ dependencies {
//CircleImageView
implementation ("de.hdodenhof:circleimageview:3.1.0")


//lottie Animation
implementation("com.airbnb.android:lottie:6.0.0")

//bottom navigation bar
implementation ("me.majiajie:pager-bottom-tab-strip:2.4.0")
}
96 changes: 96 additions & 0 deletions src/mobile/app/src/main/java/com/smilegate/Easel/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ package com.smilegate.Easel

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
import android.view.MotionEvent
import android.widget.Toolbar
import androidx.activity.OnBackPressedCallback
import androidx.core.content.ContextCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import com.google.android.material.bottomnavigation.LabelVisibilityMode
import com.google.android.material.navigation.NavigationBarView
import com.smilegate.Easel.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
Expand All @@ -15,6 +23,8 @@ class MainActivity : AppCompatActivity() {
ActivityMainBinding.inflate(layoutInflater)
}

private var lastSelectedIconId: Int? = null

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)
Expand All @@ -30,5 +40,91 @@ class MainActivity : AppCompatActivity() {
isAppearanceLightStatusBars = true
isAppearanceLightNavigationBars = true
}

window.decorView.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white))

val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar_container)
setSupportActionBar(toolbar)

// 타이틀을 비워서 보이지 않도록 설정
supportActionBar?.title = ""
toolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.white))

// 앱 초기 실행 시 홈화면으로 설정
if (savedInstanceState == null) {
binding.navView.selectedItemId = R.id.timelineFragment
lastSelectedIconId = R.id.navigation_home
updateIcon(R.id.navigation_home, R.drawable.ic_solid_home)
}

binding.navView.labelVisibilityMode = NavigationBarView.LABEL_VISIBILITY_UNLABELED

binding.navView.setOnNavigationItemSelectedListener { item ->
onNavigationItemSelected(item)
}
}

private fun updateIcon(itemId: Int, iconResId: Int) {
val item = binding.navView.menu.findItem(itemId)
// 현재 아이콘과 변경하려는 아이콘이 같지 않을 때만 변경
if (item?.icon?.constantState != ContextCompat.getDrawable(this, iconResId)?.constantState) {
item?.setIcon(iconResId)
}
}

fun onNavigationItemSelected(item: MenuItem): Boolean {
val currentIconId = item.itemId

val selectedIcon = getSelectedIcon(currentIconId)
item.setIcon(selectedIcon)

// 이전에 선택된 아이콘 원래 아이콘으로 변경
if (lastSelectedIconId != null && lastSelectedIconId != currentIconId) {
val lastSelectedItem = binding.navView.menu.findItem(lastSelectedIconId!!)
lastSelectedItem?.setIcon(getOriginalIcon(lastSelectedIconId!!))
}

// 이전에 선택된 아이콘 ID 업데이트
lastSelectedIconId = currentIconId

when (currentIconId) {
R.id.navigation_home -> {
findNavController(R.id.nav_host_fragment).navigate(R.id.timelineFragment)
return true
}
R.id.navigation_search -> {
findNavController(R.id.nav_host_fragment).navigate(R.id.searchFragment)
return true
}
R.id.navigation_notice -> {
findNavController(R.id.nav_host_fragment).navigate(R.id.noticeFragment)
return true
}
R.id.navigation_message -> {
findNavController(R.id.nav_host_fragment).navigate(R.id.messageFragment)
return true
}
}
return false
}

private fun getSelectedIcon(itemId: Int): Int {
return when (itemId) {
R.id.navigation_home -> R.drawable.ic_solid_home
R.id.navigation_search -> R.drawable.ic_selected_search
R.id.navigation_notice -> R.drawable.ic_solid_bell
R.id.navigation_message -> R.drawable.ic_solid_mail
else -> throw IllegalArgumentException("Invalid item ID")
}
}

private fun getOriginalIcon(itemId: Int): Int {
return when (itemId) {
R.id.navigation_home -> R.drawable.ic_home
R.id.navigation_search -> R.drawable.ic_search
R.id.navigation_notice -> R.drawable.ic_bell
R.id.navigation_message -> R.drawable.ic_mail
else -> throw IllegalArgumentException("Invalid item ID")
}
}
}
20 changes: 20 additions & 0 deletions src/mobile/app/src/main/java/com/smilegate/Easel/domain/Utils.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.smilegate.Easel.domain

import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import android.view.inputmethod.EditorInfo
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity

fun isDoneAction(actionId: Int, event: KeyEvent?): Boolean {
return actionId == EditorInfo.IME_ACTION_DONE ||
Expand All @@ -12,3 +16,19 @@ fun isDoneAction(actionId: Int, event: KeyEvent?): Boolean {
fun containsSpaceOrNewline(s: CharSequence?): Boolean {
return s?.contains(" ") == true || s?.contains("\n") == true
}


fun handleBackPressed(activity: AppCompatActivity, doubleBackPressed: Boolean): Boolean {
var doubleBackPressedVar = doubleBackPressed

if (doubleBackPressedVar) {
// 두 번째 눌림
activity.finish()
} else {
// 2초 내에 두 번 누르지 않으면 초기화
Handler(Looper.getMainLooper()).postDelayed({
doubleBackPressedVar = false
}, 2000)
}
return true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.smilegate.Easel.presentation.view.Timeline

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.addCallback
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.smilegate.Easel.R
import com.smilegate.Easel.databinding.FragmentStartBinding
import com.smilegate.Easel.databinding.FragmentTimelineBinding

class TimelineFragment : Fragment() {
private lateinit var binding: FragmentTimelineBinding

private lateinit var navController: NavController

private var doubleBackPressed = false

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentTimelineBinding.inflate(inflater, container, false)

val toolbar = requireActivity().findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar_container)
val backButton = toolbar.findViewById<ImageView>(R.id.back_btn)
backButton.visibility = View.GONE

val settingButton = toolbar.findViewById<ImageView>(R.id.else_btn)
settingButton.setImageResource(R.drawable.ic_setting)
settingButton.visibility = View.VISIBLE

navController = findNavController()

// 바텀 네비게이션바 보이기
val bottomNavigation = activity?.findViewById<BottomNavigationView>(R.id.nav_view)
bottomNavigation?.visibility = View.VISIBLE

return binding.root
}

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

// 바텀 네비게이션바 보이기
val bottomNavigation = activity?.findViewById<BottomNavigationView>(R.id.nav_view)
bottomNavigation?.visibility = View.VISIBLE

// 뒤로가기 버튼을 처리하는 부분
view.isFocusableInTouchMode = true
view.requestFocus()
view.setOnKeyListener { _, keyCode, _ ->
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (isCurrentFragment()) {
// 현재 프래그먼트에서 뒤로가기 버튼 처리
if (doubleBackPressed) {
// 두 번째 눌림
requireActivity().finish()
} else {
// 첫 번째 눌림
doubleBackPressed = true
// 2초 내에 두 번 누르지 않으면 초기화
Handler(Looper.getMainLooper()).postDelayed({
doubleBackPressed = false
}, 2000)
}
return@setOnKeyListener true
}
}
false
}
}

private fun isCurrentFragment(): Boolean {
return true
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.smilegate.Easel.presentation.view.join

import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
Expand All @@ -9,8 +10,10 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
Expand All @@ -32,13 +35,29 @@ class AskNameFragment : Fragment() {

navController = findNavController()

binding.askNameFragmentJoinBtn.setOnClickListener {
navController.navigate(R.id.action_askNameFragment_to_timelineFragment)
hideKeyboard()
}

return binding.root
}

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

val toolbar = requireActivity().findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar_container)
val backButton = toolbar.findViewById<ImageView>(R.id.back_btn)
backButton.visibility = View.VISIBLE

backButton.setOnClickListener {
findNavController().navigateUp()
}

val settingButton = toolbar.findViewById<ImageView>(R.id.else_btn)
settingButton.setImageResource(R.drawable.ic_setting)
settingButton.visibility = View.GONE

binding.askNameFragmentIdField.addTextChangedListener(object : TextWatcher {
// 텍스트 변경 전에 호출되는 메소드
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
Expand Down Expand Up @@ -78,4 +97,15 @@ class AskNameFragment : Fragment() {
nextButton?.setTextColor(textColor)
}
}

private fun hideKeyboard() {
val inputMethodManager =
requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

// 현재 포커스된 뷰에서 키패드를 감춥니다.
val focusedView = requireActivity().currentFocus
focusedView?.let {
inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.smilegate.Easel.presentation.view.join

import android.graphics.Color
import android.graphics.PorterDuff
import android.os.Bundle
import android.text.Editable
import android.text.SpannableString
Expand All @@ -11,9 +12,13 @@ import android.text.style.ClickableSpan
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.ImageView
import android.widget.Toast
import android.widget.Toolbar
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
Expand Down Expand Up @@ -62,6 +67,15 @@ class CreateAccountFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val toolbar = requireActivity().findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar_container)
val backButton = toolbar.findViewById<ImageView>(R.id.back_btn)
backButton.visibility = View.VISIBLE

backButton.setOnClickListener {
findNavController().navigateUp()
backButton.visibility = GONE
}

binding.createAccountInfoField.setOnFocusChangeListener { _, hasFocus ->
if (!hasFocus) {
validateEmail()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.navigation.NavController
Expand Down Expand Up @@ -50,6 +51,14 @@ class NeedPasswordFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val toolbar = requireActivity().findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar_container)
val backButton = toolbar.findViewById<ImageView>(R.id.back_btn)
backButton.visibility = View.VISIBLE

backButton.setOnClickListener {
findNavController().navigateUp()
}

binding.needPasswordFragmentPwShowBtn.setOnClickListener {
passwordVisibility()
}
Expand Down Expand Up @@ -125,7 +134,7 @@ class NeedPasswordFragment : Fragment() {
private fun validatePassword() {
val password = binding.needPasswordFragmentPwField.text.toString()

if (password.length < 8) {
if (password.length < maxPasswordLength) {
// 비밀번호가 8자 미만인 경우
val pwColorResourceId = ContextCompat.getColor(requireContext(), R.color.Red_200)
binding.needPasswordFragmentPwField.setTextColor(pwColorResourceId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ class ProfileImageFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val toolbar = requireActivity().findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar_container)
val backButton = toolbar.findViewById<ImageView>(R.id.back_btn)
backButton.visibility = View.VISIBLE

backButton.setOnClickListener {
findNavController().navigateUp()
}
}

// override fun onDestroyView() {
Expand Down
Loading

0 comments on commit 8def700

Please sign in to comment.