Add feature flags that contains new image loader flag.
This allows to release new versions of the app with unfinished/ not fully implemented features. Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
This commit is contained in:
parent
02467cb05b
commit
a63c47112c
|
@ -44,6 +44,7 @@ import org.moire.ultrasonic.domain.MusicDirectory;
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||||
import org.moire.ultrasonic.domain.PlayerState;
|
import org.moire.ultrasonic.domain.PlayerState;
|
||||||
import org.moire.ultrasonic.domain.Share;
|
import org.moire.ultrasonic.domain.Share;
|
||||||
|
import org.moire.ultrasonic.featureflags.Feature;
|
||||||
import org.moire.ultrasonic.service.*;
|
import org.moire.ultrasonic.service.*;
|
||||||
import org.moire.ultrasonic.subsonic.SubsonicImageLoaderProxy;
|
import org.moire.ultrasonic.subsonic.SubsonicImageLoaderProxy;
|
||||||
import org.moire.ultrasonic.util.*;
|
import org.moire.ultrasonic.util.*;
|
||||||
|
@ -790,9 +791,13 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void clearImageLoader()
|
public synchronized void clearImageLoader() {
|
||||||
{
|
if (IMAGE_LOADER != null &&
|
||||||
if (IMAGE_LOADER != null && IMAGE_LOADER.isRunning()) IMAGE_LOADER.clear();
|
IMAGE_LOADER.isRunning()) {
|
||||||
|
IMAGE_LOADER.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_LOADER = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized ImageLoader getImageLoader() {
|
public synchronized ImageLoader getImageLoader() {
|
||||||
|
@ -802,10 +807,18 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||||
this,
|
this,
|
||||||
Util.getImageLoaderConcurrency(this)
|
Util.getImageLoaderConcurrency(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
boolean isNewImageLoaderEnabled = ((UApp) getApplication()).getFeaturesStorage()
|
||||||
|
.isFeatureEnabled(Feature.NEW_IMAGE_DOWNLOADER);
|
||||||
|
if (isNewImageLoaderEnabled) {
|
||||||
IMAGE_LOADER = new SubsonicImageLoaderProxy(
|
IMAGE_LOADER = new SubsonicImageLoaderProxy(
|
||||||
legacyImageLoader,
|
legacyImageLoader,
|
||||||
((UApp) getApplication()).getSubsonicImageLoader()
|
((UApp) getApplication()).getSubsonicImageLoader()
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
IMAGE_LOADER = legacyImageLoader;
|
||||||
|
}
|
||||||
|
|
||||||
IMAGE_LOADER.startImageLoader();
|
IMAGE_LOADER.startImageLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,29 +4,21 @@ import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.*;
|
||||||
import android.preference.EditTextPreference;
|
|
||||||
import android.preference.ListPreference;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceCategory;
|
|
||||||
import android.preference.PreferenceFragment;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.provider.SearchRecentSuggestions;
|
import android.provider.SearchRecentSuggestions;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.moire.ultrasonic.R;
|
import org.moire.ultrasonic.R;
|
||||||
import org.moire.ultrasonic.activity.ServerSettingsActivity;
|
import org.moire.ultrasonic.activity.ServerSettingsActivity;
|
||||||
import org.moire.ultrasonic.activity.SubsonicTabActivity;
|
import org.moire.ultrasonic.activity.SubsonicTabActivity;
|
||||||
|
import org.moire.ultrasonic.app.UApp;
|
||||||
|
import org.moire.ultrasonic.featureflags.Feature;
|
||||||
|
import org.moire.ultrasonic.featureflags.FeatureStorage;
|
||||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider;
|
import org.moire.ultrasonic.provider.SearchSuggestionProvider;
|
||||||
import org.moire.ultrasonic.service.DownloadService;
|
import org.moire.ultrasonic.service.DownloadService;
|
||||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||||
import org.moire.ultrasonic.util.Constants;
|
import org.moire.ultrasonic.util.*;
|
||||||
import org.moire.ultrasonic.util.FileUtil;
|
|
||||||
import org.moire.ultrasonic.util.ImageLoader;
|
|
||||||
import org.moire.ultrasonic.util.TimeSpanPreference;
|
|
||||||
import org.moire.ultrasonic.util.Util;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
@ -115,6 +107,7 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
sharingDefaultGreeting.setText(Util.getShareGreeting(getActivity()));
|
sharingDefaultGreeting.setText(Util.getShareGreeting(getActivity()));
|
||||||
setupClearSearchPreference();
|
setupClearSearchPreference();
|
||||||
setupGaplessControlSettingsV14();
|
setupGaplessControlSettingsV14();
|
||||||
|
setupFeatureFlagsPreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -178,6 +171,24 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupFeatureFlagsPreferences() {
|
||||||
|
CheckBoxPreference ffImageLoader = (CheckBoxPreference) findPreference(
|
||||||
|
Constants.PREFERENCES_KEY_FF_IMAGE_LOADER);
|
||||||
|
|
||||||
|
final FeatureStorage featureStorage = ((UApp) getActivity().getApplication()).getFeaturesStorage();
|
||||||
|
if (ffImageLoader != null) {
|
||||||
|
ffImageLoader.setChecked(featureStorage.isFeatureEnabled(Feature.NEW_IMAGE_DOWNLOADER));
|
||||||
|
ffImageLoader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||||
|
featureStorage.changeFeatureFlag(Feature.NEW_IMAGE_DOWNLOADER, (Boolean) o);
|
||||||
|
((SubsonicTabActivity) getActivity()).clearImageLoader();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setupGaplessControlSettingsV14() {
|
private void setupGaplessControlSettingsV14() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
PreferenceCategory playbackControlSettings =
|
PreferenceCategory playbackControlSettings =
|
||||||
|
|
|
@ -130,6 +130,7 @@ public final class Constants
|
||||||
public static final String PREFERENCES_KEY_SHOW_ALL_SONGS_BY_ARTIST = "showAllSongsByArtist";
|
public static final String PREFERENCES_KEY_SHOW_ALL_SONGS_BY_ARTIST = "showAllSongsByArtist";
|
||||||
public static final String PREFERENCES_KEY_SCAN_MEDIA = "scanMedia";
|
public static final String PREFERENCES_KEY_SCAN_MEDIA = "scanMedia";
|
||||||
public static final String PREFERENCES_KEY_IMAGE_LOADER_CONCURRENCY = "imageLoaderConcurrency";
|
public static final String PREFERENCES_KEY_IMAGE_LOADER_CONCURRENCY = "imageLoaderConcurrency";
|
||||||
|
public static final String PREFERENCES_KEY_FF_IMAGE_LOADER = "ff_new_image_loader";
|
||||||
|
|
||||||
// Number of free trial days for non-licensed servers.
|
// Number of free trial days for non-licensed servers.
|
||||||
public static final int FREE_TRIAL_DAYS = 30;
|
public static final int FREE_TRIAL_DAYS = 30;
|
||||||
|
|
|
@ -5,7 +5,9 @@ import org.koin.android.ext.android.get
|
||||||
import org.koin.android.ext.android.startKoin
|
import org.koin.android.ext.android.startKoin
|
||||||
import org.moire.ultrasonic.di.baseNetworkModule
|
import org.moire.ultrasonic.di.baseNetworkModule
|
||||||
import org.moire.ultrasonic.di.directoriesModule
|
import org.moire.ultrasonic.di.directoriesModule
|
||||||
|
import org.moire.ultrasonic.di.featureFlagsModule
|
||||||
import org.moire.ultrasonic.di.musicServiceModule
|
import org.moire.ultrasonic.di.musicServiceModule
|
||||||
|
import org.moire.ultrasonic.featureflags.FeatureStorage
|
||||||
import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader
|
import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
|
|
||||||
|
@ -17,6 +19,7 @@ class UApp : Application() {
|
||||||
startKoin(this, listOf(
|
startKoin(this, listOf(
|
||||||
directoriesModule,
|
directoriesModule,
|
||||||
baseNetworkModule,
|
baseNetworkModule,
|
||||||
|
featureFlagsModule(this),
|
||||||
musicServiceModule(sharedPreferences, this)
|
musicServiceModule(sharedPreferences, this)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -27,4 +30,11 @@ class UApp : Application() {
|
||||||
fun getSubsonicImageLoader(): SubsonicImageLoader {
|
fun getSubsonicImageLoader(): SubsonicImageLoader {
|
||||||
return get()
|
return get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary method to get features storage.
|
||||||
|
*/
|
||||||
|
fun getFeaturesStorage(): FeatureStorage {
|
||||||
|
return get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.moire.ultrasonic.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.koin.dsl.module.applicationContext
|
||||||
|
import org.moire.ultrasonic.featureflags.FeatureStorage
|
||||||
|
|
||||||
|
fun featureFlagsModule(
|
||||||
|
context: Context
|
||||||
|
) = applicationContext {
|
||||||
|
factory { FeatureStorage(context) }
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.moire.ultrasonic.featureflags
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a list of new features/implementations that are not yet finished,
|
||||||
|
* but possible to try it out.
|
||||||
|
*/
|
||||||
|
enum class Feature(
|
||||||
|
val defaultValue: Boolean
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Enables new image downloader implementation.
|
||||||
|
*/
|
||||||
|
NEW_IMAGE_DOWNLOADER(false)
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.moire.ultrasonic.featureflags
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
private const val SP_NAME = "feature_flags"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides storage for current feature flag state.
|
||||||
|
*/
|
||||||
|
class FeatureStorage(
|
||||||
|
context: Context
|
||||||
|
) {
|
||||||
|
private val sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get [feature] current enabled state.
|
||||||
|
*/
|
||||||
|
fun isFeatureEnabled(feature: Feature): Boolean {
|
||||||
|
return sp.getBoolean(feature.name, feature.defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update [feature] enabled state to [isEnabled].
|
||||||
|
*/
|
||||||
|
fun changeFeatureFlag(
|
||||||
|
feature: Feature,
|
||||||
|
isEnabled: Boolean
|
||||||
|
) {
|
||||||
|
sp.edit().putBoolean(feature.name, isEnabled).apply()
|
||||||
|
}
|
||||||
|
}
|
|
@ -436,5 +436,10 @@
|
||||||
<string name="api.subsonic.trial_period_is_over">El período de prueba ha terminado.</string>
|
<string name="api.subsonic.trial_period_is_over">El período de prueba ha terminado.</string>
|
||||||
<string name="api.subsonic.upgrade_client">Versiones incompatibles. Por favor actualiza la aplicación de Android UltraSonic.</string>
|
<string name="api.subsonic.upgrade_client">Versiones incompatibles. Por favor actualiza la aplicación de Android UltraSonic.</string>
|
||||||
<string name="api.subsonic.upgrade_server">Versiones incompatibles. Por favor actualiza el servidor de Subsonic.</string>
|
<string name="api.subsonic.upgrade_server">Versiones incompatibles. Por favor actualiza el servidor de Subsonic.</string>
|
||||||
|
<string name="feature_flags_category_title">Banderas de características</string>
|
||||||
|
<string name="feature_flags_image_loader_description">Permite la implementación de un nuevo cargador de imágenes.
|
||||||
|
Actualmente no guarda la imagen en el almacenamiento del dispositivo y sólo utiliza caché en la memoria.
|
||||||
|
</string>
|
||||||
|
<string name="feature_flags_image_loader_title">Habilitar nuevo cargador de imágenes</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -436,5 +436,11 @@
|
||||||
<string name="api.subsonic.trial_period_is_over">La période d\'essai est terminée.</string>
|
<string name="api.subsonic.trial_period_is_over">La période d\'essai est terminée.</string>
|
||||||
<string name="api.subsonic.upgrade_client">Versions incompatible. Veuillez mette à jour l\'application Android UltraSonic.</string>
|
<string name="api.subsonic.upgrade_client">Versions incompatible. Veuillez mette à jour l\'application Android UltraSonic.</string>
|
||||||
<string name="api.subsonic.upgrade_server">Versions incompatible. Veuillez mette à jour le serveur Subsonic.</string>
|
<string name="api.subsonic.upgrade_server">Versions incompatible. Veuillez mette à jour le serveur Subsonic.</string>
|
||||||
|
<string name="feature_flags_category_title">Drapeaux des fonctionnalités</string>
|
||||||
|
<string name="feature_flags_image_loader_description">Permet l\'implémentation d\'un nouveau chargeur d\'images.
|
||||||
|
Actuellement, il n\'enregistre pas l\'image dans le stockage de l\'appareil et n\'utilise que le cache en
|
||||||
|
mémoire.
|
||||||
|
</string>
|
||||||
|
<string name="feature_flags_image_loader_title">Activer le nouveau chargeur d\'images</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -436,5 +436,10 @@
|
||||||
<string name="api.subsonic.trial_period_is_over">A próbaidő vége.</string>
|
<string name="api.subsonic.trial_period_is_over">A próbaidő vége.</string>
|
||||||
<string name="api.subsonic.upgrade_client">Nem kompatibilis verzió. Kérjük, frissítse az UltraSonic Android alkalmazást!</string>
|
<string name="api.subsonic.upgrade_client">Nem kompatibilis verzió. Kérjük, frissítse az UltraSonic Android alkalmazást!</string>
|
||||||
<string name="api.subsonic.upgrade_server">Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót!</string>
|
<string name="api.subsonic.upgrade_server">Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót!</string>
|
||||||
|
<string name="feature_flags_image_loader_description">Engedélyezi az új képbetöltő megvalósítását. Jelenleg nem
|
||||||
|
tárolja a képet az eszköz tárolójában, és csak a memóriában tárolja a gyorsítótárat.
|
||||||
|
</string>
|
||||||
|
<string name="feature_flags_category_title">Jellemzők Zászlók</string>
|
||||||
|
<string name="feature_flags_image_loader_title">Engedélyezzen új képbetöltőt</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -436,5 +436,10 @@
|
||||||
<string name="api.subsonic.trial_period_is_over">O período de avaliação acabou.</string>
|
<string name="api.subsonic.trial_period_is_over">O período de avaliação acabou.</string>
|
||||||
<string name="api.subsonic.upgrade_client">Versões incompativeis. Atualize o aplicativo UltraSonic para Android.</string>
|
<string name="api.subsonic.upgrade_client">Versões incompativeis. Atualize o aplicativo UltraSonic para Android.</string>
|
||||||
<string name="api.subsonic.upgrade_server">Versões incompativeis. Atualize o servidor UltraSonic.</string>
|
<string name="api.subsonic.upgrade_server">Versões incompativeis. Atualize o servidor UltraSonic.</string>
|
||||||
|
<string name="feature_flags_image_loader_description">Permite nova implementação do carregador de imagens.
|
||||||
|
Atualmente, ele não salva a imagem no armazenamento do dispositivo e usa apenas o cache na memória.
|
||||||
|
</string>
|
||||||
|
<string name="feature_flags_category_title">Bandeiras de recursos</string>
|
||||||
|
<string name="feature_flags_image_loader_title">Ativar novo carregador de imagens</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -436,5 +436,10 @@
|
||||||
<string name="api.subsonic.trial_period_is_over">O período de avaliação acabou.</string>
|
<string name="api.subsonic.trial_period_is_over">O período de avaliação acabou.</string>
|
||||||
<string name="api.subsonic.upgrade_client">Versões incompativeis. Atualize o aplicativo UltraSonic para Android.</string>
|
<string name="api.subsonic.upgrade_client">Versões incompativeis. Atualize o aplicativo UltraSonic para Android.</string>
|
||||||
<string name="api.subsonic.upgrade_server">Versões incompativeis. Atualize o servidor UltraSonic.</string>
|
<string name="api.subsonic.upgrade_server">Versões incompativeis. Atualize o servidor UltraSonic.</string>
|
||||||
|
<string name="feature_flags_image_loader_description">Permite nova implementação do carregador de imagens.
|
||||||
|
Atualmente, ele não salva a imagem no armazenamento do dispositivo e usa apenas o cache na memória.
|
||||||
|
</string>
|
||||||
|
<string name="feature_flags_category_title">Bandeiras de recursos</string>
|
||||||
|
<string name="feature_flags_image_loader_title">Ativar novo carregador de imagens</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -441,4 +441,10 @@
|
||||||
<string name="api.subsonic.upgrade_client">Incompatible versions. Please upgrade UltraSonic Android app.</string>
|
<string name="api.subsonic.upgrade_client">Incompatible versions. Please upgrade UltraSonic Android app.</string>
|
||||||
<string name="api.subsonic.upgrade_server">Incompatible versions. Please upgrade Subsonic server.</string>
|
<string name="api.subsonic.upgrade_server">Incompatible versions. Please upgrade Subsonic server.</string>
|
||||||
|
|
||||||
|
<string name="feature_flags_image_loader_title">Enable new image loader</string>
|
||||||
|
<string name="feature_flags_image_loader_description">Enables new image loader implementation.
|
||||||
|
Currently it doesn\'t save image in device storage and uses only cache in memory.
|
||||||
|
</string>
|
||||||
|
<string name="feature_flags_category_title">Feature Flags</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -284,5 +284,14 @@
|
||||||
a:summary="@string/settings.screen_lit_summary"
|
a:summary="@string/settings.screen_lit_summary"
|
||||||
a:title="@string/settings.screen_lit_title"/>
|
a:title="@string/settings.screen_lit_title"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory a:title="@string/feature_flags_category_title">
|
||||||
|
<CheckBoxPreference
|
||||||
|
a:key="ff_new_image_loader"
|
||||||
|
a:persistent="false"
|
||||||
|
a:title="@string/feature_flags_image_loader_title"
|
||||||
|
a:summary="@string/feature_flags_image_loader_description"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
Loading…
Reference in New Issue