Simple screens and logic with Navigation Component

This commit is contained in:
2021-07-12 00:17:18 +03:00
parent 1c773df3e1
commit 026c0c74af
25 changed files with 650 additions and 142 deletions
Binary file not shown.
-18
View File
@@ -1,18 +0,0 @@
{
"version": 2,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.meloda.fast",
"variantName": "processReleaseResources",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
]
}
@@ -0,0 +1,251 @@
package com.meloda.fast.base
import android.content.Intent
import android.util.SparseArray
import androidx.core.util.forEach
import androidx.core.util.set
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.meloda.fast.R
/*
fun BottomNavigationView.setupWithNavController(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
dataManager: DataManager,
containerId: Int,
intent: Intent
): LiveData<NavController> {
// Map of tags
val graphIdToTagMap = SparseArray<String>()
// Result. Mutable live data with the selected controlled
val selectedNavController = MutableLiveData<NavController>()
var firstFragmentGraphId = 0
// First create a NavHostFragment for each NavGraph ID
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Obtain its id
val graphId = navHostFragment.navController.graph.id
if (index == 0) {
firstFragmentGraphId = graphId
}
// Save to the map
graphIdToTagMap[graphId] = fragmentTag
// Attach or detach nav host fragment depending on whether it's the selected item.
if (this.selectedItemId == graphId) {
// Update livedata with the selected graph
selectedNavController.value = navHostFragment.navController
attachNavHostFragment(fragmentManager, navHostFragment, index == 0)
} else {
detachNavHostFragment(fragmentManager, navHostFragment)
}
}
// Now connect selecting an item with swapping Fragments
var selectedItemTag = graphIdToTagMap[this.selectedItemId]
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
var isOnFirstFragment = selectedItemTag == firstFragmentTag
// When a navigation item is selected
setOnNavigationItemSelectedListener { item ->
// Don't do anything if the state is state has already been saved.
if (fragmentManager.isStateSaved) {
false
} else {
val navController = (fragmentManager.findFragmentByTag(selectedItemTag) as NavHostFragment).navController
navController.popBackStack(navController.graph.startDestination, false)
if (selectedItemTag != graphIdToTagMap[item.itemId]) {
val listCheck = listOf(R.id.contacts, R.id.chats)
val newlySelectedItemTag = if (listCheck.contains(item.itemId) && dataManager.token.isBlank()) graphIdToTagMap[R.id.signIn] else graphIdToTagMap[item.itemId]
// Pop everything above the first fragment (the "fixed start destination")
fragmentManager.popBackStack(
firstFragmentTag,
FragmentManager.POP_BACK_STACK_INCLUSIVE
)
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag) as NavHostFragment
// Exclude the first fragment tag because it's always in the back stack.
if (firstFragmentTag != newlySelectedItemTag) {
// Commit a transaction that cleans the back stack and adds the first fragment
// to it, creating the fixed started destination.
fragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.nav_default_enter_anim,
R.anim.nav_default_exit_anim,
R.anim.nav_default_pop_enter_anim,
R.anim.nav_default_pop_exit_anim
)
.attach(selectedFragment)
.setPrimaryNavigationFragment(selectedFragment)
.apply {
// Detach all other Fragments
graphIdToTagMap.forEach { _, fragmentTagIter ->
if (fragmentTagIter != newlySelectedItemTag) {
detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
}
}
}
.addToBackStack(firstFragmentTag)
.setReorderingAllowed(true)
.commit()
}
selectedItemTag = newlySelectedItemTag
isOnFirstFragment = selectedItemTag == firstFragmentTag
selectedNavController.value = selectedFragment.navController
true
} else {
false
}
}
}
setOnNavigationItemReselectedListener { item ->
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag) as NavHostFragment
val navController = selectedFragment.navController
// Pop the back stack to the start destination of the current navController graph
if (selectedItemTag != graphIdToTagMap[item.itemId] && dataManager.token.isNotBlank()) {
fragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.nav_default_enter_anim,
R.anim.nav_default_exit_anim,
R.anim.nav_default_pop_enter_anim,
R.anim.nav_default_pop_exit_anim
)
.attach(selectedFragment)
.setPrimaryNavigationFragment(selectedFragment)
.apply {
// Detach all other Fragments
graphIdToTagMap.forEach { _, fragmentTagIter ->
if (fragmentTagIter != newlySelectedItemTag) {
detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
}
}
}
.addToBackStack(firstFragmentTag)
.setReorderingAllowed(true)
.commit()
selectedItemTag = newlySelectedItemTag
isOnFirstFragment = selectedItemTag == firstFragmentTag
selectedNavController.value = selectedFragment.navController
} else navController.popBackStack(navController.graph.startDestination, false)
}
// Optional: on item reselected, pop back stack to the destination of the graph
setupDeepLinks(navGraphIds, fragmentManager, containerId, intent)
// Finally, ensure that we update our BottomNavigationView when the back stack changes
fragmentManager.addOnBackStackChangedListener {
if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) {
this.selectedItemId = firstFragmentGraphId
}
// Reset the graph if the currentDestination is not valid (happens when the back
// stack is popped after using the back button).
selectedNavController.value?.let { controller ->
if (controller.currentDestination == null) {
controller.navigate(controller.graph.id)
}
}
}
return selectedNavController
}
private fun BottomNavigationView.setupDeepLinks(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent
) {
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Handle Intent
if (navHostFragment.navController.handleDeepLink(intent) &&
selectedItemId != navHostFragment.navController.graph.id
) {
this.selectedItemId = navHostFragment.navController.graph.id
}
}
}
private fun detachNavHostFragment(
fragmentManager: FragmentManager,
navHostFragment: NavHostFragment
) {
fragmentManager.beginTransaction()
.detach(navHostFragment)
.commitNow()
}
private fun attachNavHostFragment(
fragmentManager: FragmentManager,
navHostFragment: NavHostFragment,
isPrimaryNavFragment: Boolean
) {
fragmentManager.beginTransaction()
.attach(navHostFragment)
.apply {
if (isPrimaryNavFragment) {
setPrimaryNavigationFragment(navHostFragment)
}
}
.commitNow()
}
private fun obtainNavHostFragment(
fragmentManager: FragmentManager,
fragmentTag: String,
navGraphId: Int,
containerId: Int,
): NavHostFragment {
// If the Nav Host fragment exists, return it
val existingFragment = fragmentManager.findFragmentByTag(fragmentTag) as NavHostFragment?
existingFragment?.let { return it }
// Otherwise, create it and return it.
val navHostFragment = NavHostFragment.create(navGraphId)
fragmentManager.beginTransaction()
.add(containerId, navHostFragment, fragmentTag)
.commitNow()
return navHostFragment
}
private fun FragmentManager.isOnBackStack(backStackName: String): Boolean {
val backStackCount = backStackEntryCount
for (index in 0 until backStackCount) {
if (getBackStackEntryAt(index).name == backStackName) {
return true
}
}
return false
}
private fun getFragmentTag(index: Int) = "bottomNavigation#$index"
*/
@@ -27,4 +27,7 @@ abstract class BaseVM : ViewModel() {
) )
} }
}.also { it.invokeOnCompletion { viewModelScope.launch { onEnd?.invoke() } } } }.also { it.invokeOnCompletion { viewModelScope.launch { onEnd?.invoke() } } }
protected suspend fun <T : VKEvent> sendEvent(event: T) = tasksEventChannel.send(event)
} }
@@ -6,3 +6,6 @@ data class ShowDialogInfoEvent(
val positiveBtn: String? = null, val positiveBtn: String? = null,
val negativeBtn: String? = null val negativeBtn: String? = null
) : VKEvent() ) : VKEvent()
object StartProgressEvent : VKEvent()
object StopProgressEvent : VKEvent()
@@ -4,6 +4,7 @@ import android.content.Intent
import android.util.SparseArray import android.util.SparseArray
import androidx.core.util.forEach import androidx.core.util.forEach
import androidx.core.util.set import androidx.core.util.set
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@@ -11,6 +12,7 @@ import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import com.meloda.fast.R import com.meloda.fast.R
import com.meloda.fast.UserConfig
/** /**
* Manages the various graphs needed for a [BottomNavigationView]. * Manages the various graphs needed for a [BottomNavigationView].
@@ -22,7 +24,6 @@ object NavigationExtensions {
fun BottomNavigationView.setupWithNavController( fun BottomNavigationView.setupWithNavController(
navGraphIds: List<Int>, navGraphIds: List<Int>,
fragmentManager: FragmentManager, fragmentManager: FragmentManager,
// dataManager: DataManager,
containerId: Int, containerId: Int,
intent: Intent intent: Intent
): LiveData<NavController> { ): LiveData<NavController> {
@@ -71,8 +72,7 @@ object NavigationExtensions {
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId] val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
var isOnFirstFragment = selectedItemTag == firstFragmentTag var isOnFirstFragment = selectedItemTag == firstFragmentTag
// When a navigation item is selected setOnItemSelectedListener { item ->
setOnNavigationItemSelectedListener { item ->
// Don't do anything if the state is state has already been saved. // Don't do anything if the state is state has already been saved.
if (fragmentManager.isStateSaved) { if (fragmentManager.isStateSaved) {
false false
@@ -81,12 +81,9 @@ object NavigationExtensions {
(fragmentManager.findFragmentByTag(selectedItemTag) as NavHostFragment).navController (fragmentManager.findFragmentByTag(selectedItemTag) as NavHostFragment).navController
navController.popBackStack(navController.graph.startDestination, false) navController.popBackStack(navController.graph.startDestination, false)
if (selectedItemTag != graphIdToTagMap[item.itemId]) { if (selectedItemTag != graphIdToTagMap[item.itemId]) {
// val listCheck = listOf(R.id.contacts, R.id.chats) val newlySelectedItemTag = //graphIdToTagMap[item.itemId]
val newlySelectedItemTag = if (!UserConfig.isLoggedIn()) graphIdToTagMap[R.id.login] else graphIdToTagMap[item.itemId]
//if (listCheck.contains(item.itemId) && dataManager.token.isBlank()) graphIdToTagMap[R.id.signIn] else
graphIdToTagMap[item.itemId]
// Pop everything above the first fragment (the "fixed start destination")
fragmentManager.popBackStack( fragmentManager.popBackStack(
firstFragmentTag, firstFragmentTag,
FragmentManager.POP_BACK_STACK_INCLUSIVE FragmentManager.POP_BACK_STACK_INCLUSIVE
@@ -128,7 +125,8 @@ object NavigationExtensions {
} }
} }
} }
setOnNavigationItemReselectedListener { item ->
setOnItemReselectedListener { item ->
val newlySelectedItemTag = graphIdToTagMap[item.itemId] val newlySelectedItemTag = graphIdToTagMap[item.itemId]
val selectedFragment = val selectedFragment =
fragmentManager.findFragmentByTag(newlySelectedItemTag) as NavHostFragment fragmentManager.findFragmentByTag(newlySelectedItemTag) as NavHostFragment
@@ -257,5 +255,12 @@ object NavigationExtensions {
return false return false
} }
val FragmentManager.visibleFragments
get(): List<Fragment> {
val visibleFragments = arrayListOf<Fragment>()
fragments.forEach { if (it.isVisible) visibleFragments.add(it) }
return visibleFragments
}
private fun getFragmentTag(index: Int) = "bottomNavigation#$index" private fun getFragmentTag(index: Int) = "bottomNavigation#$index"
} }
@@ -0,0 +1,21 @@
package com.meloda.fast.fragment.friends
import android.os.Bundle
import android.view.View
import android.viewbinding.library.fragment.viewBinding
import com.meloda.fast.R
import com.meloda.fast.base.BaseFragment
import com.meloda.fast.databinding.FragmentFriendsBinding
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class FriendsFragment : BaseFragment(R.layout.fragment_friends) {
private val binding: FragmentFriendsBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
@@ -0,0 +1,21 @@
package com.meloda.fast.fragment.important
import android.os.Bundle
import android.view.View
import android.viewbinding.library.fragment.viewBinding
import com.meloda.fast.R
import com.meloda.fast.base.BaseFragment
import com.meloda.fast.databinding.FragmentImportantBinding
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class ImportantFragment : BaseFragment(R.layout.fragment_important) {
private val binding: FragmentImportantBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
@@ -1,5 +1,6 @@
package com.meloda.fast.fragment.login package com.meloda.fast.fragment.login
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.Gravity import android.view.Gravity
import android.view.KeyEvent import android.view.KeyEvent
@@ -7,9 +8,11 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.viewbinding.library.fragment.viewBinding import android.viewbinding.library.fragment.viewBinding
import android.webkit.CookieManager
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
@@ -21,11 +24,15 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.meloda.fast.R import com.meloda.fast.R
import com.meloda.fast.base.BaseVMFragment import com.meloda.fast.base.BaseVMFragment
import com.meloda.fast.base.viewmodel.StartProgressEvent
import com.meloda.fast.base.viewmodel.StopProgressEvent
import com.meloda.fast.base.viewmodel.VKEvent import com.meloda.fast.base.viewmodel.VKEvent
import com.meloda.fast.databinding.FragmentLoginBinding import com.meloda.fast.databinding.FragmentLoginBinding
import com.meloda.fast.fragment.main.MainFragment
import com.meloda.fast.util.KeyboardUtils import com.meloda.fast.util.KeyboardUtils
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.* import java.util.*
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
@@ -45,7 +52,7 @@ class LoginFragment : BaseVMFragment<LoginVM>(R.layout.fragment_login) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.checkUserSession() (parentFragment?.parentFragment as? MainFragment)?.bottomBar?.isVisible = false
prepareViews() prepareViews()
@@ -63,16 +70,49 @@ class LoginFragment : BaseVMFragment<LoginVM>(R.layout.fragment_login) {
when (event) { when (event) {
is ShowCaptchaDialog -> showCaptchaDialog(event.captchaImage, event.captchaSid) is ShowCaptchaDialog -> showCaptchaDialog(event.captchaImage, event.captchaSid)
is GoToValidationEvent -> goToValidation(event.redirectUrl) is GoToValidationEvent -> goToValidation(event.redirectUrl)
GoToMainEvent -> goToMain() is GoToMainEvent -> goToMain(event.haveAuthorized)
StartProgressEvent -> onProgressStarted()
StopProgressEvent -> onProgressEnded()
} }
} }
private fun onProgressStarted() {
binding.loginContainer.isVisible = false
binding.passwordContainer.isVisible = false
binding.auth.isVisible = false
binding.progress.isVisible = true
}
private fun onProgressEnded() {
binding.loginContainer.isVisible = true
binding.passwordContainer.isVisible = true
binding.auth.isVisible = true
binding.progress.isVisible = false
}
private fun prepareViews() { private fun prepareViews() {
prepareWebView()
prepareEmailEditText() prepareEmailEditText()
preparePasswordEditText() preparePasswordEditText()
prepareAuthButton() prepareAuthButton()
} }
@SuppressLint("SetJavaScriptEnabled")
private fun prepareWebView() {
with(binding.webView) {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.loadsImagesAutomatically = false
settings.userAgentString = "Chrome/41.0.2228.0 Safari/537.36"
clearCache(true)
}
val cookieManager = CookieManager.getInstance()
cookieManager.removeAllCookies(null)
cookieManager.flush()
cookieManager.setAcceptCookie(false)
}
private fun prepareEmailEditText() { private fun prepareEmailEditText() {
binding.loginInput.addTextChangedListener { binding.loginInput.addTextChangedListener {
if (!binding.loginLayout.error.isNullOrBlank()) binding.loginLayout.error = "" if (!binding.loginLayout.error.isNullOrBlank()) binding.loginLayout.error = ""
@@ -98,21 +138,30 @@ class LoginFragment : BaseVMFragment<LoginVM>(R.layout.fragment_login) {
(event.action == KeyEvent.ACTION_DOWN && (event.keyCode == KeyEvent.KEYCODE_ENTER || event.keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)) (event.action == KeyEvent.ACTION_DOWN && (event.keyCode == KeyEvent.KEYCODE_ENTER || event.keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER))
) { ) {
KeyboardUtils.hideKeyboardFrom(binding.passwordInput) KeyboardUtils.hideKeyboardFrom(binding.passwordInput)
binding.authorize.performClick() binding.auth.performClick()
true true
} else false } else false
} }
} }
private fun prepareAuthButton() { private fun prepareAuthButton() {
binding.authorize.setOnClickListener { binding.auth.setOnClickListener {
if (binding.progress.isVisible) return@setOnClickListener
val loginString = binding.loginInput.text.toString().trim() val loginString = binding.loginInput.text.toString().trim()
val passwordString = binding.passwordInput.text.toString().trim() val passwordString = binding.passwordInput.text.toString().trim()
if (!validateInputData(loginString, passwordString)) return@setOnClickListener if (!validateInputData(loginString, passwordString)) return@setOnClickListener
viewModel.login(requireContext(), loginString, passwordString)
KeyboardUtils.hideKeyboardFrom(it) KeyboardUtils.hideKeyboardFrom(it)
lifecycleScope.launch {
viewModel.login(
binding.webView,
loginString,
passwordString
)
}
} }
} }
@@ -193,17 +242,18 @@ class LoginFragment : BaseVMFragment<LoginVM>(R.layout.fragment_login) {
builder.setPositiveButton(android.R.string.ok) { _, _ -> builder.setPositiveButton(android.R.string.ok) { _, _ ->
val captchaCode = captchaCodeEditText.text.toString().trim() val captchaCode = captchaCodeEditText.text.toString().trim()
lifecycleScope.launch {
viewModel.login( viewModel.login(
requireContext(), binding.webView,
lastEmail, lastEmail,
lastPassword, lastPassword,
"&captcha_sid=$captchaSid&captcha_key=$captchaCode" "&captcha_sid=$captchaSid&captcha_key=$captchaCode"
) )
} }
}
builder.setTitle(R.string.input_captcha) builder.setTitle(R.string.input_captcha)
builder.show() builder.show()
} }
private fun goToValidation(redirectUrl: String) { private fun goToValidation(redirectUrl: String) {
@@ -213,8 +263,12 @@ class LoginFragment : BaseVMFragment<LoginVM>(R.layout.fragment_login) {
) )
} }
private fun goToMain() { private fun goToMain(haveAuthorized: Boolean) {
lifecycleScope.launch {
if (haveAuthorized) delay(500)
findNavController().navigate(R.id.toMain) findNavController().navigate(R.id.toMain)
} }
}
} }
@@ -1,10 +1,6 @@
package com.meloda.fast.fragment.login package com.meloda.fast.fragment.login
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.ViewGroup
import android.webkit.CookieManager
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
@@ -12,34 +8,34 @@ import androidx.lifecycle.viewModelScope
import com.meloda.fast.UserConfig import com.meloda.fast.UserConfig
import com.meloda.fast.api.VKAuth import com.meloda.fast.api.VKAuth
import com.meloda.fast.base.viewmodel.BaseVM import com.meloda.fast.base.viewmodel.BaseVM
import com.meloda.fast.base.viewmodel.StartProgressEvent
import com.meloda.fast.base.viewmodel.StopProgressEvent
import com.meloda.fast.base.viewmodel.VKEvent import com.meloda.fast.base.viewmodel.VKEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Jsoup import org.jsoup.Jsoup
class LoginVM : BaseVM() { class LoginVM : BaseVM() {
fun login( private var isWebViewPrepared = true
context: Context,
suspend fun login(
webView: WebView,
email: String, email: String,
password: String, password: String,
captcha: String = "" captcha: String = ""
) { ) {
sendEvent(StartProgressEvent)
val urlToGo = VKAuth.getDirectAuthUrl(email, password, captcha) val urlToGo = VKAuth.getDirectAuthUrl(email, password, captcha)
// val builder = AlertDialog.Builder(context) if (isWebViewPrepared) {
isWebViewPrepared = false
val webView = createWebView(context)
webView.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
// builder.setTitle("Auth")
// builder.setView(webView)
// builder.show()
webView.addJavascriptInterface(WebViewHandlerInterface(), "HtmlHandler") webView.addJavascriptInterface(WebViewHandlerInterface(), "HtmlHandler")
webView.webViewClient = object : WebViewClient() { webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) { override fun onPageFinished(view: WebView?, url: String?) {
webView.loadUrl( webView.loadUrl(
@@ -48,32 +44,17 @@ class LoginVM : BaseVM() {
) )
} }
} }
}
webView.loadUrl(urlToGo) webView.loadUrl(urlToGo)
} }
@SuppressLint("SetJavaScriptEnabled")
private fun createWebView(context: Context): WebView {
val loginWebView = WebView(context)
loginWebView.settings.javaScriptEnabled = true
loginWebView.settings.domStorageEnabled = true
loginWebView.settings.loadsImagesAutomatically = false
loginWebView.settings.userAgentString = "Chrome/41.0.2228.0 Safari/537.36"
loginWebView.clearCache(true)
val cookieManager = CookieManager.getInstance()
cookieManager.removeAllCookies(null)
cookieManager.flush()
cookieManager.setAcceptCookie(false)
return loginWebView
}
@Suppress("MoveVariableDeclarationIntoWhen") @Suppress("MoveVariableDeclarationIntoWhen")
private fun checkResponse(response: JSONObject) { private fun checkResponse(response: JSONObject) {
viewModelScope.launch { viewModelScope.launch(Dispatchers.Default) {
delay(1500)
sendEvent(StopProgressEvent)
if (response.has("error")) { if (response.has("error")) {
val errorString = response.optString("error") val errorString = response.optString("error")
@@ -82,33 +63,12 @@ class LoginVM : BaseVM() {
val redirectUrl = response.optString("redirect_uri") val redirectUrl = response.optString("redirect_uri")
tasksEventChannel.send(GoToValidationEvent(redirectUrl)) tasksEventChannel.send(GoToValidationEvent(redirectUrl))
// val bundle = Bundle()
// bundle.putString("url", redirectUrl)
/* fragment.setFragmentResultListener("validation") { _, bundle ->
val userId = bundle.getInt("userId")
val token = bundle.getString("token") ?: ""
saveUserData(userId, token)
openMainScreen()
}
fragment.parentFragmentManager.beginTransaction()
.replace(
R.id.fragmentContainer,
ValidationFragment().apply { arguments = bundle })
.addToBackStack("")
.commit()*/
} }
"need_captcha" -> { "need_captcha" -> {
val captchaImage = response.optString("captcha_img") val captchaImage = response.optString("captcha_img")
val captchaSid = response.optString("captcha_sid") val captchaSid = response.optString("captcha_sid")
tasksEventChannel.send(ShowCaptchaDialog(captchaImage, captchaSid)) tasksEventChannel.send(ShowCaptchaDialog(captchaImage, captchaSid))
// showCaptchaDialog(captchaImage, captchaSid)
} }
} }
} else { } else {
@@ -118,11 +78,7 @@ class LoginVM : BaseVM() {
UserConfig.accessToken = accessToken UserConfig.accessToken = accessToken
UserConfig.userId = userId UserConfig.userId = userId
tasksEventChannel.send(GoToMainEvent) tasksEventChannel.send(GoToMainEvent())
// openMainScreen()
// onResponseListener?.onResponse(null)
} }
} }
} }
@@ -134,11 +90,7 @@ class LoginVM : BaseVM() {
UserConfig.accessToken = accessToken UserConfig.accessToken = accessToken
UserConfig.userId = userId UserConfig.userId = userId
tasksEventChannel.send(GoToMainEvent) tasksEventChannel.send(GoToMainEvent())
}
fun checkUserSession() = viewModelScope.launch {
if (UserConfig.isLoggedIn()) tasksEventChannel.send(GoToMainEvent)
} }
inner class WebViewHandlerInterface { inner class WebViewHandlerInterface {
@@ -158,4 +110,4 @@ class LoginVM : BaseVM() {
data class ShowCaptchaDialog(val captchaImage: String, val captchaSid: String) : VKEvent() data class ShowCaptchaDialog(val captchaImage: String, val captchaSid: String) : VKEvent()
data class GoToValidationEvent(val redirectUrl: String) : VKEvent() data class GoToValidationEvent(val redirectUrl: String) : VKEvent()
object GoToMainEvent : VKEvent() data class GoToMainEvent(val haveAuthorized: Boolean = true) : VKEvent()
@@ -4,7 +4,9 @@ import android.os.Bundle
import android.view.View import android.view.View
import android.viewbinding.library.fragment.viewBinding import android.viewbinding.library.fragment.viewBinding
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.meloda.fast.R import com.meloda.fast.R
import com.meloda.fast.UserConfig
import com.meloda.fast.base.BaseVMFragment import com.meloda.fast.base.BaseVMFragment
import com.meloda.fast.databinding.FragmentMainBinding import com.meloda.fast.databinding.FragmentMainBinding
import com.meloda.fast.extensions.NavigationExtensions.setupWithNavController import com.meloda.fast.extensions.NavigationExtensions.setupWithNavController
@@ -21,18 +23,29 @@ class MainFragment : BaseVMFragment<MainVM>(R.layout.fragment_main) {
if (savedInstanceState == null) setupBottomBar() if (savedInstanceState == null) setupBottomBar()
if (!UserConfig.isLoggedIn()) findNavController().navigate(R.id.toLogin)
} }
private fun setupBottomBar() { private fun setupBottomBar() {
val navGraphIds = listOf(R.id.messages, R.id.friends) val navGraphIds = listOf(
R.navigation.messages,
R.navigation.friends,
R.navigation.important,
R.navigation.login
)
binding.bottomBar.setupWithNavController( with(binding.bottomBar) {
navGraphIds = listOf(), selectedItemId = R.id.messages
setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = childFragmentManager, fragmentManager = childFragmentManager,
containerId = R.id.fragmentContainer, containerId = R.id.fragmentContainer,
intent = requireActivity().intent intent = requireActivity().intent
) )
} }
}
val bottomBar get() = binding.bottomBar
} }
@@ -1,9 +1,21 @@
package com.meloda.fast.fragment.messages package com.meloda.fast.fragment.messages
import android.os.Bundle
import android.view.View
import android.viewbinding.library.fragment.viewBinding
import com.meloda.fast.R import com.meloda.fast.R
import com.meloda.fast.base.BaseFragment import com.meloda.fast.base.BaseFragment
import com.meloda.fast.databinding.FragmentConversationsBinding
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint
class ConversationsFragment : BaseFragment(R.layout.fragment_conversations) { class ConversationsFragment : BaseFragment(R.layout.fragment_conversations) {
private val binding: FragmentConversationsBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
} }
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
@@ -4,6 +4,11 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="conversations" />
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
+8 -3
View File
@@ -5,20 +5,25 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="friends" />
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent" android:background="@android:color/transparent"
app:elevation="0dp"> app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout <com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:background="@drawable/toolbar_background"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:background="@drawable/toolbar_background"
app:layout_scrollFlags="scroll|enterAlways"> app:layout_scrollFlags="scroll|enterAlways">
<include layout="@layout/toolbar" /> <include layout="@layout/toolbar" />
@@ -3,4 +3,9 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="important" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
+18 -2
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.appcompat.widget.LinearLayoutCompat <androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/loginRoot" android:id="@+id/loginRoot"
@@ -8,6 +9,12 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<WebView
android:id="@+id/webView"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone" />
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -16,6 +23,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
@@ -37,6 +45,14 @@
app:tint="?colorAccent" /> app:tint="?colorAccent" />
</FrameLayout> </FrameLayout>
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout <LinearLayout
android:id="@+id/loginContainer" android:id="@+id/loginContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -110,7 +126,7 @@
</LinearLayout> </LinearLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/authorize" android:id="@+id/auth"
style="@style/Widget.MaterialButton" style="@style/Widget.MaterialButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="60dp" android:layout_height="60dp"
@@ -2,17 +2,17 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/navigationFriends" android:id="@id/friends"
android:icon="@drawable/ic_people_outline" android:icon="@drawable/ic_people_outline"
android:title="@string/navigation_friends" /> android:title="@string/navigation_friends" />
<item <item
android:id="@+id/navigationConversations" android:id="@id/messages"
android:icon="@drawable/ic_message_outline" android:icon="@drawable/ic_message_outline"
android:title="@string/navigation_chats" /> android:title="@string/navigation_chats" />
<item <item
android:id="@+id/navigationImportant" android:id="@id/important"
android:icon="@drawable/ic_star_border" android:icon="@drawable/ic_star_border"
android:title="@string/navigation_important" /> android:title="@string/navigation_important" />
+9 -1
View File
@@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android" <navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/friends"> xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/friends"
app:startDestination="@+id/friendsFragment">
<fragment
android:id="@+id/friendsFragment"
android:name="com.meloda.fast.fragment.friends.FriendsFragment"
android:label="FriendsFragment"
tools:layout="@layout/fragment_friends" />
</navigation> </navigation>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/important"
app:startDestination="@id/importantFragment">
<fragment
android:id="@+id/importantFragment"
android:name="com.meloda.fast.fragment.important.ImportantFragment"
android:label="ImportantFragment"
tools:layout="@layout/fragment_important" />
</navigation>
+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/login"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="com.meloda.fast.fragment.login.LoginFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_login">
<action
android:id="@+id/toMain"
app:destination="@id/mainFragment"
app:popUpTo="@id/loginFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/toValidation"
app:destination="@id/validationFragment" />
</fragment>
<fragment
android:id="@+id/validationFragment"
android:name="com.meloda.fast.fragment.login.ValidationFragment"
android:label="ValidationFragment"
tools:layout="@layout/fragment_validation">
<action
android:id="@+id/toLogin"
app:destination="@id/loginFragment"
app:popUpTo="@id/validationFragment"
app:popUpToInclusive="true" />
</fragment>
</navigation>
+8 -2
View File
@@ -3,13 +3,19 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main" android:id="@+id/main"
app:startDestination="@id/loginFragment"> app:startDestination="@id/mainFragment">
<fragment <fragment
android:id="@+id/mainFragment" android:id="@+id/mainFragment"
android:name="com.meloda.fast.fragment.main.MainFragment" android:name="com.meloda.fast.fragment.main.MainFragment"
android:label="MainFragment" android:label="MainFragment"
tools:layout="@layout/fragment_main" /> tools:layout="@layout/fragment_main">
<action
android:id="@+id/toLogin"
app:destination="@id/loginFragment" />
</fragment>
<fragment <fragment
android:id="@+id/loginFragment" android:id="@+id/loginFragment"
+9 -1
View File
@@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android" <navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/messages"> xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/messages"
app:startDestination="@+id/conversationsFragment">
<fragment
android:id="@+id/conversationsFragment"
android:name="com.meloda.fast.fragment.messages.ConversationsFragment"
android:label="ConversationsFragment"
tools:layout="@layout/fragment_conversations" />
</navigation> </navigation>
+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="colorPrimary">@color/dark_primary</item>
<item name="colorPrimaryDark">@color/dark_primaryDark</item>
<item name="colorAccent">@color/dark_accent</item>
<item name="toolbarStyle">@style/AppTheme.Toolbar</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
<item name="dialogCornerRadius">12dp</item>
<item name="android:windowBackground">@color/dark_background</item>
<item name="itemTitleColor">?colorAccent</item>
<item name="dividerHorizontal">@color/dark_divider</item>
<item name="textColorSecondary">@color/dark_textSecondary</item>
<item name="editTextFilledBackgroundColor">@color/dark_edittext_filled_background</item>
<item name="messageInTextColor">@color/dark_message_in</item>
<item name="messageOutTextColor">@color/dark_message_out</item>
<item name="android:windowAnimationStyle">@style/AppTheme.ActivityAnimation</item>
<item name="android:navigationBarColor">@color/dark_navigationBar</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">
@android:color/transparent
</item>
</style>
<style name="AppTheme.Toolbar" parent="Widget.MaterialComponents.Toolbar.PrimarySurface">
<item name="titleTextAppearance">@style/Toolbar.Title</item>
<item name="android:textSize">24sp</item>
<item name="android:elevation">3dp</item>
<item name="titleTextColor">@color/dark_accent</item>
</style>
<style name="AppTheme.Login.EditText" parent="">
<item name="android:layout_height">52dp</item>
<item name="android:background">@drawable/edittext_filled_background</item>
<item name="android:paddingStart">16dp</item>
<item name="android:paddingEnd">16dp</item>
<item name="android:layout_marginEnd">16dp</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textColorHint">?textColorSecondary</item>
<item name="fontFamily">@font/google_sans_regular</item>
<item name="android:singleLine">true</item>
<item name="android:maxLines">1</item>
</style>
<style name="AppTheme.FullScreenDialog" parent="Theme.MaterialComponents.DayNight.Dialog.Bridge">
<item name="colorPrimary">@color/dark_primary</item>
<item name="colorPrimaryDark">@color/dark_primaryDark</item>
<item name="colorAccent">@color/dark_accent</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowBackground">@color/dark_background</item>
<item name="actionMenuTextColor">?colorAccent</item>
<item name="android:navigationBarColor" tools:targetApi="o_mr1">@color/dark_navigationBar</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">
@android:color/transparent
</item>
<item name="colorControlNormal">?colorAccent</item>
</style>
<style name="AppTheme.ProfileDialog" parent="Theme.MaterialComponents.DayNight.BottomSheetDialog">
<item name="colorAccent">@color/dark_accent</item>
<item name="colorPrimary">@color/dark_primary</item>
<item name="colorPrimaryDark">@color/dark_primaryDark</item>
</style>
</resources>
+6 -6
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge"> <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="colorPrimary">@color/primary</item> <item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primaryDark</item> <item name="colorPrimaryDark">@color/primaryDark</item>
<item name="colorAccent">@color/accent</item> <item name="colorAccent">@color/accent</item>
@@ -27,8 +27,6 @@
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1"> <item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">
@android:color/transparent @android:color/transparent
</item> </item>
</style> </style>
<style name="AppTheme.Toolbar" parent="Widget.MaterialComponents.Toolbar.PrimarySurface"> <style name="AppTheme.Toolbar" parent="Widget.MaterialComponents.Toolbar.PrimarySurface">
@@ -59,15 +57,16 @@
<item name="android:maxLines">1</item> <item name="android:maxLines">1</item>
</style> </style>
<style name="AppTheme.FullScreenDialog" parent="Theme.MaterialComponents.Light.Dialog.Bridge"> <style name="AppTheme.FullScreenDialog" parent="Theme.MaterialComponents.DayNight.Dialog.Bridge">
<item name="colorPrimary">@color/primary</item> <item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primaryDark</item> <item name="colorPrimaryDark">@color/primaryDark</item>
<item name="colorAccent">@color/accent</item> <item name="colorAccent">@color/accent</item>
<item name="android:windowIsFloating">false</item> <item name="android:windowIsFloating">false</item>
<item name="android:windowBackground">@color/background</item> <item name="android:windowBackground">@color/background</item>
<item name="actionMenuTextColor">?colorAccent</item> <item name="actionMenuTextColor">?colorAccent</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:navigationBarColor" tools:targetApi="o_mr1">?colorPrimaryDark</item> <item name="android:navigationBarColor" tools:targetApi="o_mr1">@color/navigationBar</item>
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item> <item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1"> <item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">
@android:color/transparent @android:color/transparent
@@ -82,10 +81,11 @@
<item name="android:layout_marginEnd">12dp</item> <item name="android:layout_marginEnd">12dp</item>
</style> </style>
<style name="AppTheme.ProfileDialog" parent="Theme.MaterialComponents.Light.BottomSheetDialog"> <style name="AppTheme.ProfileDialog" parent="Theme.MaterialComponents.DayNight.BottomSheetDialog">
<item name="colorAccent">@color/accent</item> <item name="colorAccent">@color/accent</item>
<item name="colorPrimary">@color/primary</item> <item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primaryDark</item> <item name="colorPrimaryDark">@color/primaryDark</item>
<item name="android:windowLightStatusBar">true</item>
</style> </style>
<style name="Widget.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <style name="Widget.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">