add haptic feedback. Fixes #1516

This commit is contained in:
Phillip Thelen 2021-05-25 14:00:59 +02:00
parent 9ca64e091d
commit 9f0ba2151c
8 changed files with 145 additions and 138 deletions

View file

@ -0,0 +1,17 @@
package com.habitrpg.android.habitica.helpers
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.Window
class HapticFeedbackManager {
companion object {
fun tap(view: View) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
}
fun longPress(view: View) {
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
}
}
}

View file

@ -1,133 +0,0 @@
package com.habitrpg.android.habitica.modules;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import androidx.preference.PreferenceManager;
import com.habitrpg.android.habitica.data.ApiClient;
import com.habitrpg.android.habitica.data.ContentRepository;
import com.habitrpg.android.habitica.executors.JobExecutor;
import com.habitrpg.android.habitica.executors.PostExecutionThread;
import com.habitrpg.android.habitica.executors.ThreadExecutor;
import com.habitrpg.android.habitica.executors.UIThread;
import com.habitrpg.android.habitica.helpers.AppConfigManager;
import com.habitrpg.android.habitica.helpers.KeyHelper;
import com.habitrpg.android.habitica.helpers.SoundFileLoader;
import com.habitrpg.android.habitica.helpers.SoundManager;
import com.habitrpg.android.habitica.helpers.TaskFilterHelper;
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AppModule {
public static final String NAMED_USER_ID = "userId";
private Application application;
public AppModule(Application application) {
this.application = application;
}
@Provides
@Singleton
public Context providesContext() {
return application;
}
@Provides
@Singleton
public SharedPreferences provideSharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
@Provides
@Nullable
KeyStore provideKeyStore() {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
return keyStore;
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Provides
@Nullable
KeyHelper provideKeyHelper(Context context, SharedPreferences sharedPreferences, @Nullable KeyStore keyStore) {
if (keyStore == null) {
return null;
}
return KeyHelper.Companion.getInstance(context, sharedPreferences, keyStore);
}
@Provides
@Singleton
public TaskFilterHelper providesTagsHelper() {
return new TaskFilterHelper();
}
@Provides
public Resources providesResources(Context context) {
return context.getResources();
}
@Provides
public SoundFileLoader providesSoundFileLoader(Context context) {
return new SoundFileLoader(context);
}
@Provides
@Singleton
public SoundManager providesSoundManager() {
return new SoundManager();
}
@Provides
@Singleton
ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) {
return jobExecutor;
}
@Provides
@Singleton
PostExecutionThread providePostExecutionThread(UIThread uiThread) {
return uiThread;
}
@Provides
@Singleton
PushNotificationManager pushNotificationManager(ApiClient apiClient, SharedPreferences sharedPreferences, Context context) {
return new PushNotificationManager(apiClient, sharedPreferences, context);
}
@Provides
@Singleton
AppConfigManager providesRemoteConfigManager(ContentRepository contentRepository) {
return new AppConfigManager(contentRepository);
}
}

View file

@ -0,0 +1,115 @@
package com.habitrpg.android.habitica.modules
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import android.content.res.Resources
import androidx.preference.PreferenceManager
import com.habitrpg.android.habitica.data.ApiClient
import com.habitrpg.android.habitica.data.ContentRepository
import com.habitrpg.android.habitica.executors.JobExecutor
import com.habitrpg.android.habitica.executors.PostExecutionThread
import com.habitrpg.android.habitica.executors.ThreadExecutor
import com.habitrpg.android.habitica.executors.UIThread
import com.habitrpg.android.habitica.helpers.*
import com.habitrpg.android.habitica.helpers.KeyHelper.Companion.getInstance
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager
import dagger.Module
import dagger.Provides
import java.io.IOException
import java.security.KeyStore
import java.security.KeyStoreException
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateException
import javax.inject.Singleton
@Module
class AppModule(private val application: Application) {
@Provides
@Singleton
fun providesContext(): Context {
return application
}
@Provides
@Singleton
fun provideSharedPreferences(context: Context?): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(context)
}
@Provides
fun provideKeyStore(): KeyStore? {
try {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
return keyStore
} catch (e: KeyStoreException) {
e.printStackTrace()
} catch (e: CertificateException) {
e.printStackTrace()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
@Provides
fun provideKeyHelper(context: Context?, sharedPreferences: SharedPreferences?, keyStore: KeyStore?): KeyHelper? {
return if (keyStore == null) {
null
} else getInstance(context!!, sharedPreferences!!, keyStore)
}
@Provides
@Singleton
fun providesTagsHelper(): TaskFilterHelper {
return TaskFilterHelper()
}
@Provides
fun providesResources(context: Context): Resources {
return context.resources
}
@Provides
fun providesSoundFileLoader(context: Context?): SoundFileLoader {
return SoundFileLoader(context!!)
}
@Provides
@Singleton
fun providesSoundManager(): SoundManager {
return SoundManager()
}
@Provides
@Singleton
fun provideThreadExecutor(jobExecutor: JobExecutor): ThreadExecutor {
return jobExecutor
}
@Provides
@Singleton
fun providePostExecutionThread(uiThread: UIThread): PostExecutionThread {
return uiThread
}
@Provides
@Singleton
fun pushNotificationManager(apiClient: ApiClient?, sharedPreferences: SharedPreferences?, context: Context?): PushNotificationManager {
return PushNotificationManager(apiClient!!, sharedPreferences!!, context!!)
}
@Provides
@Singleton
fun providesRemoteConfigManager(contentRepository: ContentRepository?): AppConfigManager {
return AppConfigManager(contentRepository)
}
companion object {
const val NAMED_USER_ID = "userId"
}
}

View file

@ -17,6 +17,7 @@ import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.databinding.FragmentQuestDetailBinding
import com.habitrpg.android.habitica.extensions.fromHtml
import com.habitrpg.android.habitica.helpers.HapticFeedbackManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Quest
import com.habitrpg.android.habitica.models.inventory.QuestContent
@ -201,6 +202,7 @@ class QuestDetailFragment : BaseMainFragment<FragmentQuestDetailBinding>() {
}
private fun onQuestBegin() {
HapticFeedbackManager.tap(requireView())
val context = context
if (context != null) {
val alert = HabiticaAlertDialog(context)
@ -218,6 +220,7 @@ class QuestDetailFragment : BaseMainFragment<FragmentQuestDetailBinding>() {
}
private fun onQuestCancel() {
HapticFeedbackManager.tap(requireView())
context?.let {
if (isQuestActive) {
val builder = AlertDialog.Builder(getActivity())
@ -249,6 +252,7 @@ class QuestDetailFragment : BaseMainFragment<FragmentQuestDetailBinding>() {
}
private fun onQuestLeave() {
HapticFeedbackManager.tap(requireView())
val builder = AlertDialog.Builder(getActivity())
.setMessage(if (quest?.active == true) R.string.quest_leave_message else R.string.quest_leave_message_nostart)
.setPositiveButton(R.string.yes) { _, _ ->

View file

@ -16,6 +16,7 @@ import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.databinding.FragmentPartyDetailBinding
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.HapticFeedbackManager
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.QuestContent
@ -353,11 +354,13 @@ class PartyDetailFragment : BaseFragment<FragmentPartyDetailBinding>() {
}
private fun onQuestAccept() {
HapticFeedbackManager.tap(requireView())
viewModel?.acceptQuest()
}
private fun onQuestReject() {
HapticFeedbackManager.tap(requireView())
viewModel?.rejectQuest()
}

View file

@ -21,10 +21,7 @@ import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.databinding.FragmentRefreshRecyclerviewBinding
import com.habitrpg.android.habitica.extensions.setScaledPadding
import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.helpers.SoundManager
import com.habitrpg.android.habitica.helpers.TaskFilterHelper
import com.habitrpg.android.habitica.helpers.*
import com.habitrpg.android.habitica.models.responses.TaskDirection
import com.habitrpg.android.habitica.models.responses.TaskScoringResult
import com.habitrpg.android.habitica.models.tasks.Task
@ -140,6 +137,7 @@ open class TaskRecyclerViewFragment : BaseFragment<FragmentRefreshRecyclerviewBi
}
private fun playSound(direction: TaskDirection) {
HapticFeedbackManager.tap(requireView())
val soundName = when (taskType) {
Task.TYPE_HABIT -> if (direction == TaskDirection.UP) SoundManager.SoundPlusHabit else SoundManager.SoundMinusHabit
Task.TYPE_DAILY -> SoundManager.SoundDaily

View file

@ -23,6 +23,7 @@ import com.habitrpg.android.habitica.extensions.addCancelButton
import com.habitrpg.android.habitica.extensions.addCloseButton
import com.habitrpg.android.habitica.extensions.getShortRemainingString
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.HapticFeedbackManager
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.shops.Shop
@ -336,6 +337,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop
Pair("type", shopItem.purchaseType),
Pair("key", shopItem.key)
))
HapticFeedbackManager.tap(contentView)
val snackbarText = arrayOf("")
val observable: Flowable<Any>
if (shopIdentifier != null && shopIdentifier == Shop.TIME_TRAVELERS_SHOP || "mystery_set" == shopItem.purchaseType || shopItem.currency == "hourglasses") {

View file

@ -10,6 +10,7 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.StatsViewBinding
import com.habitrpg.android.habitica.extensions.layoutInflater
import com.habitrpg.android.habitica.extensions.setTintWith
import com.habitrpg.android.habitica.helpers.HapticFeedbackManager
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
class StatsView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
@ -64,7 +65,6 @@ class StatsView(context: Context, attrs: AttributeSet?) : LinearLayout(context,
private var statColor: Int = 0
init {
val attributes = context.theme?.obtainStyledAttributes(
attrs,
R.styleable.StatsView,
@ -79,6 +79,7 @@ class StatsView(context: Context, attrs: AttributeSet?) : LinearLayout(context,
binding.titleWrapper.background = backgroundDrawable
binding.allocateButton.setOnClickListener {
HapticFeedbackManager.tap(this)
allocateAction?.invoke()
}