Skip to content

Commit

Permalink
Merge branch 'develop' into feature/fine-tuning-main-dashboard-and-list
Browse files Browse the repository at this point in the history
  • Loading branch information
cjimenezsanchez committed Jul 4, 2023
2 parents 7dbd021 + 7362162 commit 7dbfba6
Show file tree
Hide file tree
Showing 41 changed files with 958 additions and 92 deletions.
3 changes: 1 addition & 2 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
id 'androidx.navigation.safeargs.kotlin'
id 'io.gitlab.arturbosch.detekt'
id 'org.jmailen.kotlinter'
id 'kotlin-parcelize'
}

android {
Expand Down Expand Up @@ -49,12 +50,12 @@ dependencies {
implementation project(":data")
implementation project(":domain")

implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'com.google.android.material:material:1.9.0'

implementation "androidx.navigation:navigation-fragment-ktx:2.5.3"
implementation "androidx.navigation:navigation-ui-ktx:2.5.3"
implementation "androidx.navigation:navigation-fragment-ktx:2.6.0"
implementation "androidx.navigation:navigation-ui-ktx:2.6.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
Expand All @@ -74,13 +75,13 @@ dependencies {
implementation 'androidx.room:room-ktx:2.5.1'
kapt 'androidx.room:room-compiler:2.5.1'

implementation "androidx.core:core-splashscreen:1.0.0"
implementation "androidx.core:core-splashscreen:1.0.1"

// Data store
implementation "androidx.datastore:datastore-preferences:1.0.0"

// Glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'com.github.bumptech.glide:glide:4.14.2'
kapt 'com.github.bumptech.glide:compiler:4.12.0'

// Koin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,23 @@ interface DashboardDao {
"SELECT * FROM CellEntity where " +
"dashboardId = :dashboardId AND row = :row AND column = :column LIMIT 1",
)
suspend fun getCell(dashboardId: Int, row: Int, column: Int): CellEntity
suspend fun getCell(dashboardId: Int, row: Int, column: Int): CellEntity?

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertDashboard(dashboard: DashboardEntity)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCell(cell: CellEntity)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCells(cells: List<CellEntity>)

@Query("DELETE FROM DashboardEntity WHERE id = :id")
suspend fun deleteDashboardEntity(id: Int)

@Delete
suspend fun deleteCell(cell: CellEntity)

@Delete
suspend fun deleteCells(cell: List<CellEntity>)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.architectcoders.aacboard.datasource

import android.content.Context
import com.architectcoders.aacboard.R
import com.architectcoders.aacboard.domain.data.Error
import com.architectcoders.aacboard.domain.data.Error.*
import com.architectcoders.aacboard.domain.data.Response
import com.architectcoders.aacboard.domain.data.Response.Failure
import com.architectcoders.aacboard.domain.data.Response.Success
import retrofit2.HttpException
import java.io.IOException

private const val HTTP_NOT_FOUND = 404

fun Error.getMessage(context: Context): String {
return when (this) {
is Server -> context.getString(R.string.serverError, code)
is NoMatchFound -> context.getString(R.string.noMatchFoundError)
is Connectivity -> context.getString(R.string.connectivityError)
is Unknown -> message.ifEmpty { context.getString(R.string.unknownError) }
}
}

fun Throwable.toError(): Error = when (this) {
is IOException -> Connectivity
is HttpException -> if (code() == HTTP_NOT_FOUND) {
NoMatchFound
} else {
Server(code())
}
else -> Unknown(message ?: "")
}

@Suppress("TooGenericExceptionCaught")
inline fun <T> tryCall(action: () -> T): Response<T> = try {
Success(action())
} catch (e: Exception) {
Failure(e.toError())
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package com.architectcoders.aacboard.datasource.local

import com.architectcoders.aacboard.data.datasource.local.DashboardLocalDataSource
import com.architectcoders.aacboard.database.dao.DashboardDao
import com.architectcoders.aacboard.database.entity.toCellEntity
import com.architectcoders.aacboard.database.entity.toDashboard
import com.architectcoders.aacboard.database.entity.toDashboardEntity
import com.architectcoders.aacboard.database.entity.toDashboardWithCells
import com.architectcoders.aacboard.database.entity.*
import com.architectcoders.aacboard.domain.data.cell.Cell
import com.architectcoders.aacboard.domain.data.dashboard.Dashboard
import com.architectcoders.aacboard.domain.data.dashboard.DashboardWithCells
Expand All @@ -30,19 +27,26 @@ class DashboardLocalDataSourceImpl(private val dashboardDao: DashboardDao) :
dashboardDao.insertCells(dashboard.cells.map { it.toCellEntity(dashboard.id) })
}

override suspend fun deleteDashboard(id: Int) {
override suspend fun deleteDashboard(id: Int) =
dashboardDao.deleteDashboardEntity(id)
}

override suspend fun getDashboardCell(dashboardId: Int, row: Int, column: Int): Cell? =
dashboardDao.getCell(dashboardId, row, column)?.toCell()

override suspend fun saveDashboardCell(dashboardId: Int, cell: Cell) =
dashboardDao.insertCell(cell.toCellEntity(dashboardId))

override suspend fun deleteDashboardCell(dashboardId: Int, cell: Cell) =
dashboardDao.deleteCell(cell.toCellEntity(dashboardId))

override suspend fun deleteCells(dashboardId: Int, cells: List<Cell>) {
dashboardDao.deleteCells(cells.map { it.toCellEntity(dashboardId) })
}

override suspend fun deleteCellsContent(dashboardId: Int, cells: List<Cell>) {
override suspend fun deleteCellsContent(dashboardId: Int, cells: List<Cell>) =
dashboardDao.insertCells(
cells.map {
it.toCellEntity(dashboardId).copy(url = null, text = null)
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.architectcoders.aacboard.data.datasource.local.LocationDataSource
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import kotlinx.coroutines.suspendCancellableCoroutine
import java.util.Locale
import kotlin.coroutines.resume

class LocationDataSourceImpl(private val context: Context) : LocationDataSource {
Expand All @@ -34,10 +33,6 @@ class LocationDataSourceImpl(private val context: Context) : LocationDataSource
val addresses = this?.let {
geocoder.getFromLocation(latitude, longitude, 1)
}
val countryCode = addresses?.firstOrNull()?.countryCode

return Locale.getAvailableLocales().firstOrNull { locale ->
locale.country == countryCode
}?.language ?: Locale.getDefault().language
return addresses?.firstOrNull()?.countryCode
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.architectcoders.aacboard.datasource.remote

import com.architectcoders.aacboard.data.datasource.remote.RemoteDataSource
import com.architectcoders.aacboard.domain.data.arasaac.ArasaacPictogram
import com.architectcoders.aacboard.datasource.tryCall
import com.architectcoders.aacboard.domain.data.Response
import com.architectcoders.aacboard.domain.data.Response.Success
import com.architectcoders.aacboard.domain.data.cell.CellPictogram
import com.architectcoders.aacboard.network.service.ArasaacService

class RemoteDataSourceImpl(private val arasaacService: ArasaacService) : RemoteDataSource {
override suspend fun searchPictos(
locale: String,
searchStrnig: String,
): List<ArasaacPictogram> = arasaacService.searchPictos(locale, searchStrnig).map {
it.toArasaacPictogram()
searchString: String,
): Response<List<CellPictogram>> = tryCall {
val list = arasaacService.searchPictos(locale, searchString)
return Success(list.map { it.toCellPictogram() })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import com.architectcoders.aacboard.domain.repository.RegionRepository
import org.koin.dsl.module

val repositoryModule = module {
factory<PictogramsRepository> { PictogramsRepositoryImpl(get(), get(), get(), get()) }
factory<PictogramsRepository> { PictogramsRepositoryImpl(get(), get(), get()) }
factory<RegionRepository> { RegionRepositoryImpl(get(), get()) }
}
10 changes: 10 additions & 0 deletions app/src/main/java/com/architectcoders/aacboard/di/UseCaseModule.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.architectcoders.aacboard.di

import com.architectcoders.aacboard.domain.use_case.cell.delete.DeleteCellUseCase
import com.architectcoders.aacboard.domain.use_case.cell.get.GetCellUseCase
import com.architectcoders.aacboard.domain.use_case.cell.save.SaveCellUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.delete.DeleteDashboardUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.get.GetAllDashboardsUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.get.GetDashboardUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.get.GetMainDashboardUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.get.GetPreferredDashboardIdUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.save.SaveDashboardUseCase
import com.architectcoders.aacboard.domain.use_case.dashboard.save.SetPreferredDashboardIdUseCase
import com.architectcoders.aacboard.domain.use_case.location.GetUserLanguageUseCase
import com.architectcoders.aacboard.domain.use_case.search.SearchPictogramsUseCase
import org.koin.dsl.module

val useCaseModule = module {
Expand All @@ -17,4 +22,9 @@ val useCaseModule = module {
factory { GetPreferredDashboardIdUseCase(get()) }
factory { SaveDashboardUseCase(get()) }
factory { SetPreferredDashboardIdUseCase(get()) }
factory { GetCellUseCase(get()) }
factory { SaveCellUseCase(get()) }
factory { DeleteCellUseCase(get()) }
factory { SearchPictogramsUseCase(get()) }
factory { GetUserLanguageUseCase(get()) }
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
package com.architectcoders.aacboard.di

import androidx.lifecycle.SavedStateHandle
import com.architectcoders.aacboard.ui.fragments.viewmodel.EditBoardCellViewModel
import com.architectcoders.aacboard.ui.fragments.viewmodel.ListDashboardsViewModel
import com.architectcoders.aacboard.ui.fragments.viewmodel.MainDashboardViewModel
import com.architectcoders.aacboard.ui.fragments.viewmodel.SearchPictogramsViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

val viewModelModule = module {
viewModel { ListDashboardsViewModel(get(), get(), get()) }
viewModel { MainDashboardViewModel(get()) }
viewModel { SearchPictogramsViewModel(get(), get()) }
viewModel { (handle: SavedStateHandle) ->
EditBoardCellViewModel(
handle,
get(),
get(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.architectcoders.aacboard.network.response

data class ArasaacKeywordDTO(val keyword: String)
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.architectcoders.aacboard.network.response

import com.architectcoders.aacboard.domain.data.arasaac.ArasaacKeyword
import com.architectcoders.aacboard.domain.data.arasaac.ArasaacPictogram
import com.architectcoders.aacboard.domain.data.cell.CellPictogram
import com.google.gson.annotations.SerializedName

data class ArasaacPictogramDTO(
@SerializedName("_id")
val id: Int,
val arasaacKeywords: List<ArasaacKeyword>,
val sex: Boolean,
val violence: Boolean,
val keywords: List<ArasaacKeywordDTO>,
) {
fun toArasaacPictogram() = ArasaacPictogram(
id = this.id,
arasaacKeywords = this.arasaacKeywords,
sex = this.sex,
violence = this.violence,
companion object {
private const val CONST_ARASAAC_PICTOGRAM_BASE_URL =
"https://static.arasaac.org/pictograms/"
}

val url: String
get() = "${CONST_ARASAAC_PICTOGRAM_BASE_URL}$id/${id}_300.png"

fun toCellPictogram() = CellPictogram(
keywords.first().keyword,
url,
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,88 @@
package com.architectcoders.aacboard.ui.fragments

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.architectcoders.aacboard.R
import com.architectcoders.aacboard.databinding.FragmentEditBoardCellBinding
import com.architectcoders.aacboard.ui.fragments.stateholder.EditBoardCellState
import com.architectcoders.aacboard.ui.fragments.stateholder.buildEditBoardCellState
import com.architectcoders.aacboard.ui.fragments.viewmodel.EditBoardCellViewModel
import com.architectcoders.aacboard.ui.model.PictogramUI
import com.architectcoders.aacboard.ui.utils.diff
import com.architectcoders.aacboard.ui.utils.loadUrl
import org.koin.androidx.viewmodel.ext.android.viewModel

class EditBoardCellFragment : Fragment(R.layout.fragment_edit_board_cell)
class EditBoardCellFragment : Fragment(R.layout.fragment_edit_board_cell) {
private var _binding: FragmentEditBoardCellBinding? = null
private val binding get() = _binding!!

private val viewModel: EditBoardCellViewModel by viewModel()

private lateinit var editBoardCellState: EditBoardCellState

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentEditBoardCellBinding.inflate(inflater, container, false)
editBoardCellState = buildEditBoardCellState()
initViews()
collectState()
checkSearchResponse()
return binding.root
}

private fun initViews() {
binding.apply {
pictogram.setOnClickListener {
editBoardCellState.onSearchPictogram()
}

saveButton.setOnClickListener {
viewModel.onSaveClicked(keyword.text.toString())
}

cancelButton.setOnClickListener {
editBoardCellState.onCancel()
}
}
}

private fun collectState() {
viewModel.state.let { uiStateFlow ->
diff(uiStateFlow, { it.column }, ::onColumnChanged)
diff(uiStateFlow, { it.row }, ::onRowChanged)
diff(uiStateFlow, { it.pictogram }, ::onPictogramChanged)
diff(uiStateFlow, { it.exit }, ::onExitChanged)
}
}

private fun onColumnChanged(column: Int) {
binding.columnLabel.text = getString(R.string.column_label, column)
}

private fun onRowChanged(row: Int) {
binding.rowLabel.text = getString(R.string.row_label, row)
}

private fun onPictogramChanged(pictogram: PictogramUI?) {
pictogram?.let {
binding.pictogram.loadUrl(it.url)
binding.keyword.setText(it.keyword)
}
}

private fun onExitChanged(exit: Boolean) {
if (exit) editBoardCellState.onCancel()
}

private fun checkSearchResponse() {
editBoardCellState.checkSearchResponse {
viewModel.onUpdatePictogram(it)
}
}
}
Loading

0 comments on commit 7dbfba6

Please sign in to comment.