diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 54752597f..6605314a8 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -801,6 +801,7 @@
New reminder
Streak
Update available: %1$s (%2$d)
+ You can contact us and a member of our team will do their best to help!
Post a message in the %s to have your questions answered by a fellow player.
Need more help?
Become a %s
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/FAQOverviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/FAQOverviewFragment.kt
index 8ffcd86a9..518a7ba05 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/FAQOverviewFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/FAQOverviewFragment.kt
@@ -1,7 +1,15 @@
package com.habitrpg.android.habitica.ui.fragments.support
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
import android.os.Bundle
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.TextPaint
import android.text.method.LinkMovementMethod
+import android.text.style.ClickableSpan
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -20,21 +28,32 @@ import com.habitrpg.android.habitica.databinding.SupportFaqItemBinding
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
+import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
import com.habitrpg.android.habitica.ui.views.UsernameLabel
import com.habitrpg.common.habitica.extensions.dpToPx
import com.habitrpg.common.habitica.extensions.layoutInflater
+import com.habitrpg.common.habitica.helpers.AppTestingLevel
+import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.habitrpg.common.habitica.helpers.launchCatching
import com.habitrpg.common.habitica.helpers.setMarkdown
import com.habitrpg.common.habitica.models.PlayerTier
+import com.jaredrummler.android.device.DeviceName
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class FAQOverviewFragment : BaseMainFragment() {
+ private var deviceInfo: DeviceName.DeviceInfo? = null
override var binding: FragmentFaqOverviewBinding? = null
+ @Inject
+ lateinit var appConfigManager: AppConfigManager
+ @Inject
+ lateinit var userViewModel: MainUserViewModel
+
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFaqOverviewBinding {
return FragmentFaqOverviewBinding.inflate(inflater, container, false)
}
@@ -44,6 +63,25 @@ class FAQOverviewFragment : BaseMainFragment() {
@Inject
lateinit var configManager: AppConfigManager
+ private val versionName: String by lazy {
+ try {
+ mainActivity?.packageManager?.getPackageInfo(mainActivity?.packageName ?: "", 0)?.versionName
+ ?: ""
+ } catch (e: PackageManager.NameNotFoundException) {
+ ""
+ }
+ }
+
+ private val versionCode: Int by lazy {
+ try {
+ @Suppress("DEPRECATION")
+ mainActivity?.packageManager?.getPackageInfo(mainActivity?.packageName ?: "", 0)?.versionCode
+ ?: 0
+ } catch (e: PackageManager.NameNotFoundException) {
+ 0
+ }
+ }
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -62,6 +100,12 @@ class FAQOverviewFragment : BaseMainFragment() {
binding?.npcHeader?.namePlate?.setText(R.string.tavern_owner)
binding?.npcHeader?.descriptionView?.isVisible = false
+ lifecycleScope.launch(ExceptionHandler.coroutine()) {
+ DeviceName.with(context).request { info, _ ->
+ deviceInfo = info
+ }
+ }
+
binding?.healthSection?.findViewById(R.id.icon_view)?.setImageBitmap(
HabiticaIconsHelper.imageOfHeartLarge()
)
@@ -87,8 +131,23 @@ class FAQOverviewFragment : BaseMainFragment() {
binding?.contribTierSection?.findViewById(R.id.icon_view)?.setImageResource(R.drawable.contributor_icon)
addPlayerTiers()
- binding?.moreHelpTextView?.setMarkdown(context?.getString(R.string.need_help_header_description, "[Habitica Help Guild](https://habitica.com/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)"))
- binding?.moreHelpTextView?.setOnClickListener { MainNavigationController.navigate(R.id.guildFragment, bundleOf("groupID" to "5481ccf3-5d2d-48a9-a871-70a7380cee5a")) }
+ val fullText = getString(R.string.need_help_description)
+ val clickableText = "contact us"
+ val spannableString = SpannableStringBuilder(fullText)
+ val clickableSpan = object : ClickableSpan() {
+ override fun onClick(textView: View) {
+ sendEmail("[Android] Question")
+ }
+ override fun updateDrawState(ds: TextPaint) {
+ super.updateDrawState(ds)
+ ds.isUnderlineText = false
+ }
+ }
+ val startIndex = fullText.indexOf(clickableText)
+ val endIndex = startIndex + clickableText.length
+ spannableString.setSpan(clickableSpan, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+
+ binding?.moreHelpTextView?.text = spannableString
binding?.moreHelpTextView?.movementMethod = LinkMovementMethod.getInstance()
this.loadArticles()
@@ -122,6 +181,56 @@ class FAQOverviewFragment : BaseMainFragment() {
}
}
+ private fun sendEmail(subject: String) {
+ val version = Build.VERSION.SDK_INT
+ val deviceName = deviceInfo?.name ?: DeviceName.getDeviceName()
+ val manufacturer = deviceInfo?.manufacturer ?: Build.MANUFACTURER
+ val newLine = "%0D%0A"
+ var bodyOfEmail = Uri.encode("Device: $manufacturer $deviceName") +
+ newLine + Uri.encode("Android Version: $version") +
+ newLine + Uri.encode("AppVersion: " + getString(
+ R.string.version_info,
+ versionName,
+ versionCode
+ )
+ )
+
+ if (appConfigManager.testingLevel().name != AppTestingLevel.PRODUCTION.name) {
+ bodyOfEmail += " " + Uri.encode(appConfigManager.testingLevel().name)
+ }
+ bodyOfEmail += newLine + Uri.encode("User ID: ${userViewModel.userID}")
+
+ userViewModel.user.value?.let { user ->
+ bodyOfEmail += newLine + Uri.encode("Level: " + (user.stats?.lvl ?: 0)) +
+ newLine + Uri.encode(
+ "Class: " + (
+ if (user.preferences?.disableClasses == true) "Disabled" else (
+ user.stats?.habitClass
+ ?: "None"
+ )
+ )
+ ) +
+ newLine + Uri.encode("Is in Inn: " + (user.preferences?.sleep ?: false)) +
+ newLine + Uri.encode("Uses Costume: " + (user.preferences?.costume ?: false)) +
+ newLine + Uri.encode("Custom Day Start: " + (user.preferences?.dayStart ?: 0)) +
+ newLine + Uri.encode(
+ "Timezone Offset: " + (user.preferences?.timezoneOffset ?: 0)
+ )
+ }
+
+ bodyOfEmail += "%0D%0ADetails:%0D%0A%0D%0A"
+
+ mainActivity?.let {
+ val emailIntent = Intent(Intent.ACTION_SENDTO)
+ val mailto = "mailto:" + appConfigManager.supportEmail() +
+ "?subject=" + Uri.encode(subject) +
+ "&body=" + bodyOfEmail
+ emailIntent.data = Uri.parse(mailto)
+
+ startActivity(Intent.createChooser(emailIntent, "Choose an Email client:"))
+ }
+ }
+
private fun addPlayerTiers() {
val tiers = PlayerTier.getTiers()
for (tier in tiers) {