diff --git a/Habitica/assets/migrations/Habitica/29.sql b/Habitica/assets/migrations/Habitica/29.sql
new file mode 100644
index 000000000..1f9c5522b
--- /dev/null
+++ b/Habitica/assets/migrations/Habitica/29.sql
@@ -0,0 +1 @@
+ALTER TABLE Preferences ADD COLUMN 'sound' varchar(50);
\ No newline at end of file
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 724a8567a..b8851355b 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -433,4 +433,7 @@ To start, which parts of your life do you want to improve?
Open Market
Your Dailies will next reset the first time you use Habitica after %1$s. Make sure you have completed your Dailies before this time!
+
+ Audio Theme
+ Change Habitica\'s Audio Theme
diff --git a/Habitica/res/values/values.xml b/Habitica/res/values/values.xml
index f4a5b03ef..296e9e3b4 100644
--- a/Habitica/res/values/values.xml
+++ b/Habitica/res/values/values.xml
@@ -86,4 +86,24 @@
- zh_TW
+
+
+ - Off
+ - Daniel the Bard
+ - Watts\' Theme
+ - Gokul Theme
+ - LuneFox\'s Theme
+ - Rosstavo\'s Theme
+ - Dewin\'s Theme
+
+
+
+ - off
+ - danielTheBard
+ - wattsTheme
+ - gokulTheme
+ - luneFoxTheme
+ - rosstavoTheme
+ - dewinTheme
+
diff --git a/Habitica/res/xml/preferences_fragment.xml b/Habitica/res/xml/preferences_fragment.xml
index ed3c5b961..78210bb17 100644
--- a/Habitica/res/xml/preferences_fragment.xml
+++ b/Habitica/res/xml/preferences_fragment.xml
@@ -67,14 +67,19 @@
android:entries="@array/weekdays"
android:entryValues="@array/weekdayValues"
android:summary="@string/pref_first_day_of_the_week_summary"
- android:order="4"/>
+ android:order="5"/>
+
-
> download(List files) {
+ return Observable.from(files)
+ .flatMap(audioFile -> {
+ File file = new File(getFullAudioFilePath(audioFile));
+ if (file.exists()) {
+ // Important, or else the MediaPlayer can't access this file
+ file.setReadable(true, false);
+ audioFile.setFile(file);
+ return Observable.just(audioFile);
+ }
+
+ final Observable fileObservable = Observable.create(sub -> {
+ Request request = new Request.Builder().url(audioFile.getWebUrl()).build();
+
+ Response response;
+ try {
+ response = client.newCall(request).execute();
+ if (!response.isSuccessful()) { throw new IOException(); }
+ } catch (IOException io) {
+ throw OnErrorThrowable.from(OnErrorThrowable.addValueAsLastCause(io, audioFile));
+ }
+
+ if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ try {
+ BufferedSink sink = Okio.buffer(Okio.sink(file));
+ sink.writeAll(response.body().source());
+ sink.flush();
+ sink.close();
+ } catch (IOException io) {
+ throw OnErrorThrowable.from(OnErrorThrowable.addValueAsLastCause(io, audioFile));
+ }
+
+ file.setReadable(true, false);
+ audioFile.setFile(file);
+ sub.onNext(audioFile);
+ sub.onCompleted();
+ }
+ });
+ return fileObservable.subscribeOn(Schedulers.io());
+ }, 5)
+ .toList()
+ .map(ArrayList::new);
+ }
+
+ private String getExternalCacheDir() {
+ return HabiticaApplication.getInstance(HabiticaApplication.currentActivity).getExternalCacheDir().getPath();
+ }
+
+ public String getFullAudioFilePath(SoundFile soundFile) {
+ return getExternalCacheDir() + File.separator + soundFile.getFilePath();
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.java
new file mode 100644
index 000000000..1e14120ca
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.java
@@ -0,0 +1,95 @@
+package com.habitrpg.android.habitica.helpers;
+
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.util.Log;
+
+import com.habitrpg.android.habitica.HabiticaApplication;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+public class SoundManager {
+ public static String SoundAchievementUnlocked = "Achievement_Unlocked";
+ public static String SoundChat = "Chat";
+ public static String SoundDaily = "Daily";
+ public static String SoundDeath = "Death";
+ public static String SoundItemDrop = "Item_Drop";
+ public static String SoundLevelUp = "Level_Up";
+ public static String SoundMinusHabit = "Minus_Habit";
+ public static String SoundPlusHabit = "Plus_Habit";
+ public static String SoundReward = "Reward";
+ public static String SoundTodo = "ToDo";
+
+ @Inject
+ SoundFileLoader soundFileLoader;
+ private String soundTheme;
+
+ private MediaPlayer mp = new MediaPlayer();
+
+ private HashMap loadedSoundFiles;
+
+ public SoundManager(){
+ HabiticaApplication.getInstance(HabiticaApplication.currentActivity).getComponent().inject(this);
+
+ loadedSoundFiles = new HashMap<>();
+ }
+
+ public void setSoundTheme(String soundTheme){
+ this.soundTheme = soundTheme;
+ }
+
+ public Observable> preloadAllFiles() {
+ if(soundTheme == "off") {
+ return Observable.empty();
+ }
+
+ ArrayList soundFiles = new ArrayList<>();
+
+ soundFiles.add(new SoundFile(soundTheme, SoundAchievementUnlocked));
+ soundFiles.add(new SoundFile(soundTheme, SoundChat));
+ soundFiles.add(new SoundFile(soundTheme, SoundDaily));
+ soundFiles.add(new SoundFile(soundTheme, SoundDeath));
+ soundFiles.add(new SoundFile(soundTheme, SoundItemDrop));
+ soundFiles.add(new SoundFile(soundTheme, SoundLevelUp));
+ soundFiles.add(new SoundFile(soundTheme, SoundMinusHabit));
+ soundFiles.add(new SoundFile(soundTheme, SoundPlusHabit));
+ soundFiles.add(new SoundFile(soundTheme, SoundReward));
+ soundFiles.add(new SoundFile(soundTheme, SoundTodo));
+ return soundFileLoader.download(soundFiles);
+ }
+
+ public void clearLoadedFiles(){
+ loadedSoundFiles.clear();
+ }
+
+ public void loadAndPlayAudio(String type){
+ if(soundTheme == "off")
+ {
+ return;
+ }
+
+ if(loadedSoundFiles.containsKey(type)){
+ loadedSoundFiles.get(type).play();
+ } else {
+ ArrayList soundFiles = new ArrayList<>();
+
+ soundFiles.add(new SoundFile(soundTheme, type));
+ soundFileLoader.download(soundFiles).observeOn(Schedulers.newThread()).subscribe(audioFiles1 -> {
+ SoundFile file = soundFiles.get(0);
+
+ loadedSoundFiles.put(type, file);
+ file.play();
+
+ }, throwable -> throwable.printStackTrace());
+ }
+ }
+
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java
index ce5bda5e2..8fb00425b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java
@@ -1,15 +1,16 @@
package com.habitrpg.android.habitica.modules;
-import com.habitrpg.android.habitica.APIHelper;
-import com.habitrpg.android.habitica.HabiticaApplication;
-import com.habitrpg.android.habitica.R;
-import com.habitrpg.android.habitica.helpers.TagsHelper;
-
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.support.v7.preference.PreferenceManager;
+import com.habitrpg.android.habitica.HabiticaApplication;
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.helpers.SoundFileLoader;
+import com.habitrpg.android.habitica.helpers.SoundManager;
+import com.habitrpg.android.habitica.helpers.TagsHelper;
+
import javax.inject.Named;
import javax.inject.Singleton;
@@ -53,4 +54,15 @@ public class AppModule {
public Resources providesResources(Context context) {
return context.getResources();
}
+
+ @Provides
+ public SoundFileLoader providesSoundFileLoader(){
+ return new SoundFileLoader();
+ }
+
+ @Provides
+ @Singleton
+ public SoundManager providesSoundManager() {
+ return new SoundManager();
+ }
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.java b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.java
index b8d9f7f34..7f0a8d294 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.java
@@ -13,6 +13,7 @@ import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
+import android.util.Log;
/**
* Created by keithholliday on 5/29/16.
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java
index 575050a90..90cdd6577 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java
@@ -4,14 +4,12 @@ import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
-
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDoneException;
import android.databinding.DataBindingUtil;
@@ -21,6 +19,10 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -41,12 +43,13 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
-import com.amplitude.api.Amplitude;
import com.habitrpg.android.habitica.APIHelper;
+import com.habitrpg.android.habitica.helpers.SoundFile;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.HostConfig;
import com.habitrpg.android.habitica.NotificationPublisher;
import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.helpers.SoundFileLoader;
import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
import com.habitrpg.android.habitica.callbacks.ItemsCallback;
import com.habitrpg.android.habitica.callbacks.MergeUserCallback;
@@ -84,6 +87,7 @@ import com.habitrpg.android.habitica.events.commands.UnlockPathCommand;
import com.habitrpg.android.habitica.events.commands.UpdateUserCommand;
import com.habitrpg.android.habitica.helpers.AmplitudeManager;
import com.habitrpg.android.habitica.helpers.LanguageHelper;
+import com.habitrpg.android.habitica.helpers.SoundManager;
import com.habitrpg.android.habitica.helpers.TaskAlarmManager;
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager;
import com.habitrpg.android.habitica.ui.AvatarView;
@@ -143,8 +147,6 @@ import com.raizlabs.android.dbflow.structure.BaseModel;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
-import org.json.JSONException;
-import org.json.JSONObject;
import org.solovyev.android.checkout.ActivityCheckout;
import org.solovyev.android.checkout.Checkout;
@@ -157,7 +159,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@@ -167,6 +168,7 @@ import butterknife.BindView;
import retrofit2.adapter.rxjava.HttpException;
import rx.Observable;
import rx.functions.Action1;
+import rx.schedulers.Schedulers;
import static com.habitrpg.android.habitica.ui.helpers.UiUtils.SnackbarDisplayType;
import static com.habitrpg.android.habitica.ui.helpers.UiUtils.showSnackbar;
@@ -179,6 +181,9 @@ public class MainActivity extends BaseActivity implements Action1, Ha
public static final int MIN_LEVEL_FOR_SKILLS = 11;
@Inject
public APIHelper apiHelper;
+
+ @Inject
+ public SoundManager soundManager;
@Inject
public MaintenanceApiService maintenanceService;
public HabitRPGUser user;
@@ -255,6 +260,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha
getResources().updateConfiguration(configuration,
getResources().getDisplayMetrics());
+
+
if (!HabiticaApplication.checkUserAuthentication(this, hostConfig)) {
return;
}
@@ -382,6 +389,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha
apiHelper.languageCode = preferences.getLanguage();
}
+ soundManager.setSoundTheme(preferences.getSound());
+
Calendar calendar = new GregorianCalendar();
TimeZone timeZone = calendar.getTimeZone();
long offset = -TimeUnit.MINUTES.convert(timeZone.getOffset(calendar.getTimeInMillis()), TimeUnit.MILLISECONDS);
@@ -1002,6 +1011,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha
} else {
snackbarMessage = getApplicationContext().getString(R.string.armoireExp);
}
+ soundManager.loadAndPlayAudio(SoundManager.SoundItemDrop);
} else if (!event.Reward.getId().equals("potion")) {
EventBus.getDefault().post(new TaskRemovedEvent(event.Reward.getId()));
}
@@ -1031,6 +1041,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha
}, throwable -> {
});
} else {
+ soundManager.loadAndPlayAudio(SoundManager.SoundReward);
// user created Rewards
apiHelper.apiService.postTaskDirection(rewardKey, TaskDirection.down.toString())
.compose(apiHelper.configureApiCallObserver())
@@ -1205,7 +1216,10 @@ public class MainActivity extends BaseActivity implements Action1, Ha
private void showSnackBarForDataReceived(final TaskDirectionData data) {
if (data.get_tmp() != null) {
if (data.get_tmp().getDrop() != null) {
- new Handler().postDelayed(() -> showSnackbar(MainActivity.this, floatingMenuWrapper, data.get_tmp().getDrop().getDialog(), SnackbarDisplayType.DROP), 3000L);
+ new Handler().postDelayed(() -> {
+ showSnackbar(MainActivity.this, floatingMenuWrapper, data.get_tmp().getDrop().getDialog(), SnackbarDisplayType.DROP);
+ soundManager.loadAndPlayAudio(SoundManager.SoundItemDrop);
+ }, 3000L);
}
}
}
@@ -1284,12 +1298,14 @@ public class MainActivity extends BaseActivity implements Action1, Ha
})
.create();
-
+ soundManager.loadAndPlayAudio(SoundManager.SoundDeath);
this.faintDialog.show();
}
}
private void displayLevelUpDialog(int level) {
+ soundManager.loadAndPlayAudio(SoundManager.SoundLevelUp);
+
SuppressedModals suppressedModals = user.getPreferences().getSuppressModals();
if (suppressedModals != null) {
if (suppressedModals.getLevelUp()) {
@@ -1447,6 +1463,15 @@ public class MainActivity extends BaseActivity implements Action1, Ha
.compose(apiHelper.configureApiCallObserver())
.subscribe(new TaskScoringCallback(this, event.Task.getId()), throwable -> {
});
+
+ switch(event.Task.type){
+ case Task.TYPE_DAILY: {
+ soundManager.loadAndPlayAudio(SoundManager.SoundDaily);
+ } break;
+ case Task.TYPE_TODO: {
+ soundManager.loadAndPlayAudio(SoundManager.SoundTodo);
+ } break;
+ }
}
@Subscribe
@@ -1463,6 +1488,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha
.compose(apiHelper.configureApiCallObserver())
.subscribe(new TaskScoringCallback(this, event.habit.getId()), throwable -> {
});
+
+ soundManager.loadAndPlayAudio(event.Up ? SoundManager.SoundPlusHabit : SoundManager.SoundMinusHabit);
}
@Subscribe
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.java
index 7b7aefac9..250d53ed7 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.java
@@ -1,6 +1,7 @@
package com.habitrpg.android.habitica.ui.fragments;
import com.habitrpg.android.habitica.APIHelper;
+import com.habitrpg.android.habitica.helpers.SoundManager;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
import com.raizlabs.android.dbflow.sql.builder.Condition;
@@ -21,6 +22,9 @@ public abstract class BaseMainFragment extends BaseFragment {
@Inject
public APIHelper apiHelper;
+ @Inject
+ protected SoundManager soundManager;
+
public MainActivity activity;
public TabLayout tabLayout;
public FrameLayout floatingMenuWrapper;
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java
index f0cc564e6..59980b303 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java
@@ -1,7 +1,5 @@
package com.habitrpg.android.habitica.ui.fragments.preferences;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -14,10 +12,10 @@ import android.support.v7.preference.PreferenceScreen;
import com.habitrpg.android.habitica.APIHelper;
import com.habitrpg.android.habitica.HabiticaApplication;
-import com.habitrpg.android.habitica.NotificationPublisher;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.callbacks.MergeUserCallback;
import com.habitrpg.android.habitica.helpers.LanguageHelper;
+import com.habitrpg.android.habitica.helpers.SoundManager;
import com.habitrpg.android.habitica.helpers.TaskAlarmManager;
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager;
import com.habitrpg.android.habitica.prefs.TimePreference;
@@ -30,7 +28,6 @@ import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
import com.raizlabs.android.dbflow.sql.builder.Condition;
import com.raizlabs.android.dbflow.sql.language.Select;
-import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -42,6 +39,8 @@ public class PreferencesFragment extends BasePreferencesFragment implements
@Inject
public APIHelper apiHelper;
+ @Inject
+ public SoundManager soundManager;
private Context context;
private TimePreference timePreference;
private PreferenceScreen pushNotificationsPreference;
@@ -224,6 +223,23 @@ public class PreferencesFragment extends BasePreferencesFragment implements
this.startActivity(intent);
getActivity().finishAffinity();
}
+ } else if (key.equals("audioTheme")) {
+ String newAudioTheme = sharedPreferences.getString(key, "off");
+
+ Map updateData = new HashMap<>();
+ updateData.put("preferences.sound", newAudioTheme);
+ MergeUserCallback mergeUserCallback = new MergeUserCallback(activity, user);
+ apiHelper.apiService.updateUser(updateData)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(mergeUserCallback, throwable -> {
+ });
+
+ Preferences preferences = user.getPreferences();
+ preferences.setSound(newAudioTheme);
+
+ soundManager.setSoundTheme(newAudioTheme);
+
+ soundManager.preloadAllFiles();
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java
index 841b737cd..f35ef6d76 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java
@@ -16,6 +16,7 @@ import com.habitrpg.android.habitica.events.commands.EditTagCommand;
import com.habitrpg.android.habitica.events.commands.FilterTasksByTagsCommand;
import com.habitrpg.android.habitica.events.commands.RefreshUserCommand;
import com.habitrpg.android.habitica.events.commands.UpdateTagCommand;
+import com.habitrpg.android.habitica.helpers.SoundManager;
import com.habitrpg.android.habitica.helpers.TagsHelper;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
import com.habitrpg.android.habitica.ui.activities.TaskFormActivity;
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java
index 4bd6fc991..3918dc849 100644
--- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java
@@ -33,7 +33,7 @@ public class Preferences extends BaseModel {
@Column
private boolean costume, toolbarCollapsed, advancedCollapsed, tagsCollapsed, newTaskEdit, disableClasses, stickyHeader, sleep, hideHeader;
@Column
- private String allocationMode, shirt, skin, size, background, chair, language;
+ private String allocationMode, shirt, skin, size, background, chair, language, sound;
@Column
private int dayStart, timezoneOffset;
@@ -152,6 +152,14 @@ public class Preferences extends BaseModel {
this.size = size;
}
+ public String getSound() {
+ return sound;
+ }
+
+ public void setSound(String sound) {
+ this.sound = sound;
+ }
+
public int getTimezoneOffset() {
return timezoneOffset;
}