mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-22 22:47:49 +01:00
Implemented five star rating
This commit is contained in:
parent
900fa4b67e
commit
ab624be93d
@ -63,7 +63,9 @@ class MusicDirectory {
|
||||
var type: String? = null,
|
||||
var created: Date? = null,
|
||||
var closeness: Int = 0,
|
||||
var bookmarkPosition: Int = 0
|
||||
var bookmarkPosition: Int = 0,
|
||||
var userRating: Int? = null,
|
||||
var averageRating: Float? = null
|
||||
) : Serializable {
|
||||
fun setDuration(duration: Long) {
|
||||
this.duration = duration.toInt()
|
||||
|
@ -0,0 +1,55 @@
|
||||
package org.moire.ultrasonic.api.subsonic
|
||||
|
||||
import org.amshove.kluent.`should be`
|
||||
import org.junit.Test
|
||||
import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse
|
||||
|
||||
/**
|
||||
* Integration test for [SubsonicAPIClient] for setRating request.
|
||||
*/
|
||||
class SubsonicApiSetRatingTest : SubsonicAPIClientTest() {
|
||||
@Test
|
||||
fun `Should parse setRating ok response`() {
|
||||
val id = "110"
|
||||
val rating = 3
|
||||
|
||||
mockWebServerRule.enqueueResponse("ping_ok.json")
|
||||
|
||||
val response = client.api.setRating(id, rating).execute()
|
||||
|
||||
assertResponseSuccessful(response)
|
||||
response.body()?.status `should be` SubsonicResponse.Status.OK
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should parse setRating error response`() {
|
||||
val id = "110223"
|
||||
val rating = 5
|
||||
|
||||
checkErrorCallParsed(mockWebServerRule) {
|
||||
client.api.setRating(id, rating).execute()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should pass id parameter`() {
|
||||
val id = "110"
|
||||
val rating = 5
|
||||
|
||||
mockWebServerRule.assertRequestParam(responseResourceName = "ping_ok.json",
|
||||
expectedParam = "id=$id") {
|
||||
client.api.setRating(id, rating).execute()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should pass rating parameter`() {
|
||||
val id = "110"
|
||||
val rating = 5
|
||||
|
||||
mockWebServerRule.assertRequestParam(responseResourceName = "ping_ok.json",
|
||||
expectedParam = "rating=$rating") {
|
||||
client.api.setRating(id, rating).execute()
|
||||
}
|
||||
}
|
||||
}
|
@ -79,6 +79,12 @@ interface SubsonicAPIDefinition {
|
||||
@Query("artistId") artistId: String? = null
|
||||
): Call<SubsonicResponse>
|
||||
|
||||
@GET("setRating.view")
|
||||
fun setRating(
|
||||
@Query("id") id: String,
|
||||
@Query("rating") rating: Int
|
||||
): Call<SubsonicResponse>
|
||||
|
||||
@GET("getArtist.view")
|
||||
fun getArtist(@Query("id") id: String): Call<GetArtistResponse>
|
||||
|
||||
|
@ -50,11 +50,15 @@ import android.widget.TextView;
|
||||
import android.widget.ViewFlipper;
|
||||
|
||||
import com.mobeta.android.dslv.DragSortListView;
|
||||
|
||||
import org.koin.java.standalone.KoinJavaComponent;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.domain.RepeatMode;
|
||||
import org.moire.ultrasonic.featureflags.Feature;
|
||||
import org.moire.ultrasonic.featureflags.FeatureStorage;
|
||||
import org.moire.ultrasonic.service.DownloadFile;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.MusicService;
|
||||
@ -119,6 +123,15 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
private SilentBackgroundTask<Void> onProgressChangedTask;
|
||||
LinearLayout visualizerViewLayout;
|
||||
private MenuItem starMenuItem;
|
||||
private LinearLayout ratingLinearLayout;
|
||||
private ImageView fiveStar1ImageView;
|
||||
private ImageView fiveStar2ImageView;
|
||||
private ImageView fiveStar3ImageView;
|
||||
private ImageView fiveStar4ImageView;
|
||||
private ImageView fiveStar5ImageView;
|
||||
private boolean useFiveStarRating;
|
||||
private Drawable hollowStar;
|
||||
private Drawable fullStar;
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
@ -136,6 +149,8 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
int width = size.x;
|
||||
int height = size.y;
|
||||
|
||||
useFiveStarRating = KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING);
|
||||
|
||||
swipeDistance = (width + height) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
|
||||
swipeVelocity = swipeDistance;
|
||||
gestureScanner = new GestureDetector(this, this);
|
||||
@ -162,6 +177,54 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
|
||||
visualizerViewLayout = (LinearLayout) findViewById(R.id.download_visualizer_view_layout);
|
||||
|
||||
ratingLinearLayout = findViewById(R.id.song_rating);
|
||||
fiveStar1ImageView = findViewById(R.id.song_five_star_1);
|
||||
fiveStar2ImageView = findViewById(R.id.song_five_star_2);
|
||||
fiveStar3ImageView = findViewById(R.id.song_five_star_3);
|
||||
fiveStar4ImageView = findViewById(R.id.song_five_star_4);
|
||||
fiveStar5ImageView = findViewById(R.id.song_five_star_5);
|
||||
|
||||
if (!useFiveStarRating) ratingLinearLayout.setVisibility(View.GONE);
|
||||
|
||||
hollowStar = Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_hollow);
|
||||
fullStar = Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_full);
|
||||
|
||||
fiveStar1ImageView.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setSongRating(1);
|
||||
}
|
||||
});
|
||||
fiveStar2ImageView.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setSongRating(2);
|
||||
}
|
||||
});
|
||||
fiveStar3ImageView.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setSongRating(3);
|
||||
}
|
||||
});
|
||||
fiveStar4ImageView.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setSongRating(4);
|
||||
}
|
||||
});
|
||||
fiveStar5ImageView.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
setSongRating(5);
|
||||
}
|
||||
});
|
||||
|
||||
View.OnTouchListener touchListener = new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
@ -726,22 +789,20 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
currentSong = downloadFile.getSong();
|
||||
}
|
||||
|
||||
if (useFiveStarRating) starMenuItem.setVisible(false);
|
||||
|
||||
if (currentSong != null)
|
||||
{
|
||||
final Drawable starDrawable = currentSong.getStarred() ? Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_full) : Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_hollow);
|
||||
|
||||
if (starMenuItem != null)
|
||||
{
|
||||
starMenuItem.setIcon(starDrawable);
|
||||
starMenuItem.setIcon(currentSong.getStarred() ? fullStar : hollowStar);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final Drawable starDrawable = Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_hollow);
|
||||
|
||||
if (starMenuItem != null)
|
||||
{
|
||||
starMenuItem.setIcon(starDrawable);
|
||||
starMenuItem.setIcon(hollowStar);
|
||||
}
|
||||
}
|
||||
|
||||
@ -974,12 +1035,12 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
|
||||
if (isStarred)
|
||||
{
|
||||
starMenuItem.setIcon(Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_hollow));
|
||||
starMenuItem.setIcon(hollowStar);
|
||||
currentSong.setStarred(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
starMenuItem.setIcon(Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_full));
|
||||
starMenuItem.setIcon(fullStar);
|
||||
currentSong.setStarred(true);
|
||||
}
|
||||
|
||||
@ -1320,6 +1381,8 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
downloadTrackTextView.setText(trackFormat);
|
||||
downloadTotalDurationTextView.setText(duration);
|
||||
getImageLoader().loadImage(albumArtImageView, currentSong, true, 0, false, true);
|
||||
|
||||
displaySongRating();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1440,6 +1503,9 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: It would be a lot nicer if DownloadService would send an event when this is necessary instead of updating every time
|
||||
displaySongRating();
|
||||
|
||||
onProgressChangedTask = null;
|
||||
}
|
||||
};
|
||||
@ -1580,4 +1646,46 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
||||
{
|
||||
return progressBar;
|
||||
}
|
||||
|
||||
private void displaySongRating()
|
||||
{
|
||||
int rating = currentSong.getUserRating() == null ? 0 : currentSong.getUserRating();
|
||||
fiveStar1ImageView.setImageDrawable(rating > 0 ? fullStar : hollowStar);
|
||||
fiveStar2ImageView.setImageDrawable(rating > 1 ? fullStar : hollowStar);
|
||||
fiveStar3ImageView.setImageDrawable(rating > 2 ? fullStar : hollowStar);
|
||||
fiveStar4ImageView.setImageDrawable(rating > 3 ? fullStar : hollowStar);
|
||||
fiveStar5ImageView.setImageDrawable(rating > 4 ? fullStar : hollowStar);
|
||||
}
|
||||
|
||||
private void setSongRating(final int rating)
|
||||
{
|
||||
if (currentSong == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String id = currentSong.getId();
|
||||
|
||||
currentSong.setUserRating(rating);
|
||||
displaySongRating();
|
||||
getDownloadService().updateNotification();
|
||||
|
||||
new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final MusicService musicService = MusicServiceFactory.getMusicService(DownloadActivity.this);
|
||||
|
||||
try
|
||||
{
|
||||
musicService.setRating(id, rating, DownloadActivity.this, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
@ -172,10 +172,11 @@ public class SettingsFragment extends PreferenceFragment
|
||||
}
|
||||
|
||||
private void setupFeatureFlagsPreferences() {
|
||||
final FeatureStorage featureStorage = KoinJavaComponent.get(FeatureStorage.class);
|
||||
|
||||
CheckBoxPreference ffImageLoader = (CheckBoxPreference) findPreference(
|
||||
Constants.PREFERENCES_KEY_FF_IMAGE_LOADER);
|
||||
|
||||
final FeatureStorage featureStorage = KoinJavaComponent.get(FeatureStorage.class);
|
||||
if (ffImageLoader != null) {
|
||||
ffImageLoader.setChecked(featureStorage.isFeatureEnabled(Feature.NEW_IMAGE_DOWNLOADER));
|
||||
ffImageLoader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@ -187,6 +188,21 @@ public class SettingsFragment extends PreferenceFragment
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CheckBoxPreference useFiveStarRating = (CheckBoxPreference) findPreference(
|
||||
Constants.PREFERENCES_KEY_USE_FIVE_STAR_RATING);
|
||||
|
||||
if (useFiveStarRating != null) {
|
||||
useFiveStarRating.setChecked(featureStorage.isFeatureEnabled(Feature.FIVE_STAR_RATING));
|
||||
useFiveStarRating.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
featureStorage.changeFeatureFlag(Feature.FIVE_STAR_RATING, (Boolean) o);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setupGaplessControlSettingsV14() {
|
||||
|
@ -385,7 +385,6 @@ public class CachedMusicService implements MusicService
|
||||
public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
|
||||
{
|
||||
musicService.star(id, albumId, artistId, context, progressListener);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -394,6 +393,12 @@ public class CachedMusicService implements MusicService
|
||||
musicService.unstar(id, albumId, artistId, context, progressListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception
|
||||
{
|
||||
musicService.setRating(id, rating, context, progressListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception
|
||||
{
|
||||
|
@ -144,4 +144,6 @@ public interface DownloadService
|
||||
void stopJukeboxService();
|
||||
|
||||
void startJukeboxService();
|
||||
|
||||
void updateNotification();
|
||||
}
|
||||
|
@ -39,9 +39,11 @@ import android.os.PowerManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import org.koin.java.standalone.KoinJavaComponent;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.activity.SubsonicTabActivity;
|
||||
@ -52,6 +54,8 @@ import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.domain.RepeatMode;
|
||||
import org.moire.ultrasonic.domain.UserInfo;
|
||||
import org.moire.ultrasonic.featureflags.Feature;
|
||||
import org.moire.ultrasonic.featureflags.FeatureStorage;
|
||||
import org.moire.ultrasonic.provider.UltraSonicAppWidgetProvider4x1;
|
||||
import org.moire.ultrasonic.provider.UltraSonicAppWidgetProvider4x2;
|
||||
import org.moire.ultrasonic.provider.UltraSonicAppWidgetProvider4x3;
|
||||
@ -1238,11 +1242,7 @@ public class DownloadServiceImpl extends Service implements DownloadService
|
||||
// Only update notification is player state is one that will change the icon
|
||||
if (this.playerState == PlayerState.STARTED || this.playerState == PlayerState.PAUSED)
|
||||
{
|
||||
if (Util.isNotificationEnabled(this)) {
|
||||
final NotificationManagerCompat notificationManager =
|
||||
NotificationManagerCompat.from(this);
|
||||
notificationManager.notify(NOTIFICATION_ID, buildForegroundNotification());
|
||||
}
|
||||
updateNotification();
|
||||
tabInstance.showNowPlaying();
|
||||
}
|
||||
}
|
||||
@ -2071,6 +2071,16 @@ public class DownloadServiceImpl extends Service implements DownloadService
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification()
|
||||
{
|
||||
if (Util.isNotificationEnabled(this)) {
|
||||
final NotificationManagerCompat notificationManager =
|
||||
NotificationManagerCompat.from(this);
|
||||
notificationManager.notify(NOTIFICATION_ID, buildForegroundNotification());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("IconColors")
|
||||
private Notification buildForegroundNotification() {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
|
||||
@ -2103,6 +2113,7 @@ public class DownloadServiceImpl extends Service implements DownloadService
|
||||
final String title = song.getTitle();
|
||||
final String text = song.getArtist();
|
||||
final String album = song.getAlbum();
|
||||
final int rating = song.getUserRating() == null ? 0 : song.getUserRating();
|
||||
final int imageSize = Util.getNotificationImageSize(this);
|
||||
|
||||
try {
|
||||
@ -2127,6 +2138,17 @@ public class DownloadServiceImpl extends Service implements DownloadService
|
||||
contentView.setTextViewText(R.id.album, album);
|
||||
bigView.setTextViewText(R.id.album, album);
|
||||
|
||||
boolean useFiveStarRating = KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING);
|
||||
if (!useFiveStarRating) bigView.setViewVisibility(R.id.notification_rating, View.INVISIBLE);
|
||||
else
|
||||
{
|
||||
bigView.setImageViewResource(R.id.notification_five_star_1, rating > 0 ? R.drawable.ic_star_full_dark : R.drawable.ic_star_hollow_dark);
|
||||
bigView.setImageViewResource(R.id.notification_five_star_2, rating > 1 ? R.drawable.ic_star_full_dark : R.drawable.ic_star_hollow_dark);
|
||||
bigView.setImageViewResource(R.id.notification_five_star_3, rating > 2 ? R.drawable.ic_star_full_dark : R.drawable.ic_star_hollow_dark);
|
||||
bigView.setImageViewResource(R.id.notification_five_star_4, rating > 3 ? R.drawable.ic_star_full_dark : R.drawable.ic_star_hollow_dark);
|
||||
bigView.setImageViewResource(R.id.notification_five_star_5, rating > 4 ? R.drawable.ic_star_full_dark : R.drawable.ic_star_hollow_dark);
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
notification.bigContentView = bigView;
|
||||
@ -2135,6 +2157,17 @@ public class DownloadServiceImpl extends Service implements DownloadService
|
||||
return notification;
|
||||
}
|
||||
|
||||
public void setSongRating(final int rating)
|
||||
{
|
||||
if (!new FeatureStorage(this).isFeatureEnabled(Feature.FIVE_STAR_RATING))
|
||||
return;
|
||||
|
||||
final Entry song = currentPlaying.getSong();
|
||||
song.setUserRating(rating);
|
||||
|
||||
updateNotification();
|
||||
}
|
||||
|
||||
private class BufferTask extends CancellableTask
|
||||
{
|
||||
private final DownloadFile downloadFile;
|
||||
|
@ -329,6 +329,21 @@ public class DownloadServiceLifecycleSupport
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
downloadService.pause();
|
||||
break;
|
||||
case KeyEvent.KEYCODE_1:
|
||||
downloadService.setSongRating(1);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_2:
|
||||
downloadService.setSongRating(2);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_3:
|
||||
downloadService.setSongRating(3);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_4:
|
||||
downloadService.setSongRating(4);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_5:
|
||||
downloadService.setSongRating(5);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ public interface MusicService
|
||||
|
||||
void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
|
||||
|
||||
void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception;
|
||||
|
||||
List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
|
||||
|
||||
Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
|
||||
|
@ -238,6 +238,17 @@ public class RESTMusicService implements MusicService {
|
||||
checkResponseSuccessful(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRating(String id,
|
||||
int rating,
|
||||
Context context,
|
||||
ProgressListener progressListener) throws Exception {
|
||||
updateProgressListener(progressListener, R.string.parser_reading);
|
||||
Response<SubsonicResponse> response = subsonicAPIClient.getApi()
|
||||
.setRating(id, rating).execute();
|
||||
checkResponseSuccessful(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MusicDirectory getMusicDirectory(String id,
|
||||
String name,
|
||||
|
@ -131,6 +131,7 @@ public final class Constants
|
||||
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_FF_IMAGE_LOADER = "ff_new_image_loader";
|
||||
public static final String PREFERENCES_KEY_USE_FIVE_STAR_RATING = "use_five_star_rating";
|
||||
|
||||
// Number of free trial days for non-licensed servers.
|
||||
public static final int FREE_TRIAL_DAYS = 30;
|
||||
|
@ -1306,6 +1306,36 @@ public class Util extends DownloadActivity
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_stop, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_1");
|
||||
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_1));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_1, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_2");
|
||||
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_2));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_2, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_3");
|
||||
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_3));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_3, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_4");
|
||||
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_4));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_4, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_5");
|
||||
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_5));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_5, pendingIntent);
|
||||
}
|
||||
|
||||
public static int getNetworkTimeout(Context context)
|
||||
|
@ -23,6 +23,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import org.moire.ultrasonic.activity.SubsonicTabActivity;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
@ -120,6 +121,12 @@ public class EntryAdapter extends ArrayAdapter<Entry>
|
||||
TextView status;
|
||||
TextView artist;
|
||||
TextView duration;
|
||||
LinearLayout rating;
|
||||
ImageView fiveStar1;
|
||||
ImageView fiveStar2;
|
||||
ImageView fiveStar3;
|
||||
ImageView fiveStar4;
|
||||
ImageView fiveStar5;
|
||||
ImageView star;
|
||||
ImageView drag;
|
||||
}
|
||||
|
@ -28,10 +28,14 @@ import android.view.View;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.koin.java.standalone.KoinJavaComponent;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
import org.moire.ultrasonic.featureflags.Feature;
|
||||
import org.moire.ultrasonic.featureflags.FeatureStorage;
|
||||
import org.moire.ultrasonic.service.DownloadFile;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
@ -73,12 +77,15 @@ public class SongView extends UpdateView implements Checkable
|
||||
private boolean playing;
|
||||
private EntryAdapter.SongViewHolder viewHolder;
|
||||
private boolean maximized = false;
|
||||
private boolean useFiveStarRating;
|
||||
|
||||
public SongView(Context context)
|
||||
{
|
||||
super(context);
|
||||
this.context = context;
|
||||
|
||||
useFiveStarRating = KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING);
|
||||
|
||||
String theme = Util.getTheme(context);
|
||||
boolean themesMatch = theme.equals(SongView.theme);
|
||||
inflater = LayoutInflater.from(this.context);
|
||||
@ -124,6 +131,12 @@ public class SongView extends UpdateView implements Checkable
|
||||
inflater.inflate(song.isVideo() ? R.layout.video_list_item : R.layout.song_list_item, this, true);
|
||||
viewHolder = new EntryAdapter.SongViewHolder();
|
||||
viewHolder.check = (CheckedTextView) findViewById(R.id.song_check);
|
||||
viewHolder.rating = (LinearLayout) findViewById(R.id.song_rating);
|
||||
viewHolder.fiveStar1 = (ImageView) findViewById(R.id.song_five_star_1);
|
||||
viewHolder.fiveStar2 = (ImageView) findViewById(R.id.song_five_star_2);
|
||||
viewHolder.fiveStar3 = (ImageView) findViewById(R.id.song_five_star_3);
|
||||
viewHolder.fiveStar4 = (ImageView) findViewById(R.id.song_five_star_4);
|
||||
viewHolder.fiveStar5 = (ImageView) findViewById(R.id.song_five_star_5);
|
||||
viewHolder.star = (ImageView) findViewById(R.id.song_star);
|
||||
viewHolder.drag = (ImageView) findViewById(R.id.song_drag);
|
||||
viewHolder.track = (TextView) findViewById(R.id.song_track);
|
||||
@ -237,56 +250,59 @@ public class SongView extends UpdateView implements Checkable
|
||||
if (Util.isOffline(this.context))
|
||||
{
|
||||
viewHolder.star.setVisibility(View.GONE);
|
||||
viewHolder.rating.setVisibility(View.GONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewHolder.star.setImageDrawable(song.getStarred() ? starDrawable : starHollowDrawable);
|
||||
|
||||
viewHolder.star.setOnClickListener(new View.OnClickListener()
|
||||
if (useFiveStarRating)
|
||||
{
|
||||
@Override
|
||||
public void onClick(View view)
|
||||
{
|
||||
final boolean isStarred = song.getStarred();
|
||||
final String id = song.getId();
|
||||
viewHolder.star.setVisibility(View.GONE);
|
||||
|
||||
if (!isStarred)
|
||||
{
|
||||
viewHolder.star.setImageDrawable(starDrawable);
|
||||
song.setStarred(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewHolder.star.setImageDrawable(starHollowDrawable);
|
||||
song.setStarred(false);
|
||||
}
|
||||
int rating = song.getUserRating() == null ? 0 : song.getUserRating();
|
||||
viewHolder.fiveStar1.setImageDrawable(rating > 0 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar2.setImageDrawable(rating > 1 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar3.setImageDrawable(rating > 2 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar4.setImageDrawable(rating > 3 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar5.setImageDrawable(rating > 4 ? starDrawable : starHollowDrawable);
|
||||
|
||||
new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SongView.this.context);
|
||||
}
|
||||
else {
|
||||
viewHolder.rating.setVisibility(View.GONE);
|
||||
viewHolder.star.setImageDrawable(song.getStarred() ? starDrawable : starHollowDrawable);
|
||||
|
||||
try
|
||||
{
|
||||
if (!isStarred)
|
||||
{
|
||||
musicService.star(id, null, null, SongView.this.context, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
musicService.unstar(id, null, null, SongView.this.context, null);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
viewHolder.star.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final boolean isStarred = song.getStarred();
|
||||
final String id = song.getId();
|
||||
|
||||
if (!isStarred) {
|
||||
viewHolder.star.setImageDrawable(starDrawable);
|
||||
song.setStarred(true);
|
||||
} else {
|
||||
viewHolder.star.setImageDrawable(starHollowDrawable);
|
||||
song.setStarred(false);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SongView.this.context);
|
||||
|
||||
try {
|
||||
if (!isStarred) {
|
||||
musicService.star(id, null, null, SongView.this.context, null);
|
||||
} else {
|
||||
musicService.unstar(id, null, null, SongView.this.context, null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
@ -394,6 +410,13 @@ public class SongView extends UpdateView implements Checkable
|
||||
}
|
||||
}
|
||||
|
||||
int rating = song.getUserRating() == null ? 0 : song.getUserRating();
|
||||
viewHolder.fiveStar1.setImageDrawable(rating > 0 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar2.setImageDrawable(rating > 1 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar3.setImageDrawable(rating > 2 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar4.setImageDrawable(rating > 3 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar5.setImageDrawable(rating > 4 ? starDrawable : starHollowDrawable);
|
||||
|
||||
boolean playing = downloadService.getCurrentPlaying() == downloadFile;
|
||||
|
||||
if (playing)
|
||||
|
@ -45,6 +45,8 @@ fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry = MusicDirectory.
|
||||
if (this@toDomainEntity.publishDate != null) {
|
||||
artist = dateFormat.format(this@toDomainEntity.publishDate!!.time)
|
||||
}
|
||||
userRating = this@toDomainEntity.userRating
|
||||
averageRating = this@toDomainEntity.averageRating
|
||||
}
|
||||
|
||||
fun List<MusicDirectoryChild>.toDomainEntityList() = this.map { it.toDomainEntity() }
|
||||
|
@ -10,5 +10,9 @@ enum class Feature(
|
||||
/**
|
||||
* Enables new image downloader implementation.
|
||||
*/
|
||||
NEW_IMAGE_DOWNLOADER(false)
|
||||
NEW_IMAGE_DOWNLOADER(false),
|
||||
/**
|
||||
* Enables five star rating system.
|
||||
*/
|
||||
FIVE_STAR_RATING(false)
|
||||
}
|
||||
|
@ -26,15 +26,93 @@
|
||||
a:contentDescription="@string/albumArt"/>
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/download_visualizer_view_layout"
|
||||
a:id="@+id/album_art_inside"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="60dip"
|
||||
a:layout_gravity="bottom|center_horizontal"
|
||||
a:layout_marginLeft="60dip"
|
||||
a:layout_marginRight="60dip"
|
||||
a:background="@color/translucent"
|
||||
a:orientation="vertical"/>
|
||||
a:layout_height="fill_parent"
|
||||
a:gravity="bottom"
|
||||
a:orientation="vertical" >
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/song_rating"
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="60dip"
|
||||
a:layout_gravity="center"
|
||||
a:layout_margin="40dip"
|
||||
a:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_1"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="10dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_2"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="10dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_3"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="10dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_4"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="10dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_5"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="10dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/download_visualizer_view_layout"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="60dip"
|
||||
a:layout_gravity="bottom|center_horizontal"
|
||||
a:layout_marginLeft="60dip"
|
||||
a:layout_marginRight="60dip"
|
||||
a:background="@color/translucent"
|
||||
a:orientation="vertical"/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<include layout="@layout/download_playlist"/>
|
||||
|
@ -28,16 +28,94 @@
|
||||
a:contentDescription="@string/albumArt"/>
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/download_visualizer_view_layout"
|
||||
a:id="@+id/album_art_inside"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="60dip"
|
||||
a:layout_alignParentBottom="true"
|
||||
a:layout_gravity="center_horizontal"
|
||||
a:background="@color/translucent"
|
||||
a:layout_marginLeft="80dip"
|
||||
a:layout_marginRight="80dip"
|
||||
a:orientation="vertical"
|
||||
/>
|
||||
a:layout_height="fill_parent"
|
||||
a:gravity="bottom"
|
||||
a:orientation="vertical" >
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/song_rating"
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="60dip"
|
||||
a:layout_gravity="center"
|
||||
a:layout_margin="40dip"
|
||||
a:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_1"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="5dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_2"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="5dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_3"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="5dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_4"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="5dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_5"
|
||||
a:layout_width="0dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:padding="5dip"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="fitCenter"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/download_visualizer_view_layout"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="60dip"
|
||||
a:layout_gravity="center"
|
||||
a:background="@color/translucent"
|
||||
a:layout_marginLeft="80dip"
|
||||
a:layout_marginRight="80dip"
|
||||
a:orientation="vertical"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<include layout="@layout/download_playlist" />
|
||||
|
@ -4,14 +4,14 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/statusbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:layout_height="150dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="@color/background_color_dark" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_image"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:gravity="center"
|
||||
tools:background="#ff00ff"
|
||||
/>
|
||||
@ -41,7 +41,7 @@
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="marquee"
|
||||
android:focusable="true"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
tools:text="Track name"
|
||||
/>
|
||||
|
||||
@ -80,15 +80,75 @@
|
||||
android:maxLines="1"
|
||||
tools:text="Album"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_rating"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dip"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_five_star_1"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
android:focusable="false"
|
||||
android:gravity="center_vertical"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_five_star_2"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
android:focusable="false"
|
||||
android:gravity="center_vertical"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_five_star_3"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
android:focusable="false"
|
||||
android:gravity="center_vertical"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_five_star_4"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
android:focusable="false"
|
||||
android:gravity="center_vertical"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_five_star_5"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
android:focusable="false"
|
||||
android:gravity="center_vertical"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginTop="5dip"
|
||||
android:layout_marginBottom="10dip"
|
||||
android:background="#DD696969"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -10,60 +10,59 @@
|
||||
android:layout_height="4dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:background="@drawable/drop_shadow" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/now_playing_view"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/now_playing_image"
|
||||
android:layout_width="64.0dip"
|
||||
android:layout_height="64.0dip"
|
||||
android:focusable="true"
|
||||
android:gravity="center" />
|
||||
<ImageView
|
||||
android:id="@+id/now_playing_image"
|
||||
android:layout_width="64.0dip"
|
||||
android:layout_height="64.0dip"
|
||||
android:focusable="true"
|
||||
android:gravity="center" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0.0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1.0"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="11.0dip" >
|
||||
<LinearLayout
|
||||
android:layout_width="0.0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1.0"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="11.0dip">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/now_playing_trackname"
|
||||
<TextView
|
||||
android:id="@+id/now_playing_trackname"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/now_playing_artist"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:ellipsize="end"
|
||||
android:scrollHorizontally="true"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/now_playing_control_play"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold" />
|
||||
android:layout_gravity="center|right"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_weight="0.0"
|
||||
android:focusable="false"
|
||||
android:src="?attr/media_pause" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/now_playing_artist"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:ellipsize="end"
|
||||
android:scrollHorizontally="true"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/now_playing_control_play"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|right"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_weight="0.0"
|
||||
android:focusable="false"
|
||||
android:src="?attr/media_pause" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -15,6 +15,66 @@
|
||||
|
||||
<include layout="@layout/song_details" />
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/song_rating"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_gravity="center_vertical"
|
||||
a:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_1"
|
||||
a:layout_width="10dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="centerInside"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_2"
|
||||
a:layout_width="10dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="centerInside"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_3"
|
||||
a:layout_width="10dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="centerInside"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_4"
|
||||
a:layout_width="10dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="centerInside"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_five_star_5"
|
||||
a:layout_width="10dip"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@android:color/transparent"
|
||||
a:focusable="false"
|
||||
a:gravity="center_vertical"
|
||||
a:scaleType="centerInside"
|
||||
a:layout_marginRight="3dip"
|
||||
a:src="?attr/star_hollow" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
a:id="@+id/song_star"
|
||||
a:layout_width="wrap_content"
|
||||
|
@ -441,5 +441,9 @@
|
||||
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>
|
||||
<string name="feature_flags_five_star_rating_title">Use cinco estrellas para las canciones.</string>
|
||||
<string name="feature_flags_five_star_rating_description">Utilice el sistema de calificación de cinco estrellas para canciones
|
||||
en lugar de simplemente destacar / desestimar elementos.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
@ -442,6 +442,10 @@
|
||||
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_five_star_rating_title">Utiliser une note de cinq étoiles pour les chansons</string>
|
||||
<string name="feature_flags_five_star_rating_description">Utiliser un système de notation à cinq étoiles pour les chansons
|
||||
au lieu de simplement mettre en vedette / désactiver les éléments.
|
||||
</string>
|
||||
<string name="feature_flags_category_title">Drapeaux des fonctionnalités</string>
|
||||
|
||||
</resources>
|
||||
|
@ -441,5 +441,9 @@
|
||||
</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>
|
||||
<string name="feature_flags_five_star_rating_title">Öt csillagos értékelés használata a dalokhoz</string>
|
||||
<string name="feature_flags_five_star_rating_description">Öt csillag használata az értékeléshez az egyszerű
|
||||
csillaggal jelölés helyett.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
@ -442,5 +442,9 @@
|
||||
Momenteel slaat het geen afbeeldingen op op de apparaatopslag en wordt alleen geheugencache gebruikt.
|
||||
</string>
|
||||
<string name="feature_flags_category_title">Experimentele functies</string>
|
||||
<string name="feature_flags_five_star_rating_title">Gebruik vijf sterren voor nummers</string>
|
||||
<string name="feature_flags_five_star_rating_description">Gebruik vijf sterren ratingsysteem voor liedjes
|
||||
in plaats van items simpelweg in de hoofdrol te zetten / niet te verwijderen.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
@ -455,5 +455,9 @@ ponieważ api Subsonic nie wspiera nowego sposobu autoryzacji dla użytkowników
|
||||
<string name="feature_flags_image_loader_description">Włącza implementację modułu ładującego nowe obrazy.
|
||||
Obecnie nie zapisuje obrazów w pamięci urządzenia, tylko wykorzystuje tylko pamięć podręczną.</string>
|
||||
<string name="feature_flags_category_title">Flagi funkcji</string>
|
||||
<string name="feature_flags_five_star_rating_title">Użyj pięciu gwiazdek dla utworów</string>
|
||||
<string name="feature_flags_five_star_rating_description">W przypadku utworów użyj systemu pięciu gwiazdek
|
||||
zamiast po prostu grać gwiazdkami / bez gwiazd.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
@ -441,5 +441,9 @@
|
||||
</string>
|
||||
<string name="feature_flags_category_title">Bandeiras de recursos</string>
|
||||
<string name="feature_flags_image_loader_title">Ativar novo carregador de imagens</string>
|
||||
<string name="feature_flags_five_star_rating_title">Use classificação de cinco estrelas para músicas</string>
|
||||
<string name="feature_flags_five_star_rating_description">Use o sistema de classificação de cinco estrelas para músicas
|
||||
em vez de simplesmente estrelar / não estrelar itens.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
@ -441,5 +441,9 @@
|
||||
</string>
|
||||
<string name="feature_flags_category_title">Bandeiras de recursos</string>
|
||||
<string name="feature_flags_image_loader_title">Ativar novo carregador de imagens</string>
|
||||
<string name="feature_flags_five_star_rating_title">Use classificação de cinco estrelas para músicas</string>
|
||||
<string name="feature_flags_five_star_rating_description">Use o sistema de classificação de cinco estrelas para músicas
|
||||
em vez de simplesmente estrelar / não estrelar itens.
|
||||
</string>
|
||||
|
||||
</resources>
|
||||
|
@ -445,6 +445,10 @@
|
||||
<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_five_star_rating_title">Use five star rating for songs</string>
|
||||
<string name="feature_flags_five_star_rating_description">Use five star rating system for songs
|
||||
instead of simply starring/unstarring items.
|
||||
</string>
|
||||
<string name="feature_flags_category_title">Feature Flags</string>
|
||||
|
||||
</resources>
|
||||
|
@ -291,6 +291,12 @@
|
||||
a:title="@string/feature_flags_image_loader_title"
|
||||
a:summary="@string/feature_flags_image_loader_description"
|
||||
/>
|
||||
<CheckBoxPreference
|
||||
a:key="use_five_star_rating"
|
||||
a:persistent="false"
|
||||
a:title="@string/feature_flags_five_star_rating_title"
|
||||
a:summary="@string/feature_flags_five_star_rating_description"
|
||||
/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
@ -39,7 +39,7 @@ class APIMusicDirectoryConverterTest {
|
||||
transcodedSuffix = "some-transcoded-suffix", duration = 11, bitRate = 256,
|
||||
path = "some-path", isDir = true, isVideo = true, playCount = 323, discNumber = 2,
|
||||
created = Calendar.getInstance(), type = "some-type",
|
||||
starred = Calendar.getInstance())
|
||||
starred = Calendar.getInstance(), userRating = 3, averageRating = 2.99F)
|
||||
|
||||
val convertedEntity = entity.toDomainEntity()
|
||||
|
||||
@ -69,6 +69,8 @@ class APIMusicDirectoryConverterTest {
|
||||
starred `should be equal to` (entity.starred != null)
|
||||
discNumber `should equal` entity.discNumber
|
||||
type `should equal` entity.type
|
||||
userRating `should equal` entity.userRating
|
||||
averageRating `should equal` entity.averageRating
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user