mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-08-01 03:30:34 +00:00
add haptic feedback. Fixes #1516
This commit is contained in:
parent
9ca64e091d
commit
9f0ba2151c
8 changed files with 145 additions and 138 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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) { _, _ ->
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue