Move more code to coroutines

This commit is contained in:
Phillip Thelen 2022-06-01 14:57:30 +02:00
parent 8a5877ab13
commit 3f1e0d77e8
18 changed files with 83 additions and 105 deletions

View file

@ -167,7 +167,7 @@ android {
buildConfigField "String", "TESTING_LEVEL", "\"production\""
resConfigs 'en', 'bg', 'de', 'en-rGB', 'es', 'fr', 'hr-rHR', 'in', 'it', 'iw', 'ja', 'ko', 'lt', 'nl', 'pl', 'pt-rBR', 'pt-rPT', 'ru', 'tr', 'zh', 'zh-rTW'
versionCode 3510
versionCode 3512
versionName "3.6"
targetSdkVersion 32

View file

@ -63,7 +63,7 @@ interface TaskRepository : BaseRepository {
fun getTaskCopies(userId: String): Flow<List<Task>>
fun getTaskCopies(tasks: List<Task>): Flowable<List<Task>>
fun getTaskCopies(tasks: List<Task>): List<Task>
fun retrieveDailiesFromDate(date: Date): Flowable<TaskList>
fun retrieveCompletedTodos(userId: String? = null): Flowable<TaskList>

View file

@ -88,7 +88,7 @@ interface UserRepository : BaseRepository {
fun reroll(): Flowable<User>
fun retrieveTeamPlans(): Flowable<List<TeamPlan>>
fun getTeamPlans(): Flowable<out List<TeamPlan>>
fun getTeamPlans(): Flow<List<TeamPlan>>
fun retrieveTeamPlan(teamID: String): Flowable<Group>
fun getTeamPlan(teamID: String): Flowable<Group>
}

View file

@ -24,6 +24,7 @@ import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Single
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.map
import java.text.SimpleDateFormat
import java.util.Date
@ -319,8 +320,7 @@ class TaskRepositoryImpl(
override fun getTaskCopies(userId: String): Flow<List<Task>> =
localRepository.getTasks(userId).map { localRepository.getUnmanagedCopy(it) }
override fun getTaskCopies(tasks: List<Task>): Flowable<List<Task>> =
Flowable.just(localRepository.getUnmanagedCopy(tasks))
override fun getTaskCopies(tasks: List<Task>): List<Task> = localRepository.getUnmanagedCopy(tasks)
override fun retrieveDailiesFromDate(date: Date): Flowable<TaskList> {
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.US)

View file

@ -371,7 +371,7 @@ class UserRepositoryImpl(
}
}
override fun getTeamPlans(): Flowable<out List<TeamPlan>> {
override fun getTeamPlans(): Flow<List<TeamPlan>> {
return localRepository.getTeamPlans(userID)
}

View file

@ -35,6 +35,6 @@ interface UserLocalRepository : BaseLocalRepository {
fun getAchievements(): Flow<List<Achievement>>
fun getQuestAchievements(userID: String): Flow<List<QuestAchievement>>
fun getUserQuestStatus(userID: String): Flowable<UserQuestStatus>
fun getTeamPlans(userID: String): Flowable<out List<TeamPlan>>
fun getTeamPlans(userID: String): Flow<List<TeamPlan>>
fun getTeamPlan(teamID: String): Flowable<Group>
}

View file

@ -125,14 +125,12 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
}
}
override fun getTeamPlans(userID: String): Flowable<out List<TeamPlan>> {
return RxJavaBridge.toV3Flowable(
realm.where(TeamPlan::class.java)
override fun getTeamPlans(userID: String): Flow<List<TeamPlan>> {
return realm.where(TeamPlan::class.java)
.equalTo("userID", userID)
.findAll()
.asFlowable()
.toFlow()
.filter { it.isLoaded }
)
}
override fun getTeamPlan(teamID: String): Flowable<Group> {

View file

@ -27,10 +27,6 @@ class LanguageHelper(languageSharedPref: String?) {
locale = Locale("pt", "PT")
languageCode = "pt"
}
"uk" -> {
locale = Locale("uk", "UA")
languageCode = "uk"
}
else -> {
locale = if (pref.contains("_")) {
val languageCodeParts = pref.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()

View file

@ -199,12 +199,12 @@ abstract class BaseActivity : AppCompatActivity() {
actionBar.setHomeButtonEnabled(true)
}
}
toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, this, overrideModernHeader) }
toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, this) }
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val ret = super.onCreateOptionsMenu(menu)
toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, this, overrideModernHeader) }
toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, this) }
return ret
}

View file

@ -123,7 +123,6 @@ class ChallengeFormActivity : BaseActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.menu_create_challenge, menu)
findViewById<Toolbar>(R.id.toolbar).let { ToolbarColorHelper.colorizeToolbar(it, this, overrideModernHeader) }
return super.onCreateOptionsMenu(menu)
}

View file

@ -17,10 +17,16 @@ import com.habitrpg.android.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter
import com.habitrpg.android.habitica.widget.HabitButtonWidgetProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Named
class HabitButtonWidgetActivity : BaseActivity() {
private val job = SupervisorJob()
private lateinit var binding: WidgetConfigureHabitButtonBinding
@ -72,11 +78,12 @@ class HabitButtonWidgetActivity : BaseActivity() {
adapter?.getTaskSelectionEvents()?.subscribe(
{ task -> taskSelected(task.id) },
RxErrorHandler.handleEmptyError()
)
?.let { compositeSubscription.add(it) }
)?.let { compositeSubscription.add(it) }
binding.recyclerView.adapter = adapter
compositeSubscription.add(taskRepository.getTasksFlowable(TaskType.HABIT, userId).subscribe({ adapter?.data = it }, RxErrorHandler.handleEmptyError()))
CoroutineScope(Dispatchers.Main + job).launch {
adapter?.data = taskRepository.getTasks(TaskType.HABIT, userId).firstOrNull() ?: listOf()
}
}
private fun taskSelected(taskId: String?) {

View file

@ -8,7 +8,6 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
@ -19,7 +18,6 @@ import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.databinding.FragmentRefreshRecyclerviewBinding
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.adapter.AchievementsAdapter
import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull
@ -157,9 +155,6 @@ class AchievementsFragment : BaseMainFragment<FragmentRefreshRecyclerviewBinding
menuItem?.setIcon(R.drawable.ic_round_view_module_24px)
tintMenuIcon(menuItem)
}
activity?.findViewById<Toolbar>(R.id.toolbar)?.let {
ToolbarColorHelper.colorizeToolbar(it, activity, null)
}
super.onCreateOptionsMenu(menu, inflater)
}

View file

@ -58,7 +58,8 @@ abstract class BaseMainFragment<VB : ViewBinding> : BaseFragment<VB>() {
setHasOptionsMenu(true)
updateTabLayoutVisibility()
updateToolbarInteractivity()
if (hidesToolbar) {
hideToolbar()
disableToolbarScrolling()
@ -86,7 +87,7 @@ abstract class BaseMainFragment<VB : ViewBinding> : BaseFragment<VB>() {
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
activity?.toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, activity, null) }
activity?.toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, activity) }
updateToolbarInteractivity()
}

View file

@ -50,6 +50,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import java.util.Calendar
import java.util.Date
@ -171,17 +172,14 @@ class NavigationDrawerFragment : DialogFragment() {
)
if (configManager.enableTeamBoards()) {
subscriptions?.add(
lifecycleScope.launch {
userRepository.getTeamPlans()
.distinctUntilChanged { firstTeams, secondTeams -> firstTeams == secondTeams }
.subscribe(
{
getItemWithIdentifier(SIDEBAR_TEAMS)?.isVisible = it.isNotEmpty()
adapter.setTeams(it)
},
RxErrorHandler.handleEmptyError()
)
)
.distinctUntilChanged()
.collect {
getItemWithIdentifier(SIDEBAR_TEAMS)?.isVisible = it.isNotEmpty()
adapter.setTeams(it)
}
}
} else {
getItemWithIdentifier(SIDEBAR_TEAMS)?.isVisible = false
}

View file

@ -25,7 +25,6 @@ import android.widget.TextView
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.appcompat.widget.ActionMenuView
import androidx.appcompat.widget.Toolbar
import androidx.preference.PreferenceManager
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.getThemeColor
import com.habitrpg.android.habitica.extensions.waitForLayout
@ -43,45 +42,33 @@ object ToolbarColorHelper {
fun colorizeToolbar(
toolbar: Toolbar,
activity: Activity?,
overrideModernHeader: Boolean? = null
) {
if (activity == null) return
val modernHeaderStyle = overrideModernHeader ?: PreferenceManager.getDefaultSharedPreferences(activity).getBoolean("modern_header_style", true)
val toolbarIconsColor = if (modernHeaderStyle) {
toolbar.setBackgroundColor(activity.getThemeColor(R.attr.headerBackgroundColor))
activity.getThemeColor(R.attr.headerTextColor)
} else {
toolbar.setBackgroundColor(activity.getThemeColor(R.attr.colorPrimary))
activity.getThemeColor(R.attr.toolbarContentColor)
}
toolbar.setBackgroundColor(activity.getThemeColor(R.attr.headerBackgroundColor))
val toolbarIconsColor = activity.getThemeColor(R.attr.headerTextColor)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
activity.window.statusBarColor = activity.getThemeColor(R.attr.colorPrimaryDark)
}
val colorFilter = PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.MULTIPLY)
for (i in 0 until toolbar.childCount) {
val v = toolbar.getChildAt(i)
// Step 1 : Changing the color of back button (or open drawer button).
if (v is ImageButton) {
// Action Bar back button
v.drawable.colorFilter = colorFilter
} else if (v is ActionMenuView) {
for (j in 0 until v.childCount) {
// Step 2: Changing the color of any ActionMenuViews - icons that are not back button, nor text, nor overflow menu icon.
// Colorize the ActionViews -> all icons that are NOT: back button | overflow menu
colorizeChild(v.getChildAt(j), toolbarIconsColor, colorFilter)
when (val v = toolbar.getChildAt(i)) {
is ImageButton -> {
v.drawable.colorFilter = colorFilter
}
is ActionMenuView -> {
for (j in 0 until v.childCount) {
colorizeChild(v.getChildAt(j), toolbarIconsColor, colorFilter)
}
}
is TextView -> {
v.setTextColor(toolbarIconsColor)
}
} else if (v is TextView) {
v.setTextColor(toolbarIconsColor)
}
}
// Step 3: Changing the color of title and subtitle.
toolbar.setTitleTextColor(toolbarIconsColor)
toolbar.setSubtitleTextColor(toolbarIconsColor)
// Step 4: Changing the color of the Overflow Menu icon.
setOverflowButtonColor(activity, toolbarIconsColor)
}

View file

@ -4,6 +4,7 @@ import android.content.SharedPreferences
import android.text.format.DateUtils
import androidx.core.content.edit
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.TagRepository
import com.habitrpg.android.habitica.data.TaskRepository
@ -20,6 +21,7 @@ import io.realm.Case
import io.realm.OrderedRealmCollection
import io.realm.RealmQuery
import io.realm.Sort
import kotlinx.coroutines.launch
import java.util.Date
import javax.inject.Inject
import javax.inject.Named
@ -58,21 +60,25 @@ class TasksViewModel : BaseViewModel() {
}
init {
compositeSubscription.add(
userRepository.getTeamPlans()
.subscribe({
owners = listOf(Pair(userID, userViewModel.displayName)) + it.map {
Pair(
it.id,
it.summary
)
if (appConfigManager.enableTeamBoards()) {
viewModelScope.launch {
userRepository.getTeamPlans()
.collect {
owners = listOf(Pair(userID, userViewModel.displayName)) + it.map {
Pair(
it.id,
it.summary
)
}
if (owners.size > 1 && canSwitchOwners.value != false) {
canSwitchOwners.value = owners.size > 1
}
}
if (owners.size > 1 && canSwitchOwners.value != false) {
canSwitchOwners.value = owners.size > 1
}
}, RxErrorHandler.handleEmptyError())
)
compositeSubscription.add(userRepository.retrieveTeamPlans().subscribe({}, RxErrorHandler.handleEmptyError()))
}
compositeSubscription.add(
userRepository.retrieveTeamPlans().subscribe({}, RxErrorHandler.handleEmptyError())
)
}
}
internal fun refreshData(onComplete: () -> Unit) {

View file

@ -108,8 +108,8 @@ class ReminderItemFormView @JvmOverloads constructor(
if (taskType == TaskType.DAILY) {
val timePickerDialog = TimePickerDialog(
context, this,
ZonedDateTime.now().hour,
ZonedDateTime.now().minute,
item.getZonedDateTime()?.hour ?: ZonedDateTime.now().hour,
item.getZonedDateTime()?.minute ?: ZonedDateTime.now().minute,
android.text.format.DateFormat.is24HourFormat(context)
)
timePickerDialog.show()

View file

@ -3,7 +3,6 @@ package com.habitrpg.android.habitica.widget
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.text.SpannableStringBuilder
import android.widget.RemoteViews
import android.widget.RemoteViewsService
@ -11,12 +10,14 @@ import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import javax.inject.Inject
abstract class TaskListFactory internal constructor(
@ -26,6 +27,8 @@ abstract class TaskListFactory internal constructor(
private val listItemResId: Int,
private val listItemTextResId: Int
) : RemoteViewsService.RemoteViewsFactory {
private val job = SupervisorJob()
private val widgetId: Int = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0)
@Inject
lateinit var taskRepository: TaskRepository
@ -42,25 +45,13 @@ abstract class TaskListFactory internal constructor(
if (!this::taskRepository.isInitialized) {
return
}
val mainHandler = Handler(context.mainLooper)
mainHandler.post {
taskRepository.getTasksFlowable(taskType)
.firstElement()
.toObservable()
.flatMap { Observable.fromIterable(it) }
.filter { task -> task.type == TaskType.TODO && !task.completed || task.isDisplayedActive }
.toList()
.flatMapMaybe { tasks -> taskRepository.getTaskCopies(tasks).firstElement() }
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ tasks ->
reloadData = false
taskList = tasks
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(widgetId, R.id.list_view)
},
RxErrorHandler.handleEmptyError()
)
CoroutineScope(Dispatchers.Main + job).launch {
val tasks = taskRepository.getTasks(taskType).firstOrNull()?.filter { task ->
task.type == TaskType.TODO && !task.completed || task.isDisplayedActive
} ?: return@launch
taskList = taskRepository.getTaskCopies(tasks)
reloadData = false
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(widgetId, R.id.list_view)
}
}
@ -94,7 +85,7 @@ abstract class TaskListFactory internal constructor(
remoteView.setInt(R.id.checkbox_background, "setBackgroundResource", task.lightTaskColor)
val fillInIntent = Intent()
fillInIntent.putExtra(TaskListWidgetProvider.TASK_ID_ITEM, task.id)
remoteView.setOnClickFillInIntent(R.id.checkbox_background, fillInIntent)
//remoteView.setOnClickFillInIntent(R.id.checkbox_background, fillInIntent)
}
return remoteView
}