diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index dd836b80b..f7ec0a105 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -44,31 +44,31 @@ jobs: with: arguments: testProdDebugUnitTest - ui-test: - runs-on: macos-latest - strategy: - matrix: - api-level: [24, 26, 28, 29, 30, 31] - steps: - - uses: actions/checkout@v2 - - name: set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'adopt' - cache: gradle - - name: Prepare - run: ./.github/prepare-workflow - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b - - name: run tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: ${{ matrix.api-level }} - arch: x86_64 - emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - disable-animations: true - script: ./gradlew connectedProdDebugAndroidTest +# ui-test: +# runs-on: macos-latest +# strategy: +# matrix: +# api-level: [24, 26, 28, 29, 30, 31] +# steps: +# - uses: actions/checkout@v2 +# - name: set up JDK 11 +# uses: actions/setup-java@v2 +# with: +# java-version: '11' +# distribution: 'adopt' +# cache: gradle +# - name: Prepare +# run: ./.github/prepare-workflow +# - name: Validate Gradle wrapper +# uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b +# - name: run tests +# uses: reactivecircus/android-emulator-runner@v2 +# with: +# api-level: ${{ matrix.api-level }} +# arch: x86_64 +# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none +# disable-animations: true +# script: ./gradlew connectedProdDebugAndroidTest lint: runs-on: ubuntu-latest diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 661f8e427..d4baccca6 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -150,7 +150,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 4000 + versionCode app_version_code versionName app_version_name targetSdkVersion target_sdk @@ -212,22 +212,26 @@ android { dimension "buildType" buildConfigField "String", "TESTING_LEVEL", "\"staff\"" resValue "string", "app_name", "Habitica Staff" + versionCode app_version_code + 6 } alpha { dimension "buildType" buildConfigField "String", "TESTING_LEVEL", "\"alpha\"" resValue "string", "app_name", "Habitica Alpha" + versionCode app_version_code + 4 } beta { buildConfigField "String", "TESTING_LEVEL", "\"beta\"" dimension "buildType" + versionCode app_version_code + 2 } prod { buildConfigField "String", "TESTING_LEVEL", "\"production\"" dimension "buildType" + versionCode app_version_code } } diff --git a/Habitica/res/drawable-hdpi/baseline_error_outline_black_36dp.png b/Habitica/res/drawable-hdpi/baseline_error_outline_black_36dp.png deleted file mode 100644 index ec4860d02..000000000 Binary files a/Habitica/res/drawable-hdpi/baseline_error_outline_black_36dp.png and /dev/null differ diff --git a/Habitica/res/drawable-mdpi/baseline_error_outline_black_36dp.png b/Habitica/res/drawable-mdpi/baseline_error_outline_black_36dp.png deleted file mode 100644 index 8994911fa..000000000 Binary files a/Habitica/res/drawable-mdpi/baseline_error_outline_black_36dp.png and /dev/null differ diff --git a/Habitica/res/drawable-xhdpi/baseline_error_outline_black_36dp.png b/Habitica/res/drawable-xhdpi/baseline_error_outline_black_36dp.png deleted file mode 100644 index 356880514..000000000 Binary files a/Habitica/res/drawable-xhdpi/baseline_error_outline_black_36dp.png and /dev/null differ diff --git a/Habitica/res/drawable-xxhdpi/baseline_error_outline_black_36dp.png b/Habitica/res/drawable-xxhdpi/baseline_error_outline_black_36dp.png deleted file mode 100644 index a65cafc82..000000000 Binary files a/Habitica/res/drawable-xxhdpi/baseline_error_outline_black_36dp.png and /dev/null differ diff --git a/Habitica/res/drawable-xxxhdpi/baseline_error_outline_black_36dp.png b/Habitica/res/drawable-xxxhdpi/baseline_error_outline_black_36dp.png deleted file mode 100644 index 0a0d146a4..000000000 Binary files a/Habitica/res/drawable-xxxhdpi/baseline_error_outline_black_36dp.png and /dev/null differ diff --git a/Habitica/res/values/dimens.xml b/Habitica/res/values/dimens.xml index 9b3247235..ad847cc41 100644 --- a/Habitica/res/values/dimens.xml +++ b/Habitica/res/values/dimens.xml @@ -4,8 +4,7 @@ 16dp 8dp - 18.0sp - 14.0sp + 12dp 6dp 6dp diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index aec444b80..8314dbe93 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -270,7 +270,6 @@ • Bosses won’t do damage for your missed Dailies\n • Your boss damage or collection quest items will stay pending until check-out You don\'t have any %s - Lvl %d Lvl %1$d %2$s Level %1$d %2$s Warrior @@ -1138,9 +1137,7 @@ You must purchase the previous items in this sequence to unlock You caused damage to the boss Style - Failed to load Daily Checkbox - Retry Nothing here yet You don\'t have any equipment of this type yet. You can purchase equipment from the market using the gold you earned. Todo Checkbox diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.kt index d150e600b..0f0fef56b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ChallengeRepositoryImpl.kt @@ -69,7 +69,7 @@ class ChallengeRepositoryImpl( for ((key, value) in stringListMap) { val taskIdList = value.map { t -> t.id ?: "" } - + if (key == null) continue when (key) { TaskType.HABIT -> tasksOrder.habits = taskIdList TaskType.DAILY -> tasksOrder.dailys = taskIdList diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt index 1d0e34b28..bac4e94fd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt @@ -5,14 +5,14 @@ import androidx.appcompat.app.AppCompatActivity import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.executors.PostExecutionThread import com.habitrpg.android.habitica.helpers.SoundManager -import com.habitrpg.common.habitica.models.responses.TaskScoringResult import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar +import com.habitrpg.common.habitica.models.responses.TaskScoringResult import io.reactivex.rxjava3.core.Flowable -import javax.inject.Inject import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.MainScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import javax.inject.Inject class DisplayItemDropUseCase @Inject constructor(private val soundManager: SoundManager, postExecutionThread: PostExecutionThread) : UseCase(postExecutionThread) { @@ -22,14 +22,14 @@ constructor(private val soundManager: SoundManager, postExecutionThread: PostExe val data = requestValues.data val snackbarText = StringBuilder(data?.drop?.dialog ?: "") - if (data?.questItemsFound ?: 0 > 0 && requestValues.showQuestItems) { + if ((data?.questItemsFound ?: 0) > 0 && requestValues.showQuestItems) { if (snackbarText.isNotEmpty()) snackbarText.append('\n') snackbarText.append(requestValues.context.getString(R.string.quest_items_found, data!!.questItemsFound)) } if (snackbarText.isNotEmpty()) { - GlobalScope.launch(context = Dispatchers.Main) { + MainScope().launch(context = Dispatchers.Main) { delay(3000L) HabiticaSnackbar.showSnackbar( requestValues.snackbarTargetView, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt index e59b9180b..f73bce063 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt @@ -1,11 +1,11 @@ package com.habitrpg.android.habitica.interactors -import com.habitrpg.common.habitica.models.responses.TaskDirection -import com.habitrpg.common.habitica.models.responses.TaskDirectionData import com.habitrpg.android.habitica.models.tasks.Task -import com.habitrpg.common.habitica.models.tasks.TaskType import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.common.habitica.models.responses.TaskDirection +import com.habitrpg.common.habitica.models.responses.TaskDirectionData +import com.habitrpg.common.habitica.models.tasks.TaskType import kotlin.math.min import kotlin.math.pow import kotlin.math.roundToLong @@ -46,6 +46,9 @@ class ScoreTaskLocallyInteractor { private fun scoreToDo(user: User, task: Task, direction: TaskDirection) { } + private fun scoreReward(user: User, task: Task, direction: TaskDirection) { + } + fun score(user: User, task: Task, direction: TaskDirection): TaskDirectionData? { return if (task.type == TaskType.HABIT || direction == TaskDirection.UP) { val stats = user.stats ?: return null @@ -67,14 +70,16 @@ class ScoreTaskLocallyInteractor { TaskType.HABIT -> scoreHabit(user, task, direction) TaskType.DAILY -> scoreDaily(user, task, direction) TaskType.TODO -> scoreToDo(user, task, direction) + TaskType.REWARD -> scoreReward(user, task, direction) + else -> {} } if (result.hp <= 0.0) { result.hp = 0.0 } - if (result.exp >= stats.toNextLevel?.toDouble() ?: 0.0) { + if (result.exp >= (stats.toNextLevel?.toDouble() ?: 0.0)) { result.exp = result.exp - (stats.toNextLevel?.toDouble() ?: 0.0) - result.lvl = user.stats?.lvl ?: 0 + 1 + result.lvl = (user.stats?.lvl ?: 0) + 1 result.hp = 50.0 } else { result.lvl = user.stats?.lvl ?: 0 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index ebe1b17ce..1e61f956b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -29,7 +29,6 @@ import java.util.Date import java.util.GregorianCalendar open class Task : RealmObject, BaseMainObject, Parcelable { - override val realmClass: Class get() = Task::class.java override val primaryIdentifier: String? @@ -109,6 +108,21 @@ open class Task : RealmObject, BaseMainObject, Parcelable { val completedChecklistCount: Int get() = checklist?.count { it.completed } ?: 0 + val streakString: String? + get() { + return if (counterUp != null && (counterUp ?: 0) > 0 && counterDown != null && (counterDown ?: 0) > 0) { + "+" + counterUp.toString() + " | -" + counterDown?.toString() + } else if (counterUp != null && (counterUp ?: 0) > 0) { + "+" + counterUp.toString() + } else if (counterDown != null && (counterDown ?: 0) > 0) { + "-" + counterDown.toString() + } else if ((streak ?: 0) > 0) { + return streak.toString() + } else { + null + } + } + val extraLightTaskColor: Int get() { return when { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt index 3bdd27755..a715cabf1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt @@ -31,7 +31,7 @@ import com.habitrpg.android.habitica.models.user.Outfit import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.ui.AvatarWithBarsViewModel import com.habitrpg.android.habitica.ui.adapter.social.AchievementProfileAdapter -import com.habitrpg.android.habitica.ui.helpers.RecyclerViewState +import com.habitrpg.common.habitica.helpers.RecyclerViewState import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt index a190fa740..e0d8bd7ab 100755 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt @@ -496,7 +496,7 @@ open class MainActivity : BaseActivity(), SnackbarActivity { private fun checkMaintenance() { viewModel.ifNeedsMaintenance { maintenanceResponse -> - if (maintenanceResponse.activeMaintenance) { + if (maintenanceResponse.activeMaintenance == true) { val intent = createMaintenanceIntent(maintenanceResponse, false) startActivity(intent) } else { @@ -504,7 +504,7 @@ open class MainActivity : BaseActivity(), SnackbarActivity { try { val packageInfo = packageManager.getPackageInfo(packageName, 0) @Suppress("DEPRECATION") - if (packageInfo.versionCode < maintenanceResponse.minBuild) { + if (packageInfo.versionCode < (maintenanceResponse.minBuild ?: 0)) { val intent = createMaintenanceIntent(maintenanceResponse, true) startActivity(intent) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt index 9a5f4872b..7bef8b85f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt @@ -72,7 +72,7 @@ class MaintenanceActivity : BaseActivity() { .observeOn(AndroidSchedulers.mainThread()) .subscribe( { maintenanceResponse -> - if (!maintenanceResponse.activeMaintenance) { + if (maintenanceResponse.activeMaintenance == false) { finish() } }, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt index 0539b94e6..e66a08d7d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt @@ -8,7 +8,6 @@ import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.RecyclerView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.ItemItemBinding -import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.models.inventory.Food import com.habitrpg.android.habitica.models.inventory.HatchingPotion @@ -20,10 +19,11 @@ import com.habitrpg.android.habitica.models.user.OwnedItem import com.habitrpg.android.habitica.models.user.OwnedPet import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter -import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem import com.habitrpg.android.habitica.ui.views.dialogs.DetailDialog +import com.habitrpg.common.habitica.extensions.layoutInflater +import com.habitrpg.common.habitica.extensions.loadImage import io.reactivex.rxjava3.core.BackpressureStrategy import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.subjects.PublishSubject @@ -105,7 +105,7 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter 0) { + if (specialItem.isMysteryItem && (ownedItem?.numberOwned ?: 0) > 0) { menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.open))) - } else if (ownedItem?.numberOwned ?: 0 > 0) { + } else if ((ownedItem?.numberOwned ?: 0) > 0) { menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.use_item))) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt index 597073473..68275bca6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt @@ -15,7 +15,7 @@ import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.ui.adapter.inventory.EquipmentRecyclerViewAdapter import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import javax.inject.Inject diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt index 24bfc8ab3..985f5f2bc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemDialogFragment.kt @@ -31,7 +31,7 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.adapter.inventory.ItemRecyclerAdapter import com.habitrpg.android.habitica.ui.fragments.BaseDialogFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt index 5e7186238..47c5353d1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt @@ -37,7 +37,7 @@ import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.SkillMemberActivity import com.habitrpg.android.habitica.ui.adapter.inventory.ItemRecyclerAdapter import com.habitrpg.android.habitica.ui.fragments.BaseFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt index e1d66a087..1741c70dd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt @@ -21,7 +21,7 @@ import com.habitrpg.android.habitica.models.social.Group import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.adapter.inventory.ShopRecyclerAdapter import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment -import com.habitrpg.android.habitica.ui.helpers.RecyclerViewState +import com.habitrpg.common.habitica.helpers.RecyclerViewState import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.CurrencyViews diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt index c3a1a63d8..5433ec79a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt @@ -19,7 +19,7 @@ import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.models.inventory.HatchingPotion import com.habitrpg.android.habitica.ui.adapter.inventory.StableRecyclerAdapter import com.habitrpg.android.habitica.ui.fragments.BaseFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.MarginDecoration import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt index 8a968cef5..e9569346f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt @@ -24,21 +24,21 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.members.Member import com.habitrpg.android.habitica.models.social.Challenge import com.habitrpg.android.habitica.models.tasks.Task -import com.habitrpg.common.habitica.models.tasks.TaskType import com.habitrpg.android.habitica.ui.activities.ChallengeFormActivity import com.habitrpg.android.habitica.ui.activities.FullProfileActivity import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment -import com.habitrpg.common.habitica.helpers.EmojiParser -import com.habitrpg.common.habitica.helpers.setMarkdown import com.habitrpg.android.habitica.ui.viewHolders.tasks.DailyViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.HabitViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.RewardViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.TodoViewHolder import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel -import com.habitrpg.common.habitica.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import javax.inject.Inject +import com.habitrpg.common.habitica.helpers.EmojiParser +import com.habitrpg.common.habitica.helpers.setMarkdown +import com.habitrpg.common.habitica.models.tasks.TaskType +import com.habitrpg.common.habitica.views.HabiticaIconsHelper import retrofit2.HttpException +import javax.inject.Inject class ChallengeDetailFragment : BaseMainFragment() { @@ -117,7 +117,8 @@ class ChallengeDetailFragment : BaseMainFragment val rewards = ArrayList() for (entry in taskList) { - when (entry.type) { + val type = entry.type ?: continue + when (type) { TaskType.TODO -> todos.add(entry) TaskType.HABIT -> habits.add(entry) TaskType.DAILY -> dailies.add(entry) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt index caa1844ca..a85a6e613 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt @@ -18,7 +18,7 @@ import com.habitrpg.android.habitica.models.social.Group import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.adapter.social.ChallengesListViewAdapter import com.habitrpg.android.habitica.ui.fragments.BaseFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.kotlin.Flowables diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/guilds/GuildListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/guilds/GuildListFragment.kt index 774ece179..7b090ab0a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/guilds/GuildListFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/guilds/GuildListFragment.kt @@ -13,7 +13,7 @@ import com.habitrpg.android.habitica.databinding.FragmentRefreshRecyclerviewBind import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.ui.adapter.social.GuildListAdapter import com.habitrpg.android.habitica.ui.fragments.BaseFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import javax.inject.Inject diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt index dcc701b40..80033e1a9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt @@ -28,10 +28,7 @@ import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.NotificationsManager import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.helpers.SoundManager -import com.habitrpg.common.habitica.models.responses.TaskDirection -import com.habitrpg.common.habitica.models.responses.TaskScoringResult import com.habitrpg.android.habitica.models.tasks.Task -import com.habitrpg.common.habitica.models.tasks.TaskType import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.TaskFormActivity import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter @@ -41,13 +38,16 @@ import com.habitrpg.android.habitica.ui.adapter.tasks.RewardsRecyclerViewAdapter import com.habitrpg.android.habitica.ui.adapter.tasks.TaskRecyclerViewAdapter import com.habitrpg.android.habitica.ui.adapter.tasks.TodosRecyclerViewAdapter import com.habitrpg.android.habitica.ui.fragments.BaseFragment -import com.habitrpg.android.habitica.ui.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import com.habitrpg.android.habitica.ui.viewHolders.tasks.BaseTaskViewHolder import com.habitrpg.android.habitica.ui.viewmodels.TasksViewModel -import com.habitrpg.common.habitica.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog +import com.habitrpg.common.habitica.models.responses.TaskDirection +import com.habitrpg.common.habitica.models.responses.TaskScoringResult +import com.habitrpg.common.habitica.models.tasks.TaskType +import com.habitrpg.common.habitica.views.HabiticaIconsHelper import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import kotlinx.coroutines.Job @@ -471,6 +471,7 @@ open class TaskRecyclerViewFragment : BaseFragment {} } } } @@ -534,6 +535,10 @@ open class TaskRecyclerViewFragment : BaseFragment { + fragment.tutorialStepIdentifier = "rewards" + tutorialTexts = listOf(context.getString(R.string.tutorial_rewards_1), context.getString(R.string.tutorial_rewards_2)) + } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/RecyclerViewEmptySupport.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/RecyclerViewEmptySupport.kt index e2ad593c6..9d95f282b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/RecyclerViewEmptySupport.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/RecyclerViewEmptySupport.kt @@ -2,34 +2,18 @@ package com.habitrpg.android.habitica.ui.helpers import android.content.Context import android.util.AttributeSet -import android.view.View -import android.view.ViewGroup -import android.view.animation.AlphaAnimation -import android.widget.ProgressBar -import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.databinding.EmptyItemBinding -import com.habitrpg.android.habitica.databinding.FailedItemBinding -import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.common.habitica.helpers.EmptyItem +import com.habitrpg.common.habitica.helpers.RecyclerViewState +import com.habitrpg.common.habitica.helpers.RecyclerViewStateAdapter -data class EmptyItem( - var title: String, - var text: String? = null, - var iconResource: Int? = null, - var buttonLabel: String? = null, - var onButtonTap: (() -> Unit)? = null -) +class RecyclerViewEmptySupport @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null +) : RecyclerView(context, attrs) { + var onRefresh: (() -> Unit)? + get() = emptyAdapter.onRefresh + set(value) { emptyAdapter.onRefresh = value } -enum class RecyclerViewState { - LOADING, - EMPTY, - DISPLAYING_DATA, - FAILED -} - -class RecyclerViewEmptySupport : RecyclerView { - var onRefresh: (() -> Unit)? = null var state: RecyclerViewState = RecyclerViewState.LOADING set(value) { field = value @@ -37,7 +21,7 @@ class RecyclerViewEmptySupport : RecyclerView { RecyclerViewState.DISPLAYING_DATA -> updateAdapter(actualAdapter) else -> { updateAdapter(emptyAdapter) - emptyAdapter.notifyDataSetChanged() + emptyAdapter.state = value } } } @@ -48,53 +32,16 @@ class RecyclerViewEmptySupport : RecyclerView { } } - var emptyItem: EmptyItem? = null + var emptyItem: EmptyItem? + get() = emptyAdapter.emptyItem set(value) { - field = value - emptyAdapter.notifyDataSetChanged() + emptyAdapter.emptyItem = value } private var actualAdapter: Adapter<*>? = null - private val emptyAdapter: Adapter = object : Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return when (viewType) { - 0 -> { - val view = parent.inflate(R.layout.loading_item) - val animation1 = AlphaAnimation(0.0f, 1.0f) - animation1.duration = 300 - animation1.startOffset = 500 - animation1.fillAfter = true - view.findViewById(R.id.loading_indicator).startAnimation(animation1) - object : ViewHolder(view) {} - } - 1 -> FailedViewHolder(parent.inflate(R.layout.failed_item)) - else -> EmptyViewHolder(parent.inflate(R.layout.empty_item)) - } - } + private val emptyAdapter = RecyclerViewStateAdapter() - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - if (holder is EmptyViewHolder) { - holder.bind(emptyItem) - } else if (holder is FailedViewHolder) { - holder.bind(onRefresh) - } - (holder as? EmptyViewHolder)?.bind(emptyItem) - } - - override fun getItemCount(): Int { - return 1 - } - - override fun getItemViewType(position: Int): Int { - return when (state) { - RecyclerViewState.LOADING -> 0 - RecyclerViewState.FAILED -> 1 - else -> 2 - } - } - } - - private val observer = object : RecyclerView.AdapterDataObserver() { + private val observer = object : AdapterDataObserver() { override fun onChanged() { updateState() } @@ -108,22 +55,16 @@ class RecyclerViewEmptySupport : RecyclerView { } } - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) - internal fun updateState(isInitial: Boolean = false) { - if (actualAdapter != null && !isInitial) { + state = if (actualAdapter != null && !isInitial) { val emptyViewVisible = actualAdapter?.itemCount == 0 if (emptyViewVisible) { - state = RecyclerViewState.EMPTY + RecyclerViewState.EMPTY } else { - state = RecyclerViewState.DISPLAYING_DATA + RecyclerViewState.DISPLAYING_DATA } } else { - state = RecyclerViewState.LOADING + RecyclerViewState.LOADING } } @@ -135,38 +76,4 @@ class RecyclerViewEmptySupport : RecyclerView { actualAdapter = adapter updateState(true) } -} - -class FailedViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val binding = FailedItemBinding.bind(itemView) - - fun bind(onRefresh: (() -> Unit)?) { - if (onRefresh != null) { - binding.refreshButton.visibility = View.VISIBLE - binding.refreshButton.setOnClickListener { onRefresh() } - } else { - binding.refreshButton.visibility = View.GONE - } - } -} - -class EmptyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - - private val binding = EmptyItemBinding.bind(itemView) - - fun bind(emptyItem: EmptyItem?) { - binding.emptyIconView.setColorFilter(ContextCompat.getColor(itemView.context, R.color.text_dimmed), android.graphics.PorterDuff.Mode.MULTIPLY) - emptyItem?.iconResource?.let { binding.emptyIconView.setImageResource(it) } - binding.emptyViewTitle.text = emptyItem?.title - binding.emptyViewDescription.text = emptyItem?.text - - val buttonLabel = emptyItem?.buttonLabel - if (buttonLabel != null) { - binding.button.visibility = View.VISIBLE - binding.button.text = buttonLabel - binding.button.setOnClickListener { emptyItem.onButtonTap?.invoke() } - } else { - binding.button.visibility = View.GONE - } - } -} +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt index c5d9788af..381a7b484 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt @@ -7,8 +7,8 @@ import android.widget.FrameLayout import android.widget.ImageView import androidx.core.content.ContextCompat import com.habitrpg.android.habitica.R -import com.habitrpg.common.habitica.models.responses.TaskDirection import com.habitrpg.android.habitica.models.tasks.Task +import com.habitrpg.common.habitica.models.responses.TaskDirection class HabitViewHolder( itemView: View, @@ -110,15 +110,8 @@ class HabitViewHolder( this.btnMinus.isClickable = false } - var streakString = "" - if (data.counterUp != null && data.counterUp ?: 0 > 0 && data.counterDown != null && data.counterDown ?: 0 > 0) { - streakString = streakString + "+" + data.counterUp.toString() + " | -" + data.counterDown?.toString() - } else if (data.counterUp != null && data.counterUp ?: 0 > 0) { - streakString = streakString + "+" + data.counterUp.toString() - } else if (data.counterDown != null && data.counterDown ?: 0 > 0) { - streakString = streakString + "-" + data.counterDown.toString() - } - if (streakString.isNotEmpty()) { + val streakString = task?.streakString + if (streakString?.isNotEmpty() == true) { streakTextView.text = streakString streakTextView.visibility = View.VISIBLE streakIconView.visibility = View.VISIBLE diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt index 3d147718e..49fdd9f2c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt @@ -4,7 +4,6 @@ import android.content.SharedPreferences import androidx.core.content.edit import androidx.lifecycle.viewModelScope import com.habitrpg.android.habitica.R -import com.habitrpg.common.habitica.api.HostConfig import com.habitrpg.android.habitica.api.MaintenanceApiService import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.ContentRepository @@ -16,9 +15,10 @@ import com.habitrpg.android.habitica.helpers.TaskAlarmManager import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager import com.habitrpg.android.habitica.models.TutorialStep import com.habitrpg.android.habitica.models.inventory.Egg -import com.habitrpg.common.habitica.models.responses.MaintenanceResponse import com.habitrpg.android.habitica.proxy.AnalyticsManager import com.habitrpg.android.habitica.ui.TutorialView +import com.habitrpg.common.habitica.api.HostConfig +import com.habitrpg.common.habitica.models.responses.MaintenanceResponse import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.schedulers.Schedulers import io.realm.kotlin.isValid @@ -136,7 +136,7 @@ class MainActivityViewModel : BaseViewModel(), TutorialView.OnTutorialReaction { .observeOn(AndroidSchedulers.mainThread()) .subscribe( { maintenanceResponse -> - if (maintenanceResponse == null) { + if (maintenanceResponse.activeMaintenance == null) { return@subscribe } onResult(maintenanceResponse) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt index 1623d21c7..fa249029c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt @@ -63,6 +63,9 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaBo binding.secondTaskFilter.setText(R.string.dated) binding.thirdTaskFilter.setText(R.string.completed) } + TaskType.REWARD -> { + + } } setActiveFilter(viewModel.getActiveFilter(value)) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt index bde20e30b..b4845d870 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt @@ -184,6 +184,9 @@ class TaskSerializer : JsonSerializer, JsonDeserializer { } obj.addProperty("completed", task.completed) } + else -> { + + } } return obj diff --git a/build.gradle b/build.gradle index 25a598769..04bbe2395 100644 --- a/build.gradle +++ b/build.gradle @@ -4,9 +4,10 @@ buildscript { ext { target_sdk = 32 app_version_name = '4.0' + app_version_code = 4010 - kotlin_version = '1.6.21' + kotlin_version = '1.7.0' core_ktx_version = '1.8.0' appcompat_version = '1.4.2' lifecycle_version = '2.4.1' @@ -37,7 +38,7 @@ buildscript { classpath "io.realm:realm-gradle-plugin:10.10.1" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.19.0" - classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.0-rc01" + classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.0-rc02" classpath 'com.google.firebase:perf-plugin:1.4.1' classpath "com.google.dagger:hilt-android-gradle-plugin:$daggerhilt_version" } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewGroup-Extensions.kt b/common/src/main/java/com/habitrpg/common/habitica/extensions/ViewGroup-Extensions.kt similarity index 100% rename from Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewGroup-Extensions.kt rename to common/src/main/java/com/habitrpg/common/habitica/extensions/ViewGroup-Extensions.kt diff --git a/common/src/main/java/com/habitrpg/common/habitica/helpers/RecyclerViewEmptySupport.kt b/common/src/main/java/com/habitrpg/common/habitica/helpers/RecyclerViewEmptySupport.kt new file mode 100644 index 000000000..e88db2736 --- /dev/null +++ b/common/src/main/java/com/habitrpg/common/habitica/helpers/RecyclerViewEmptySupport.kt @@ -0,0 +1,118 @@ +package com.habitrpg.common.habitica.helpers + +import android.view.View +import android.view.ViewGroup +import android.view.animation.AlphaAnimation +import android.widget.ProgressBar +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.common.habitica.R +import com.habitrpg.common.habitica.databinding.EmptyItemBinding +import com.habitrpg.common.habitica.databinding.FailedItemBinding + +data class EmptyItem( + var title: String, + var text: String? = null, + var iconResource: Int? = null, + var buttonLabel: String? = null, + var onButtonTap: (() -> Unit)? = null +) + +enum class RecyclerViewState { + LOADING, + EMPTY, + DISPLAYING_DATA, + FAILED +} + +class FailedViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + private val binding = FailedItemBinding.bind(itemView) + + fun bind(onRefresh: (() -> Unit)?) { + if (onRefresh != null) { + binding.refreshButton.visibility = View.VISIBLE + binding.refreshButton.setOnClickListener { onRefresh() } + } else { + binding.refreshButton.visibility = View.GONE + } + } +} + +class EmptyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + private val binding = EmptyItemBinding.bind(itemView) + + fun bind(emptyItem: EmptyItem?) { + binding.emptyIconView.setColorFilter( + ContextCompat.getColor( + itemView.context, + R.color.text_dimmed + ), android.graphics.PorterDuff.Mode.MULTIPLY) + emptyItem?.iconResource?.let { binding.emptyIconView.setImageResource(it) } + binding.emptyViewTitle.text = emptyItem?.title + binding.emptyViewDescription.text = emptyItem?.text + + val buttonLabel = emptyItem?.buttonLabel + if (buttonLabel != null) { + binding.button.visibility = View.VISIBLE + binding.button.text = buttonLabel + binding.button.setOnClickListener { emptyItem.onButtonTap?.invoke() } + } else { + binding.button.visibility = View.GONE + } + } +} + +class RecyclerViewStateAdapter(val showLoadingAsEmpty: Boolean = false) : RecyclerView.Adapter() { + var onRefresh: (() -> Unit)? = null + var emptyItem: EmptyItem? = null + set(value) { + field = value + notifyItemChanged(0) + } + + var state: RecyclerViewState = RecyclerViewState.LOADING + set(value) { + field = value + notifyItemChanged(0) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + 0 -> { + val view = parent.inflate(R.layout.loading_item) + val animation1 = AlphaAnimation(0.0f, 1.0f) + animation1.duration = 300 + animation1.startOffset = 500 + animation1.fillAfter = true + view.findViewById(R.id.loading_indicator).startAnimation(animation1) + object : RecyclerView.ViewHolder(view) {} + } + 1 -> FailedViewHolder(parent.inflate(R.layout.failed_item)) + else -> EmptyViewHolder(parent.inflate(R.layout.empty_item)) + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is EmptyViewHolder) { + holder.bind(emptyItem) + } else if (holder is FailedViewHolder) { + holder.bind(onRefresh) + } + (holder as? EmptyViewHolder)?.bind(emptyItem) + } + + override fun getItemCount(): Int { + return 1 + } + + override fun getItemViewType(position: Int): Int { + return when { + state == RecyclerViewState.LOADING && !showLoadingAsEmpty -> 0 + state == RecyclerViewState.FAILED -> 1 + else -> 2 + } + } +} + diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/MaintenanceResponse.java b/common/src/main/java/com/habitrpg/common/habitica/models/responses/MaintenanceResponse.java deleted file mode 100644 index ffcffb8b3..000000000 --- a/common/src/main/java/com/habitrpg/common/habitica/models/responses/MaintenanceResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.habitrpg.common.habitica.models.responses; - -public class MaintenanceResponse { - - public Boolean activeMaintenance; - public Integer minBuild; - public String title; - public String imageUrl; - public String description; -} diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/MaintenanceResponse.kt b/common/src/main/java/com/habitrpg/common/habitica/models/responses/MaintenanceResponse.kt new file mode 100644 index 000000000..034ddc1d3 --- /dev/null +++ b/common/src/main/java/com/habitrpg/common/habitica/models/responses/MaintenanceResponse.kt @@ -0,0 +1,9 @@ +package com.habitrpg.common.habitica.models.responses + +class MaintenanceResponse { + var activeMaintenance: Boolean? = null + var minBuild: Int? = null + var title: String? = null + var imageUrl: String? = null + var description: String? = null +} \ No newline at end of file diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt index ba2d20ce5..6e6186e56 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt @@ -1,5 +1,8 @@ package com.habitrpg.common.habitica.models.responses +import android.os.Parcel +import android.os.Parcelable + class TaskDirectionDataTemp { var drop: TaskDirectionDataDrop? = null @@ -12,10 +15,37 @@ class TaskDirectionDataQuest { var collection: Int = 0 } -class TaskDirectionDataDrop { - +class TaskDirectionDataDrop() : Parcelable { var value: Int = 0 var key: String? = null var type: String? = null var dialog: String? = null + + constructor(parcel: Parcel) : this() { + value = parcel.readInt() + key = parcel.readString() + type = parcel.readString() + dialog = parcel.readString() + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(value) + parcel.writeString(key) + parcel.writeString(type) + parcel.writeString(dialog) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): TaskDirectionDataDrop { + return TaskDirectionDataDrop(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt index 15aad3a07..b3f51dc9f 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt @@ -8,10 +8,10 @@ class TaskScoringResult(): Parcelable { constructor(data: TaskDirectionData, stats: AvatarStats?) : this() { hasLeveledUp = data.lvl > (stats?.lvl ?: 0) healthDelta = data.hp - (stats?.hp ?: 0.0) - if (hasLeveledUp) { - experienceDelta = (stats?.toNextLevel ?: 0).toDouble() - (stats?.exp ?: 0.0) + data.exp + experienceDelta = if (hasLeveledUp) { + (stats?.toNextLevel ?: 0).toDouble() - (stats?.exp ?: 0.0) + data.exp } else { - experienceDelta = data.exp - (stats?.exp ?: 0.0) + data.exp - (stats?.exp ?: 0.0) } manaDelta = data.mp - (stats?.mp ?: 0.0) goldDelta = data.gp - (stats?.gp ?: 0.0) @@ -40,6 +40,7 @@ class TaskScoringResult(): Parcelable { level = parcel.readValue(Int::class.java.classLoader) as? Int questDamage = parcel.readValue(Double::class.java.classLoader) as? Double questItemsFound = parcel.readValue(Int::class.java.classLoader) as? Int + drop = parcel.readValue(TaskDirectionDataDrop::class.java.classLoader) as? TaskDirectionDataDrop } override fun writeToParcel(parcel: Parcel, flags: Int) { @@ -51,6 +52,7 @@ class TaskScoringResult(): Parcelable { parcel.writeValue(level) parcel.writeValue(questDamage) parcel.writeValue(questItemsFound) + parcel.writeValue(drop) } override fun describeContents(): Int { diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/tasks/TasksOrder.kt b/common/src/main/java/com/habitrpg/common/habitica/models/tasks/TasksOrder.kt index 6b83bc3fc..501a45ac4 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/models/tasks/TasksOrder.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/models/tasks/TasksOrder.kt @@ -1,6 +1,15 @@ package com.habitrpg.common.habitica.models.tasks class TasksOrder { + fun positionOf(key: String, type: TaskType): Int { + return when (type) { + TaskType.HABIT -> habits.indexOf(key) + TaskType.DAILY -> dailys.indexOf(key) + TaskType.TODO -> todos.indexOf(key) + TaskType.REWARD -> rewards.indexOf(key) + } + } + var habits: List = listOf() var dailys: List = listOf() var todos: List = listOf() diff --git a/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt b/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt index 8bd65580f..6ab09431d 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt @@ -13,7 +13,9 @@ import androidx.core.content.ContextCompat import com.habitrpg.common.habitica.R import com.habitrpg.common.habitica.models.PlayerTier -class UsernameLabel(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { +class UsernameLabel @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null +) : LinearLayout(context, attrs) { private val textView = TextView(context) private val tierIconView = ImageView(context) @@ -54,7 +56,7 @@ class UsernameLabel(context: Context?, attrs: AttributeSet?) : LinearLayout(cont textViewParams.gravity = Gravity.CENTER_VERTICAL textViewParams.weight = 1.0f addView(textView, textViewParams) - val padding = context?.resources?.getDimension(R.dimen.spacing_small)?.toInt() ?: 0 + val padding = context.resources.getDimension(R.dimen.spacing_small).toInt() textView.setPadding(0, 0, padding, 0) textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f) val iconViewParams = LayoutParams( diff --git a/common/src/main/res/drawable-anydpi/failed_loading.xml b/common/src/main/res/drawable-anydpi/failed_loading.xml new file mode 100644 index 000000000..a2abd198b --- /dev/null +++ b/common/src/main/res/drawable-anydpi/failed_loading.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/common/src/main/res/drawable-hdpi/failed_loading.png b/common/src/main/res/drawable-hdpi/failed_loading.png new file mode 100644 index 000000000..92a4bc43b Binary files /dev/null and b/common/src/main/res/drawable-hdpi/failed_loading.png differ diff --git a/Habitica/res/drawable-hdpi/task_icon_calendar.png b/common/src/main/res/drawable-hdpi/task_icon_calendar.png similarity index 100% rename from Habitica/res/drawable-hdpi/task_icon_calendar.png rename to common/src/main/res/drawable-hdpi/task_icon_calendar.png diff --git a/Habitica/res/drawable-hdpi/task_icon_reminder.png b/common/src/main/res/drawable-hdpi/task_icon_reminder.png similarity index 100% rename from Habitica/res/drawable-hdpi/task_icon_reminder.png rename to common/src/main/res/drawable-hdpi/task_icon_reminder.png diff --git a/Habitica/res/drawable-hdpi/task_icon_streak.png b/common/src/main/res/drawable-hdpi/task_icon_streak.png similarity index 100% rename from Habitica/res/drawable-hdpi/task_icon_streak.png rename to common/src/main/res/drawable-hdpi/task_icon_streak.png diff --git a/Habitica/res/drawable-hdpi/task_icon_team.png b/common/src/main/res/drawable-hdpi/task_icon_team.png similarity index 100% rename from Habitica/res/drawable-hdpi/task_icon_team.png rename to common/src/main/res/drawable-hdpi/task_icon_team.png diff --git a/Habitica/res/drawable-hdpi/task_lock.png b/common/src/main/res/drawable-hdpi/task_lock.png similarity index 100% rename from Habitica/res/drawable-hdpi/task_lock.png rename to common/src/main/res/drawable-hdpi/task_lock.png diff --git a/common/src/main/res/drawable-mdpi/failed_loading.png b/common/src/main/res/drawable-mdpi/failed_loading.png new file mode 100644 index 000000000..1e3f3a3ec Binary files /dev/null and b/common/src/main/res/drawable-mdpi/failed_loading.png differ diff --git a/Habitica/res/drawable-mdpi/task_icon_calendar.png b/common/src/main/res/drawable-mdpi/task_icon_calendar.png similarity index 100% rename from Habitica/res/drawable-mdpi/task_icon_calendar.png rename to common/src/main/res/drawable-mdpi/task_icon_calendar.png diff --git a/Habitica/res/drawable-mdpi/task_icon_reminder.png b/common/src/main/res/drawable-mdpi/task_icon_reminder.png similarity index 100% rename from Habitica/res/drawable-mdpi/task_icon_reminder.png rename to common/src/main/res/drawable-mdpi/task_icon_reminder.png diff --git a/Habitica/res/drawable-mdpi/task_icon_streak.png b/common/src/main/res/drawable-mdpi/task_icon_streak.png similarity index 100% rename from Habitica/res/drawable-mdpi/task_icon_streak.png rename to common/src/main/res/drawable-mdpi/task_icon_streak.png diff --git a/Habitica/res/drawable-mdpi/task_icon_team.png b/common/src/main/res/drawable-mdpi/task_icon_team.png similarity index 100% rename from Habitica/res/drawable-mdpi/task_icon_team.png rename to common/src/main/res/drawable-mdpi/task_icon_team.png diff --git a/Habitica/res/drawable-mdpi/task_lock.png b/common/src/main/res/drawable-mdpi/task_lock.png similarity index 100% rename from Habitica/res/drawable-mdpi/task_lock.png rename to common/src/main/res/drawable-mdpi/task_lock.png diff --git a/common/src/main/res/drawable-xhdpi/failed_loading.png b/common/src/main/res/drawable-xhdpi/failed_loading.png new file mode 100644 index 000000000..29dbf8210 Binary files /dev/null and b/common/src/main/res/drawable-xhdpi/failed_loading.png differ diff --git a/Habitica/res/drawable-xhdpi/task_icon_calendar.png b/common/src/main/res/drawable-xhdpi/task_icon_calendar.png similarity index 100% rename from Habitica/res/drawable-xhdpi/task_icon_calendar.png rename to common/src/main/res/drawable-xhdpi/task_icon_calendar.png diff --git a/Habitica/res/drawable-xhdpi/task_icon_reminder.png b/common/src/main/res/drawable-xhdpi/task_icon_reminder.png similarity index 100% rename from Habitica/res/drawable-xhdpi/task_icon_reminder.png rename to common/src/main/res/drawable-xhdpi/task_icon_reminder.png diff --git a/Habitica/res/drawable-xhdpi/task_icon_streak.png b/common/src/main/res/drawable-xhdpi/task_icon_streak.png similarity index 100% rename from Habitica/res/drawable-xhdpi/task_icon_streak.png rename to common/src/main/res/drawable-xhdpi/task_icon_streak.png diff --git a/Habitica/res/drawable-xhdpi/task_icon_team.png b/common/src/main/res/drawable-xhdpi/task_icon_team.png similarity index 100% rename from Habitica/res/drawable-xhdpi/task_icon_team.png rename to common/src/main/res/drawable-xhdpi/task_icon_team.png diff --git a/Habitica/res/drawable-xhdpi/task_lock.png b/common/src/main/res/drawable-xhdpi/task_lock.png similarity index 100% rename from Habitica/res/drawable-xhdpi/task_lock.png rename to common/src/main/res/drawable-xhdpi/task_lock.png diff --git a/common/src/main/res/drawable-xxhdpi/failed_loading.png b/common/src/main/res/drawable-xxhdpi/failed_loading.png new file mode 100644 index 000000000..9710e0ab7 Binary files /dev/null and b/common/src/main/res/drawable-xxhdpi/failed_loading.png differ diff --git a/Habitica/res/drawable-xxhdpi/task_icon_calendar.png b/common/src/main/res/drawable-xxhdpi/task_icon_calendar.png similarity index 100% rename from Habitica/res/drawable-xxhdpi/task_icon_calendar.png rename to common/src/main/res/drawable-xxhdpi/task_icon_calendar.png diff --git a/Habitica/res/drawable-xxhdpi/task_icon_reminder.png b/common/src/main/res/drawable-xxhdpi/task_icon_reminder.png similarity index 100% rename from Habitica/res/drawable-xxhdpi/task_icon_reminder.png rename to common/src/main/res/drawable-xxhdpi/task_icon_reminder.png diff --git a/Habitica/res/drawable-xxhdpi/task_icon_streak.png b/common/src/main/res/drawable-xxhdpi/task_icon_streak.png similarity index 100% rename from Habitica/res/drawable-xxhdpi/task_icon_streak.png rename to common/src/main/res/drawable-xxhdpi/task_icon_streak.png diff --git a/Habitica/res/drawable-xxhdpi/task_icon_team.png b/common/src/main/res/drawable-xxhdpi/task_icon_team.png similarity index 100% rename from Habitica/res/drawable-xxhdpi/task_icon_team.png rename to common/src/main/res/drawable-xxhdpi/task_icon_team.png diff --git a/Habitica/res/drawable-xxhdpi/task_lock.png b/common/src/main/res/drawable-xxhdpi/task_lock.png similarity index 100% rename from Habitica/res/drawable-xxhdpi/task_lock.png rename to common/src/main/res/drawable-xxhdpi/task_lock.png diff --git a/Habitica/res/layout/empty_item.xml b/common/src/main/res/layout/empty_item.xml similarity index 95% rename from Habitica/res/layout/empty_item.xml rename to common/src/main/res/layout/empty_item.xml index e439f0418..b3d38777a 100644 --- a/Habitica/res/layout/empty_item.xml +++ b/common/src/main/res/layout/empty_item.xml @@ -26,10 +26,10 @@ @@ -37,7 +37,6 @@ android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/HabiticaButton.Primary" android:visibility="gone" tools:visibility="visible" android:layout_marginTop="@dimen/spacing_large"/> diff --git a/Habitica/res/layout/failed_item.xml b/common/src/main/res/layout/failed_item.xml similarity index 76% rename from Habitica/res/layout/failed_item.xml rename to common/src/main/res/layout/failed_item.xml index 9944a2a90..d43be218c 100644 --- a/Habitica/res/layout/failed_item.xml +++ b/common/src/main/res/layout/failed_item.xml @@ -2,24 +2,23 @@ - + android:src="@drawable/failed_loading" + app:tint="@color/text_quad"/>