diff --git a/Habitica/build.gradle b/Habitica/build.gradle
index df75689a4..f775c402d 100644
--- a/Habitica/build.gradle
+++ b/Habitica/build.gradle
@@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
+apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.noveogroup.android.check'
apply plugin: 'realm-android'
@@ -15,7 +16,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.2.1'
+ classpath 'com.android.tools.build:gradle:4.2.2'
classpath('com.noveogroup.android:check:1.2.5') {
exclude module: 'checkstyle'
exclude module: 'pmd-java'
@@ -49,8 +50,6 @@ dependencies {
}
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
- //Crash Logging
- implementation 'com.google.firebase:firebase-crashlytics:18.0.0'
//Dependency Injection
implementation 'com.google.dagger:dagger:2.36'
@@ -58,9 +57,9 @@ dependencies {
compileOnly 'javax.annotation:javax.annotation-api:1.3.2'
compileOnly 'com.github.pengrad:jdk9-deps:1.0'
//App Compatibility and Material Design
- implementation 'androidx.appcompat:appcompat:1.3.0'
- implementation 'com.google.android.material:material:1.3.0'
- implementation 'androidx.recyclerview:recyclerview:1.2.0'
+ implementation 'androidx.appcompat:appcompat:1.3.1'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.preference:preference-ktx:1.1.1"
@@ -92,7 +91,7 @@ dependencies {
implementation("io.coil-kt:coil-gif:1.2.2")
//Tests
testImplementation 'junit:junit:4.12'
- testImplementation 'androidx.test:core:1.3.0'
+ testImplementation 'androidx.test:core:1.4.0'
testImplementation "com.google.truth:truth:1.0.1"
testImplementation 'org.assertj:assertj-core:2.6.0'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
@@ -106,20 +105,22 @@ dependencies {
//Leak Detection
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
//Push Notifications
- implementation 'com.google.firebase:firebase-core:19.0.0'
- implementation 'com.google.firebase:firebase-messaging:22.0.0'
- implementation 'com.google.firebase:firebase-config:21.0.0'
- implementation 'com.google.firebase:firebase-perf:20.0.0'
- implementation 'com.google.android.gms:play-services-auth:19.0.0'
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.10"
+ implementation platform('com.google.firebase:firebase-bom:28.3.0')
+ implementation 'com.google.firebase:firebase-crashlytics'
+ implementation 'com.google.firebase:firebase-core'
+ implementation 'com.google.firebase:firebase-messaging'
+ implementation 'com.google.firebase:firebase-config'
+ implementation 'com.google.firebase:firebase-perf'
+ implementation 'com.google.android.gms:play-services-auth:19.2.0'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.20"
implementation 'com.nex3z:flow-layout:1.2.2'
- implementation 'androidx.core:core-ktx:1.5.0'
+ implementation 'androidx.core:core-ktx:1.6.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
- implementation "androidx.paging:paging-runtime-ktx:3.0.0"
+ implementation "androidx.paging:paging-runtime-ktx:3.0.1"
implementation 'com.plattysoft.leonids:LeonidsLib:1.3.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0'
@@ -146,8 +147,8 @@ 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 3011
- versionName "3.3"
+ versionCode 3020
+ versionName "3.3.1"
}
buildFeatures {
diff --git a/Habitica/res/layout/widget_habit_button.xml b/Habitica/res/layout/widget_habit_button.xml
index 63adf9e2f..658811657 100644
--- a/Habitica/res/layout/widget_habit_button.xml
+++ b/Habitica/res/layout/widget_habit_button.xml
@@ -4,8 +4,10 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/brand_100"
- android:clipChildren="true">
+ android:background="@drawable/widget_background"
+ android:id="@+id/widget"
+ android:clipChildren="true"
+ android:clipToPadding="true">
\ No newline at end of file
diff --git a/Habitica/res/layout/widget_task_list.xml b/Habitica/res/layout/widget_task_list.xml
index 75d57b887..7b7be4199 100644
--- a/Habitica/res/layout/widget_task_list.xml
+++ b/Habitica/res/layout/widget_task_list.xml
@@ -10,12 +10,12 @@
android:padding="4dp"
android:textSize="18sp"
android:id="@+id/widget_title"
- android:textColor="@android:color/white"/>
+ android:textColor="@color/text_primary"/>
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp">
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 305674ac3..4d87e89ab 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -1176,4 +1176,5 @@
You aren\'t a member of any Challenges.
You aren\'t a member of any Guilds.
Head over to the Discover tab to find some to join!
+ You completed all your tasks. Well done!
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt
index 8d3dc726a..20c905a65 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt
@@ -63,7 +63,7 @@ class AppConfigManager(contentRepository: ContentRepository?) {
}
fun testingLevel(): AppTestingLevel {
- return AppTestingLevel.valueOf(BuildConfig.TESTING_LEVEL.toUpperCase(Locale.US))
+ return AppTestingLevel.valueOf(BuildConfig.TESTING_LEVEL.uppercase())
}
fun enableLocalTaskScoring(): Boolean {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt
index afa69f054..d4ce76fdf 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt
@@ -7,6 +7,10 @@ import android.text.TextUtils
import android.util.AttributeSet
import android.widget.FrameLayout
import android.widget.ImageView
+import androidx.core.graphics.drawable.toBitmap
+import androidx.core.view.drawToBitmap
+import androidx.core.view.marginStart
+import androidx.core.view.marginTop
import coil.clear
import coil.load
import com.habitrpg.android.habitica.BuildConfig
@@ -62,12 +66,15 @@ class AvatarView : FrameLayout {
if (BuildConfig.DEBUG && (avatar == null || avatarRectF == null)) {
error("Assertion failed")
}
- val canvasRect = Rect()
- avatarRectF?.round(canvasRect)
+ val canvasRect = Rect(0, 0, 140.dpToPx(context), 147.dpToPx(context))
if (canvasRect.isEmpty) return null
avatarBitmap = Bitmap.createBitmap(canvasRect.width(), canvasRect.height(), Bitmap.Config.ARGB_8888)
avatarBitmap?.let { avatarCanvas = Canvas(it) }
- draw(avatarCanvas)
+ imageViewHolder.forEach {
+ val lp = it.layoutParams
+ val bitmap = it.drawable?.toBitmap(lp.width, lp.height) ?: return@forEach
+ avatarCanvas?.drawBitmap(bitmap, Rect(0, 0, bitmap.width, bitmap.height), Rect(it.marginStart, it.marginTop, bitmap.width, bitmap.height), null)
+ }
return avatarBitmap
}
@@ -148,6 +155,8 @@ class AvatarView : FrameLayout {
val layoutParams = imageView.layoutParams as? LayoutParams
layoutParams?.topMargin = bounds.top
layoutParams?.marginStart = bounds.left
+ layoutParams?.width = bounds.right
+ layoutParams?.height = bounds.bottom
imageView.layoutParams = layoutParams
onLayerComplete()
})
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt
index d0dbd4abf..9773d233e 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt
@@ -24,7 +24,6 @@ import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.activities.TaskFormActivity
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
-import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemRecyclerFragment
import com.habitrpg.android.habitica.ui.views.navigation.HabiticaBottomNavigationViewListener
import com.habitrpg.android.habitica.ui.views.tasks.TaskFilterDialog
import io.reactivex.rxjava3.disposables.Disposable
@@ -86,10 +85,10 @@ class TasksFragment : BaseMainFragment(), SearchView.O
switchToTaskTab(taskType)
} else {
when (sharedPreferences.getString("launch_screen", "")) {
- "/user/tasks/habits" -> binding?.viewPager?.currentItem = 0
- "/user/tasks/dailies" -> binding?.viewPager?.currentItem = 1
- "/user/tasks/todos" -> binding?.viewPager?.currentItem = 2
- "/user/tasks/rewards" -> binding?.viewPager?.currentItem = 3
+ "/user/tasks/habits" -> onTabSelected(Task.TYPE_HABIT, false)
+ "/user/tasks/dailies" -> onTabSelected(Task.TYPE_DAILY, false)
+ "/user/tasks/todos" -> onTabSelected(Task.TYPE_TODO, false)
+ "/user/tasks/rewards" -> onTabSelected(Task.TYPE_REWARD, false)
}
}
}
@@ -104,6 +103,7 @@ class TasksFragment : BaseMainFragment(), SearchView.O
3 -> Task.TYPE_REWARD
else -> Task.TYPE_HABIT
}
+ binding?.viewPager?.currentItem = binding?.viewPager?.currentItem ?: 0
bottomNavigation?.listener = this
bottomNavigation?.canAddTasks = true
}
@@ -397,7 +397,7 @@ class TasksFragment : BaseMainFragment(), SearchView.O
}
- override fun onTabSelected(taskType: String) {
+ override fun onTabSelected(taskType: String, smooth: Boolean) {
val newItem = when (taskType) {
Task.TYPE_HABIT -> 0
Task.TYPE_DAILY -> 1
@@ -405,7 +405,7 @@ class TasksFragment : BaseMainFragment(), SearchView.O
Task.TYPE_REWARD -> 3
else -> 0
}
- binding?.viewPager?.currentItem = newItem
+ binding?.viewPager?.setCurrentItem(newItem, smooth)
updateBottomBarBadges()
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TeamBoardFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TeamBoardFragment.kt
index 5c0080b35..91f6ee61c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TeamBoardFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TeamBoardFragment.kt
@@ -400,7 +400,7 @@ class TeamBoardFragment : BaseMainFragment(), SearchVi
var lastTaskFormOpen: Date? = null
}
- override fun onTabSelected(taskType: String) {
+ override fun onTabSelected(taskType: String, smooth: Boolean) {
val newItem = when (taskType) {
Task.TYPE_HABIT -> 0
Task.TYPE_DAILY -> 1
@@ -408,7 +408,7 @@ class TeamBoardFragment : BaseMainFragment(), SearchVi
Task.TYPE_REWARD -> 3
else -> 0
}
- binding?.viewPager?.currentItem = newItem
+ binding?.viewPager?.setCurrentItem(newItem, smooth)
updateBottomBarBadges()
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/navigation/HabiticaBottomNavigationView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/navigation/HabiticaBottomNavigationView.kt
index b19922156..72884454d 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/navigation/HabiticaBottomNavigationView.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/navigation/HabiticaBottomNavigationView.kt
@@ -22,7 +22,7 @@ import com.habitrpg.android.habitica.extensions.setTintWith
import com.habitrpg.android.habitica.models.tasks.Task
interface HabiticaBottomNavigationViewListener {
- fun onTabSelected(taskType: String)
+ fun onTabSelected(taskType: String, smooth: Boolean)
fun onAdd(taskType: String)
}
@@ -56,7 +56,7 @@ class HabiticaBottomNavigationView @JvmOverloads constructor(
field = value
if (wasChanged) {
updateItemSelection()
- listener?.onTabSelected(value)
+ listener?.onTabSelected(value, true)
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt
index e703ce359..84771a688 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt
@@ -6,9 +6,11 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.view.View
+import android.view.ViewGroup
import android.widget.RemoteViews
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.extensions.dpToPx
import com.habitrpg.android.habitica.helpers.HealthFormatter
import com.habitrpg.android.habitica.helpers.NumberAbbreviator
import com.habitrpg.android.habitica.helpers.RxErrorHandler
@@ -22,6 +24,7 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
private var appWidgetManager: AppWidgetManager? = null
private var showManaBar: Boolean = true
+ private var showAvatar: Boolean = true
override fun layoutResourceId(): Int {
return R.layout.widget_avatar_stats
@@ -44,18 +47,17 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
}
override fun configureRemoteViews(remoteViews: RemoteViews, widgetId: Int, columns: Int, rows: Int): RemoteViews {
- if (columns > 3) {
- remoteViews.setViewVisibility(R.id.avatar_view, View.GONE)
+ showAvatar = columns > 3
+ if (showAvatar) {
+ remoteViews.setViewVisibility(R.id.avatar_view, View.VISIBLE)
} else {
remoteViews.setViewVisibility(R.id.avatar_view, View.GONE)
}
showManaBar = rows > 1
if (rows > 1) {
- remoteViews.setViewVisibility(R.id.mp_wrapper, View.VISIBLE)
remoteViews.setViewVisibility(R.id.detail_info_view, View.VISIBLE)
} else {
- remoteViews.setViewVisibility(R.id.mp_wrapper, View.GONE)
remoteViews.setViewVisibility(R.id.detail_info_view, View.GONE)
}
@@ -109,13 +111,17 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
remoteViews.setImageViewBitmap(R.id.gold_icon, HabiticaIconsHelper.imageOfGold())
remoteViews.setTextViewText(R.id.lvl_tv, context.getString(R.string.user_level, user.stats?.lvl ?: 0))
- val avatarView = AvatarView(context, showBackground = true, showMount = true, showPet = true)
-
- avatarView.setAvatar(user)
- val finalRemoteViews = remoteViews
- avatarView.onAvatarImageReady { bitmap ->
- finalRemoteViews.setImageViewBitmap(R.id.avatar_view, bitmap)
- appWidgetManager.partiallyUpdateAppWidget(allWidgetIds, finalRemoteViews)
+ if (showAvatar) {
+ val avatarView =
+ AvatarView(context, showBackground = true, showMount = true, showPet = true)
+ val layoutParams = ViewGroup.LayoutParams(140.dpToPx(context), 147.dpToPx(context))
+ avatarView.layoutParams = layoutParams
+ avatarView.setAvatar(user)
+ val finalRemoteViews = remoteViews
+ avatarView.onAvatarImageReady { bitmap ->
+ finalRemoteViews.setImageViewBitmap(R.id.avatar_view, bitmap)
+ appWidgetManager.partiallyUpdateAppWidget(allWidgetIds, finalRemoteViews)
+ }
}
val openAppIntent = Intent(context.applicationContext, MainActivity::class.java)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.kt
index 78a05c28b..8bd812370 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.kt
@@ -11,6 +11,7 @@ import android.os.IBinder
import android.text.SpannableStringBuilder
import android.text.style.DynamicDrawableSpan
import android.view.View
+import android.view.ViewOutlineProvider
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.HabiticaBaseApplication
@@ -22,6 +23,7 @@ import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
import java.util.*
import javax.inject.Inject
+import kotlin.math.min
class HabitButtonWidgetService : Service() {
@Inject
@@ -57,8 +59,7 @@ class HabitButtonWidgetService : Service() {
val parsedText = MarkdownParser.parseMarkdown(task.text)
val builder = SpannableStringBuilder(parsedText)
-
- remoteViews.setTextViewText(R.id.habit_title, builder)
+ remoteViews.setTextViewText(R.id.habit_title, builder.substring(0, min(builder.length, 70)))
if (task.up != true) {
remoteViews.setViewVisibility(R.id.btnPlusWrapper, View.GONE)
diff --git a/build.gradle b/build.gradle
index 20487b61d..baa00dc74 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,9 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.5.10'
- ext.build_tools_version = '29.0.0'
- ext.sdk_version = 30
+ ext.kotlin_version = '1.5.20'
repositories {
google()
@@ -11,10 +9,10 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.2.1'
+ classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.google.gms:google-services:4.3.8'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.6.1'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
classpath "io.realm:realm-gradle-plugin:10.3.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.1.0"
diff --git a/fastlane/README.md b/fastlane/README.md
index 305cebbb2..7507466dd 100644
--- a/fastlane/README.md
+++ b/fastlane/README.md
@@ -44,6 +44,6 @@ Deploy a new version to the Google Play
----
-This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
+This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
diff --git a/fastlane/changelog.txt b/fastlane/changelog.txt
index de0221881..a0fb0b394 100644
--- a/fastlane/changelog.txt
+++ b/fastlane/changelog.txt
@@ -1 +1 @@
-In this update, we’ve improved more of our notifications so they bring you to the relevant screen when tapped. When customizing your avatar, you’ll be able to see your avatar updating in real time as you select different options. You can also see your current Gems when gifting Gems from your balance now. We've fixed a few bugs too, including one where tasks wouldn’t load when the app is left running in the background for awhile, and another where Dailies wouldn’t filter properly on launch.
+We’ve improved more of our notifications so they bring you to the relevant screen when tapped. When customizing your avatar, you’ll be able to see your avatar updating in real time as you select different options. You can also see your current Gems when gifting Gems from your balance now. We’ve fixed a few bugs too, including one where tasks wouldn’t load when the app is left running in the background, the stats widget works again, and another where Dailies wouldn’t filter properly on launch.