Skip to content

Commit

Permalink
Rewrite details feature using view binding (#120)
Browse files Browse the repository at this point in the history
- Transfer databinding to viewbinding module
- Move ICharacterDetailViewModel and ICharacterDetailViewState to api module, cause it is API.
- Remove LiveData from API of ICharacterDetailViewState (debatable)
- Add ImageViewExtensions.kt file to provide extension to loadImage by url. Copy of databinding-adapter method

Closes #100
  • Loading branch information
Grigoriy Bykov authored May 3, 2023
1 parent 9734598 commit 4182e87
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 173 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
build
/captures
**/.idea/*
!.idea/codeStyles
!.idea/dictionaries
!.idea/fileTemplates
!.idea/file.template.settings.xml
!.idea/inspectionProfiles
!.idea/vcs.xml
*.iml
.externalNativeBuild
.cxx
1 change: 0 additions & 1 deletion application/binary/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ androidBinary(
target(":feature:characters:list:databinding"),
target(":feature:characters:detail:api"),
target(":feature:characters:detail:impl"),
target(":feature:characters:detail:databinding"),
target(":feature:characters:favorite:api"),
target(":feature:characters:favorite:impl"),
target(":feature:characters:favorite:databinding"),
Expand Down
2 changes: 2 additions & 0 deletions application/common/extensions/android-util/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ androidUtil(
androidx.paging,
google.material,
io.coil
) + deps(
target(":common:placeholder:res")
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2023 forma.tools
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.stepango.blockme.common.extensions.android.util

import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import coil.load
import kotlin.random.Random

fun ImageView.loadImage(url: String?, @DrawableRes placeholderId: Int? = null) {
load(url) {
crossfade(true)
placeholder(placeholderId?.let {
ContextCompat.getDrawable(context, it)
} ?: run {
val placeholdersColors = resources.getStringArray(R.array.placeholders)
val placeholderColor = placeholdersColors[Random.nextInt(placeholdersColors.size)]
ColorDrawable(Color.parseColor(placeholderColor))
})
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
package com.stepango.blockme.feature.characters.detail.impl.presentation

import androidx.lifecycle.LiveData
import com.stepango.blockme.feature.characters.core.api.domain.model.ICharacter
package com.stepango.blockme.feature.characters.detail.api.presentation

interface ICharacterDetailViewModel {

val data: LiveData<ICharacter>
val state: LiveData<ICharacterDetailViewState>

fun loadCharacterDetail(characterId: Long)

fun addCharacterToFavorite()
Expand Down
17 changes: 0 additions & 17 deletions application/feature/characters/detail/databinding/build.gradle.kts

This file was deleted.

This file was deleted.

This file was deleted.

7 changes: 3 additions & 4 deletions application/feature/characters/detail/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ impl(
google.material,
google.dagger,
jakewharton.timber,
kotlinx.coroutines_core

kotlinx.coroutines_core,
viewbinding.viewpropertydelegate
) + deps(
target(":feature:characters:core:api"),
target(":feature:characters:favorite:api"),
target(":feature:characters:detail:api"),
target(":feature:characters:detail:databinding"),
target(":feature:characters:detail:viewbinding"),

target(":core:di:library"),
target(":core:theme:android-util"),
Expand All @@ -28,7 +28,6 @@ impl(

target(":common:util"),
target(":common:extensions:android-util"),
target(":common:extensions:databinding-adapter"),
target(":common:progressbar:databinding")
)
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 vmadalin.com
* Copyright 2019 forma.tools
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,6 +22,8 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.stepango.blockme.feature.characters.core.api.domain.model.ICharacter
import com.stepango.blockme.feature.characters.core.api.domain.repository.MarvelRepository
import com.stepango.blockme.feature.characters.detail.api.presentation.ICharacterDetailViewModel
import com.stepango.blockme.feature.characters.detail.api.presentation.ICharacterDetailViewState
import com.stepango.blockme.feature.characters.favorite.api.domain.usecase.IGetCharacterFavoriteUseCase
import com.stepango.blockme.feature.characters.favorite.api.domain.usecase.ISetCharacterFavoriteUseCase
import kotlinx.coroutines.launch
Expand All @@ -34,11 +36,11 @@ class CharacterDetailViewModel @Inject constructor(
) : ViewModel(), ICharacterDetailViewModel {

private val _data = MutableLiveData<ICharacter>()
override val data: LiveData<ICharacter>
val data: LiveData<ICharacter>
get() = _data

private val _state = MutableLiveData<ICharacterDetailViewState>()
override val state: LiveData<ICharacterDetailViewState>
val state: LiveData<ICharacterDetailViewState>
get() = _state

override fun loadCharacterDetail(characterId: Long) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 vmadalin.com
* Copyright 2019 forma.tools
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@
package com.stepango.blockme.feature.characters.detail.impl.presentation

import com.stepango.blockme.core.mvvm.library.ui.BaseViewState
import com.stepango.blockme.feature.characters.detail.api.presentation.ICharacterDetailViewState

sealed class CharacterDetailViewState : BaseViewState, ICharacterDetailViewState {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 vmadalin.com
* Copyright 2019 forma.tools
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,28 +18,32 @@ package com.stepango.blockme.feature.characters.detail.impl.ui

import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.android.material.snackbar.Snackbar
import com.stepango.blockme.common.extensions.android.util.loadImage
import com.stepango.blockme.common.extensions.android.util.observe
import com.stepango.blockme.common.progressbar.databinding.ProgressBarDialog
import com.stepango.blockme.core.mvvm.library.ui.BaseFragment
import com.stepango.blockme.core.mvvm.library.ui.BaseViewBindingFragment
import com.stepango.blockme.core.mvvm.library.viewModels
import com.stepango.blockme.feature.characters.core.api.di.CharactersCoreFeatureProvider
import com.stepango.blockme.feature.characters.detail.databinding.databinding.FragmentCharacterDetailBinding
import com.stepango.blockme.feature.characters.core.api.domain.model.ICharacter
import com.stepango.blockme.feature.characters.detail.api.presentation.ICharacterDetailViewState
import com.stepango.blockme.feature.characters.detail.viewbinding.databinding.FragmentCharacterDetailBinding
import com.stepango.blockme.feature.characters.detail.impl.R
import com.stepango.blockme.feature.characters.detail.impl.di.DaggerCharacterDetailComponent
import com.stepango.blockme.feature.characters.detail.impl.presentation.CharacterDetailViewModel
import com.stepango.blockme.feature.characters.detail.impl.presentation.CharacterDetailViewState
import com.stepango.blockme.feature.characters.detail.impl.presentation.ICharacterDetailViewState
import com.stepango.blockme.feature.characters.favorite.api.di.CharacterFavoriteFeatureProvider

class CharacterDetailFragment :
BaseFragment<FragmentCharacterDetailBinding>(
layoutId = R.layout.fragment_character_detail
) {
class CharacterDetailFragment : BaseViewBindingFragment(
layoutId = R.layout.fragment_character_detail
) {

private val viewModel: CharacterDetailViewModel by viewModels()
private val viewBinding: FragmentCharacterDetailBinding by viewBinding(FragmentCharacterDetailBinding::bind)

private val args: CharacterDetailFragmentArgs by navArgs()

Expand All @@ -48,7 +52,9 @@ class CharacterDetailFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
progressDialog = ProgressBarDialog(requireCompatActivity())
setupViews()

observe(viewModel.data, ::onViewDataChange)
observe(viewModel.state, ::onViewStateChange)
viewModel.loadCharacterDetail(args.characterId)
}
Expand All @@ -63,11 +69,24 @@ class CharacterDetailFragment :
.inject(this)
}

override fun onInitDataBinding() {
viewBinding.viewModel = viewModel
private fun setupViews() {
viewBinding.toolbar.setNavigationOnClickListener {
viewModel.dismissCharacterDetail()
}
viewBinding.addFavoriteButton.setOnClickListener {
viewModel.addCharacterToFavorite()
}
}

private fun onViewDataChange(viewData: ICharacter) {
viewBinding.collapsingToolbar.title = viewData.name
viewBinding.characterImage.loadImage(viewData.imageUrl)
viewBinding.includeDetailBody.characterName.text = viewData.name
viewBinding.includeDetailBody.characterDescription.text = viewData.description
}

private fun onViewStateChange(viewState: ICharacterDetailViewState) {
viewBinding.addFavoriteButton.isVisible = viewState.isAddToFavorite()
when (viewState) {
is CharacterDetailViewState.Loading ->
progressDialog.show(R.string.character_detail_dialog_loading_text)
Expand Down
10 changes: 10 additions & 0 deletions application/feature/characters/detail/viewbinding/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
viewBinding(
packageName = "com.stepango.blockme.feature.characters.detail.viewbinding",
dependencies = deps(
google.material,
androidx.constraintlayout,
) + deps(
target(":feature:characters:detail:res"),
target(":core:theme:res"),
)
)
Loading

0 comments on commit 4182e87

Please sign in to comment.