diff options
author | Wilhelm Fitzpatrick <rafial@cyngn.com> | 2014-09-12 16:10:08 -0700 |
---|---|---|
committer | linus_lee <llee@cyngn.com> | 2014-11-20 12:03:03 -0800 |
commit | 9442e221ed4b8f1abaebe0dae3ee0d979e6d79b3 (patch) | |
tree | a0477f5060ebdc8f5ea2492cad699c20152fc782 | |
parent | 1142f32db0658647186e474e4da32640643647bc (diff) | |
download | android_packages_apps_Eleven-9442e221ed4b8f1abaebe0dae3ee0d979e6d79b3.tar.gz android_packages_apps_Eleven-9442e221ed4b8f1abaebe0dae3ee0d979e6d79b3.tar.bz2 android_packages_apps_Eleven-9442e221ed4b8f1abaebe0dae3ee0d979e6d79b3.zip |
Eleven: AlbumDetailPage implemented according to red lines
Change-Id: I6b5d5051951eda26018f1be67d19aab27af9ae1a
20 files changed, 569 insertions, 111 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index fdd3a9c..cfc3834 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -153,6 +153,13 @@ android:screenOrientation="portrait" android:theme="@style/Eleven.Theme.ActionBar.Overlay"> </activity> + <!-- Album Detail Activity --> + <activity + android:name=".ui.activities.AlbumDetailActivity" + android:excludeFromRecents="true" + android:screenOrientation="portrait" + android:theme="@style/Eleven.Theme.ActionBar.Overlay"> + </activity> <!-- Playlist Detail Activity --> <activity android:name=".ui.activities.PlaylistDetailActivity" diff --git a/res/drawable-hdpi/stopwatch_icon_small_grey.png b/res/drawable-hdpi/stopwatch_icon_small_grey.png Binary files differnew file mode 100644 index 0000000..ab2aa7e --- /dev/null +++ b/res/drawable-hdpi/stopwatch_icon_small_grey.png diff --git a/res/drawable-mdpi/stopwatch_icon_small_grey.png b/res/drawable-mdpi/stopwatch_icon_small_grey.png Binary files differnew file mode 100644 index 0000000..e3cf1f4 --- /dev/null +++ b/res/drawable-mdpi/stopwatch_icon_small_grey.png diff --git a/res/drawable-xhdpi/stopwatch_icon_small_grey.png b/res/drawable-xhdpi/stopwatch_icon_small_grey.png Binary files differnew file mode 100644 index 0000000..3a0d75f --- /dev/null +++ b/res/drawable-xhdpi/stopwatch_icon_small_grey.png diff --git a/res/drawable-xxhdpi/stopwatch_icon_small_grey.png b/res/drawable-xxhdpi/stopwatch_icon_small_grey.png Binary files differnew file mode 100644 index 0000000..9b4db72 --- /dev/null +++ b/res/drawable-xxhdpi/stopwatch_icon_small_grey.png diff --git a/res/layout/activity_album_detail.xml b/res/layout/activity_album_detail.xml new file mode 100644 index 0000000..d93fc1d --- /dev/null +++ b/res/layout/activity_album_detail.xml @@ -0,0 +1,100 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/background_color" > + + <RelativeLayout + android:id="@+id/header" + android:layout_width="match_parent" + android:layout_height="108dp" + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" + android:background="@color/page_header_background" > + + <ImageView + android:id="@+id/overflow" + android:layout_width="@dimen/overflow_width" + android:layout_height="@dimen/overflow_width" + android:layout_alignParentBottom="true" + android:layout_alignParentRight="true" + android:layout_marginBottom="40dp" + android:gravity="center" + android:src="@drawable/menu_item_button" /> + + <ImageView + android:id="@+id/album_art" + android:layout_width="108dp" + android:layout_height="108dp" + android:layout_marginRight="@dimen/standard_padding" + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" /> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_toRightOf="@id/album_art" + android:layout_toLeftOf="@id/overflow" + android:layout_marginTop="21dp" + android:singleLine="true" + android:fontFamily="sans-serif" + android:textStyle="bold" + android:textSize="@dimen/text_size_large" + android:textColor="@color/default_text_color" /> + + <TextView + android:id="@+id/song_count_and_year" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/title" + android:layout_toRightOf="@id/album_art" + android:singleLine="true" + android:fontFamily="sans-serif-light" + android:textSize="@dimen/text_size_micro" + android:textColor="@color/default_text_color" /> + + <TextView + android:id="@+id/genre" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/song_count_and_year" + android:layout_toRightOf="@id/album_art" + android:layout_marginRight="@dimen/standard_padding" + android:singleLine="true" + android:fontFamily="sans-serif-light" + android:textSize="@dimen/text_size_micro" + android:textColor="@color/default_text_color" + android:visibility="gone" /> + + <ImageView + android:id="@+id/duration_icon" + android:layout_width="10dp" + android:layout_height="12dp" + android:layout_below="@id/song_count_and_year" + android:layout_toRightOf="@id/genre" + android:layout_marginTop="2dp" + android:layout_marginRight="4dp" + android:gravity="center" + android:src="@drawable/stopwatch_icon_small_grey" /> + + <TextView + android:id="@+id/duration" + android:layout_width="60dp" + android:layout_height="30dp" + android:layout_below="@id/song_count_and_year" + android:layout_toRightOf="@id/duration_icon" + android:singleLine="true" + android:fontFamily="sans-serif-light" + android:textSize="@dimen/text_size_micro" + android:textColor="@color/default_text_color" /> + </RelativeLayout> + + <ListView + android:id="@+id/songs" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_below="@id/header" + android:layout_alignParentLeft="true" + android:divider="@color/background_color" /> +</RelativeLayout>
\ No newline at end of file diff --git a/res/layout/album_detail_song.xml b/res/layout/album_detail_song.xml new file mode 100644 index 0000000..e3b1587 --- /dev/null +++ b/res/layout/album_detail_song.xml @@ -0,0 +1,48 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="70dp" > + + <!-- FIXME: hide this until we know what goes in the popup menu --> + <ImageView + android:visibility="gone" + android:id="@+id/overflow" + android:layout_width="@dimen/overflow_width" + android:layout_height="68dp" + android:layout_alignParentTop="true" + android:layout_alignParentRight="true" + android:layout_marginBottom="2dp" + android:gravity="center" + android:src="@drawable/menu_item_button" /> + + <TextView + android:id="@+id/title" + style="@style/ListItemMainText.Single" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" + android:layout_toLeftOf="@id/overflow" + android:paddingTop="6dp" + android:layout_marginTop="@dimen/list_preferred_item_padding" + android:layout_marginLeft="@dimen/list_preferred_item_padding" /> + + <TextView + android:id="@+id/duration" + style="@style/ListItemSecondaryText.Single" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/title" + android:layout_alignParentLeft="true" + android:layout_toLeftOf="@id/overflow" + android:layout_marginTop="-2dp" + android:layout_marginLeft="@dimen/standard_padding" /> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_alignParentBottom="true" + android:layout_alignParentLeft="true" + android:layout_marginLeft="@dimen/list_preferred_item_padding" + android:layout_marginRight="@dimen/list_preferred_item_padding" + android:background="@color/list_item_divider_color" /> +</RelativeLayout>
\ No newline at end of file diff --git a/res/layout/artist_detail_album.xml b/res/layout/artist_detail_album.xml index f7469bc..93131a2 100644 --- a/res/layout/artist_detail_album.xml +++ b/res/layout/artist_detail_album.xml @@ -15,7 +15,7 @@ <ImageView android:visibility="gone" android:id="@+id/overflow" - android:layout_width="24dp" + android:layout_width="@dimen/overflow_width" android:layout_height="40dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" @@ -26,30 +26,23 @@ <TextView android:id="@+id/title" + style="@style/ListItemMainText.Single" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/album_art" android:layout_toLeftOf="@id/overflow" android:layout_alignParentLeft="true" android:layout_marginLeft="8dp" - android:layout_marginTop="3dp" - android:singleLine="true" - android:fontFamily="sans-serif" - android:textStyle="bold" - android:textSize="@dimen/text_size_small" - android:textColor="@color/default_text_color" /> + android:layout_marginTop="3dp" /> <TextView android:id="@+id/year" + style="@style/ListItemSecondaryText.Single" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/title" android:layout_alignParentLeft="true" android:layout_toLeftOf="@id/overflow" android:layout_marginLeft="8dp" - android:layout_marginTop="-4dp" - android:singleLine="true" - android:fontFamily="sans-serif-light" - android:textSize="@dimen/text_size_micro" - android:textColor="@color/default_text_color" /> + android:layout_marginTop="-4dp" /> </RelativeLayout>
\ No newline at end of file diff --git a/res/layout/artist_detail_song.xml b/res/layout/artist_detail_song.xml index 8f20e72..4973ae3 100644 --- a/res/layout/artist_detail_song.xml +++ b/res/layout/artist_detail_song.xml @@ -8,13 +8,13 @@ android:layout_height="50dp" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" - android:layout_margin="10dp" /> + android:layout_margin="@dimen/list_preferred_item_padding" /> <!-- FIXME: hide this until we know what goes in the popup menu --> <ImageView android:visibility="gone" android:id="@+id/overflow" - android:layout_width="24dp" + android:layout_width="@dimen/overflow_width" android:layout_height="68dp" android:layout_alignParentTop="true" android:layout_alignParentRight="true" @@ -24,37 +24,29 @@ <TextView android:id="@+id/title" + style="@style/ListItemMainText.Single" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@id/overflow" - android:layout_toRightOf="@id/album_art" - android:layout_marginTop="16dp" - android:singleLine="true" - android:fontFamily="sans-serif" - android:textStyle="bold" - android:textSize="@dimen/text_size_small" - android:textColor="@color/default_text_color" /> + android:layout_toRightOf="@id/album_art" /> <TextView android:id="@+id/album" + style="@style/ListItemSecondaryText.Single" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/title" android:layout_toRightOf="@id/album_art" android:layout_toLeftOf="@id/overflow" - android:layout_marginTop="-2dp" - android:singleLine="true" - android:fontFamily="sans-serif-light" - android:textSize="@dimen/text_size_micro" - android:textColor="@color/default_text_color" /> + android:layout_marginTop="-2dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" - android:layout_marginLeft="10dp" - android:layout_marginRight="10dp" + android:layout_marginLeft="@dimen/list_preferred_item_padding" + android:layout_marginRight="@dimen/list_preferred_item_padding" android:background="@color/list_item_divider_color" /> </RelativeLayout>
\ No newline at end of file diff --git a/res/values/colors.xml b/res/values/colors.xml index 6c18a71..2bef984 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -66,6 +66,9 @@ <color name="header_action_bar_text_color">@color/white</color> <color name="bottom_action_bar_text_color">@color/default_text_color_light</color> + <!-- Background color used on some page headers --> + <color name="page_header_background">#fff4f4f4</color> + <!-- Color for background for shadow on playlist page --> <color name="header_shadow_color">#ea31353f</color> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 3a766d1..5ab4b1e 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -24,6 +24,13 @@ <dimen name="text_size_x_large">24.0sp</dimen> <dimen name="text_size_dayum">36.0sp</dimen> + <!-- Frequently used spacing between elements in many layouts --> + <dimen name="standard_padding">10.0dip</dimen> + + <!-- overflow menu used on page headers and in list items --> + <dimen name="overflow_height">30.0dip</dimen> + <dimen name="overflow_width">24.0dip</dimen> + <!-- List item section header --> <dimen name="list_item_header_height">30.0dip</dimen> @@ -35,8 +42,8 @@ <dimen name="list_item_padding_top">10.0dip</dimen> <dimen name="list_item_padding_bottom">10.0dip</dimen> <dimen name="list_item_header_size">16.0sp</dimen> - <dimen name="list_item_main_text_size">14.0sp</dimen> - <dimen name="list_item_secondary_text_size">12.0sp</dimen> + <dimen name="list_item_main_text_size">@dimens/text_size_small</dimen> + <dimen name="list_item_secondary_text_size">@dimens/text_size_micro</dimen> <dimen name="list_item_queue_text_padding_left">15.0dip</dimen> <!-- List view fast scroll padding left --> diff --git a/res/values/strings.xml b/res/values/strings.xml index ad3a907..260a285 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -202,6 +202,9 @@ <string name="header_n_albums"><xliff:g id="number">%d</xliff:g> Albums</string> <string name="header_5_plus_albums">5+ Albums</string> + <string name="duration_album_mins_only"><xliff:g id="format">%1$dm</xliff:g></string> + <string name="duration_album_hour_mins"><xliff:g id="format">%1$dh %2$dm</xliff:g></string> + <string name="duration_mins"><xliff:g id="format">%3$dm %4$ds</xliff:g></string> <string name="duration_hours"><xliff:g id="format">%2$dh %3$dm %4$ds</xliff:g></string> <string name="duration_days"><xliff:g id="format">%1$dd %2$dd %3$dm %4$ds</xliff:g></string> diff --git a/src/com/cyngn/eleven/Config.java b/src/com/cyngn/eleven/Config.java index 2d18d71..99e90fb 100644 --- a/src/com/cyngn/eleven/Config.java +++ b/src/com/cyngn/eleven/Config.java @@ -54,6 +54,9 @@ public final class Config { */ public static final String ALBUM_YEAR = "album_year"; + /** number of songs in a album or track list */ + public static final String SONG_COUNT = "song_count"; + /** * The MIME type passed to a the profile activity */ diff --git a/src/com/cyngn/eleven/adapters/AlbumDetailSongAdapter.java b/src/com/cyngn/eleven/adapters/AlbumDetailSongAdapter.java new file mode 100644 index 0000000..7f5dcee --- /dev/null +++ b/src/com/cyngn/eleven/adapters/AlbumDetailSongAdapter.java @@ -0,0 +1,58 @@ +package com.cyngn.eleven.adapters; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.support.v4.content.Loader; +import android.view.View; +import android.widget.TextView; + +import com.cyngn.eleven.Config; +import com.cyngn.eleven.R; +import com.cyngn.eleven.cache.ImageFetcher; +import com.cyngn.eleven.loaders.AlbumSongLoader; +import com.cyngn.eleven.model.Song; +import com.cyngn.eleven.ui.activities.AlbumDetailActivity; +import com.cyngn.eleven.utils.MusicUtils; + +import java.util.List; + +public class AlbumDetailSongAdapter extends DetailSongAdapter { + + public AlbumDetailSongAdapter(Activity activity) { + super(activity); + } + + protected int rowLayoutId() { return R.layout.album_detail_song; } + + @Override // LoaderCallbacks + public Loader<List<Song>> onCreateLoader(int id, Bundle args) { + return new AlbumSongLoader(mActivity, args.getLong(Config.ID)); + } + + @Override // LoaderCallbacks + public void onLoadFinished(Loader<List<Song>> loader, List<Song> songs) { + super.onLoadFinished(loader, songs); + ((AlbumDetailActivity)mActivity).update(songs); + } + + protected Holder newHolder(View root, ImageFetcher fetcher) { + return new AlbumHolder(root, fetcher, mActivity); + } + + private static class AlbumHolder extends Holder { + TextView duration; + Context context; + + protected AlbumHolder(View root, ImageFetcher fetcher, Context context) { + super(root, fetcher); + this.context = context; + duration = (TextView)root.findViewById(R.id.duration); + } + + protected void update(Song song) { + title.setText(song.mSongName); + duration.setText(MusicUtils.makeShortTimeString(context, song.mDuration)); + } + } +}
\ No newline at end of file diff --git a/src/com/cyngn/eleven/adapters/ArtistDetailSongAdapter.java b/src/com/cyngn/eleven/adapters/ArtistDetailSongAdapter.java index 64a1ece..c24ba7e 100644 --- a/src/com/cyngn/eleven/adapters/ArtistDetailSongAdapter.java +++ b/src/com/cyngn/eleven/adapters/ArtistDetailSongAdapter.java @@ -2,12 +2,8 @@ package com.cyngn.eleven.adapters; import android.app.Activity; import android.os.Bundle; -import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; @@ -16,92 +12,43 @@ import com.cyngn.eleven.R; import com.cyngn.eleven.cache.ImageFetcher; import com.cyngn.eleven.loaders.ArtistSongLoader; import com.cyngn.eleven.model.Song; -import com.cyngn.eleven.utils.ApolloUtils; -import com.cyngn.eleven.utils.MusicUtils; -import java.util.Collections; import java.util.List; -public class ArtistDetailSongAdapter extends BaseAdapter -implements LoaderCallbacks<List<Song>> { - private final Activity mActivity; - private final ImageFetcher mImageFetcher; - private final LayoutInflater mInflater; - private List<Song> mSongs = Collections.emptyList(); +public class ArtistDetailSongAdapter extends DetailSongAdapter { - public ArtistDetailSongAdapter(final Activity activity) { - mActivity = activity; - mImageFetcher = ApolloUtils.getImageFetcher(activity); - mInflater = LayoutInflater.from(activity); + public ArtistDetailSongAdapter(Activity activity) { + super(activity); } - @Override - public int getCount() { return mSongs.size(); } - - @Override - public Song getItem(int pos) { return mSongs.get(pos); } - - @Override - public long getItemId(int pos) { return pos; } - - @Override - public View getView(int pos, View convertView, ViewGroup parent) { - if(convertView == null) { - convertView = mInflater.inflate(R.layout.artist_detail_song, parent, false); - convertView.setTag(new Holder(convertView)); - } - - Holder h = (Holder)convertView.getTag(); - Song s = getItem(pos); - h.title.setText(s.mSongName); - h.album.setText(s.mAlbumName); - - if (s.mAlbumId >= 0) { - mImageFetcher.loadAlbumImage(s.mArtistName, s.mAlbumName, s.mAlbumId, h.art); - } - - addAction(convertView, s); - - return convertView; - } - - private void addAction(View view, final Song song) { - view.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MusicUtils.playAll(mActivity, new long[] { song.mSongId }, -1, false); - } - }); - } + protected int rowLayoutId() { return R.layout.artist_detail_song; } @Override // LoaderCallbacks public Loader<List<Song>> onCreateLoader(int id, Bundle args) { return new ArtistSongLoader(mActivity, args.getLong(Config.ID)); } - @Override // LoaderCallbacks - public void onLoadFinished(Loader<List<Song>> loader, List<Song> songs) { - if (songs.isEmpty()) { return; } - mSongs = songs; - notifyDataSetChanged(); - } - - @Override // LoaderCallbacks - public void onLoaderReset(Loader<List<Song>> loader) { - mSongs = Collections.emptyList(); - notifyDataSetChanged(); - mImageFetcher.flush(); + protected Holder newHolder(View root, ImageFetcher fetcher) { + return new ArtistHolder(root, fetcher); } - private class Holder { + private static class ArtistHolder extends Holder { ImageView art; - TextView title; TextView album; - Holder(View root) { + protected ArtistHolder(View root, ImageFetcher fetcher) { + super(root, fetcher); art = (ImageView)root.findViewById(R.id.album_art); - title = (TextView)root.findViewById(R.id.title); album = (TextView)root.findViewById(R.id.album); } + + protected void update(Song song) { + title.setText(song.mSongName); + album.setText(song.mAlbumName); + + if (song.mAlbumId >= 0) { + fetcher.loadAlbumImage(song.mArtistName, song.mAlbumName, song.mAlbumId, art); + } + } } }
\ No newline at end of file diff --git a/src/com/cyngn/eleven/adapters/DetailSongAdapter.java b/src/com/cyngn/eleven/adapters/DetailSongAdapter.java new file mode 100644 index 0000000..3bd2321 --- /dev/null +++ b/src/com/cyngn/eleven/adapters/DetailSongAdapter.java @@ -0,0 +1,102 @@ +package com.cyngn.eleven.adapters; + +import android.app.Activity; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.cyngn.eleven.R; +import com.cyngn.eleven.cache.ImageFetcher; +import com.cyngn.eleven.model.Song; +import com.cyngn.eleven.utils.ApolloUtils; +import com.cyngn.eleven.utils.MusicUtils; + +import java.util.Collections; +import java.util.List; + +public abstract class DetailSongAdapter extends BaseAdapter +implements LoaderCallbacks<List<Song>> { + protected final Activity mActivity; + private final ImageFetcher mImageFetcher; + private final LayoutInflater mInflater; + private List<Song> mSongs = Collections.emptyList(); + + public DetailSongAdapter(final Activity activity) { + mActivity = activity; + mImageFetcher = ApolloUtils.getImageFetcher(activity); + mInflater = LayoutInflater.from(activity); + } + + @Override + public int getCount() { return mSongs.size(); } + + @Override + public Song getItem(int pos) { return mSongs.get(pos); } + + @Override + public long getItemId(int pos) { return pos; } + + @Override + public View getView(int pos, View convertView, ViewGroup parent) { + if(convertView == null) { + convertView = mInflater.inflate(rowLayoutId(), parent, false); + convertView.setTag(newHolder(convertView, mImageFetcher)); + } + + Holder holder = (Holder)convertView.getTag(); + + Song song = getItem(pos); + holder.update(song); + addAction(convertView, pos); + + return convertView; + } + + protected abstract int rowLayoutId(); + + private void addAction(View view, final int position) { + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // play clicked song and enqueue all following songs + long[] toPlay = new long[getCount() - position]; + for(int i = 0; i < toPlay.length; i++) { + toPlay[i] = getItem(position + i).mSongId; + } + MusicUtils.playAll(mActivity, toPlay, -1, false); + } + }); + } + + @Override // LoaderCallbacks + public void onLoadFinished(Loader<List<Song>> loader, List<Song> songs) { + if (songs.isEmpty()) { return; } + mSongs = songs; + notifyDataSetChanged(); + } + + @Override // LoaderCallbacks + public void onLoaderReset(Loader<List<Song>> loader) { + mSongs = Collections.emptyList(); + notifyDataSetChanged(); + mImageFetcher.flush(); + } + + protected abstract Holder newHolder(View root, ImageFetcher fetcher); + + protected static abstract class Holder { + protected ImageFetcher fetcher; + protected TextView title; + + protected Holder(View root, ImageFetcher fetcher) { + this.fetcher = fetcher; + title = (TextView)root.findViewById(R.id.title); + } + + protected abstract void update(Song song); + } +}
\ No newline at end of file diff --git a/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java b/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java new file mode 100644 index 0000000..e2ee2b9 --- /dev/null +++ b/src/com/cyngn/eleven/ui/activities/AlbumDetailActivity.java @@ -0,0 +1,139 @@ +package com.cyngn.eleven.ui.activities; + +import android.app.ActionBar; +import android.database.Cursor; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.app.LoaderManager; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.cyngn.eleven.Config; +import com.cyngn.eleven.R; +import com.cyngn.eleven.adapters.AlbumDetailSongAdapter; +import com.cyngn.eleven.adapters.DetailSongAdapter; +import com.cyngn.eleven.cache.ImageFetcher; +import com.cyngn.eleven.model.Song; +import com.cyngn.eleven.utils.GenreFetcher; + +import java.util.List; +import java.util.Locale; + +public class AlbumDetailActivity extends SlidingPanelActivity { + + private ListView mSongs; + private DetailSongAdapter mSongAdapter; + private TextView mAlbumDuration; + private TextView mGenre; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle arguments = getIntent().getExtras(); + String artistName = arguments.getString(Config.ARTIST_NAME); + + setupActionBar(artistName); + + View root = findViewById(R.id.activity_base_content); + + setupHeader(root, artistName, arguments); + setupSongList(root); + + LoaderManager lm = getSupportLoaderManager(); + lm.initLoader(1, arguments, mSongAdapter); + } + + private void setupHeader(View root, String artist, Bundle arguments) { + String album = arguments.getString(Config.NAME); + String year = arguments.getString(Config.ALBUM_YEAR); + long albumId = arguments.getLong(Config.ID); + int songCount = arguments.getInt(Config.SONG_COUNT); + + ImageView albumArt = (ImageView)root.findViewById(R.id.album_art); + albumArt.setContentDescription(album); + ImageFetcher.getInstance(this).loadAlbumImage(artist, album, albumId, albumArt); + + TextView title = (TextView)root.findViewById(R.id.title); + title.setText(album); + + setupCountAndYear(root, year, songCount); + + // will be updated once we have song data + mAlbumDuration = (TextView)root.findViewById(R.id.duration); + mGenre = (TextView)root.findViewById(R.id.genre); + } + + private void setupCountAndYear(View root, String year, int songCount) { + TextView songCountAndYear = (TextView)root.findViewById(R.id.song_count_and_year); + if(songCount > 0) { + String countText = getResources(). + getQuantityString(R.plurals.Nsongs, songCount, songCount); + if(year == null) { + songCountAndYear.setText(countText); + } else { + songCountAndYear.setText(getString(R.string.combine_two_strings, countText, year)); + } + } else if(year != null) { + songCountAndYear.setText(year); + } + } + + private void setupSongList(View root) { + mSongs = (ListView)root.findViewById(R.id.songs); + mSongAdapter = new AlbumDetailSongAdapter(this); + mSongs.setAdapter(mSongAdapter); + } + + @Override + protected int getLayoutToInflate() { return R.layout.activity_album_detail; } + + protected void setupActionBar(String name) { + ActionBar actionBar = getActionBar(); + actionBar.setTitle(name.toUpperCase(Locale.getDefault())); + actionBar.setIcon(R.drawable.ic_action_back); + actionBar.setHomeButtonEnabled(true); + } + + /** cause action bar icon tap to act like back -- boo-urns! */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + /** called back by song loader */ + public void update(List<Song> songs) { + /** compute total run time for album */ + int duration = 0; + for(Song s : songs) { duration += s.mDuration; } + updateDuration(duration); + + /** use the first song on the album to get a genre */ + if(!songs.isEmpty()) { + GenreFetcher.fetch(this, (int)songs.get(0).mSongId, mGenre); + } + } + + public void updateDuration(int duration) { + int mins = Math.round(duration/60); + int hours = mins/60; + mins %= 60; + + String durationText = (hours == 0) + ? getString(R.string.duration_album_mins_only, mins) + : getString(R.string.duration_album_hour_mins, hours, mins); + + mAlbumDuration.setText(durationText); + } +}
\ No newline at end of file diff --git a/src/com/cyngn/eleven/utils/GenreFetcher.java b/src/com/cyngn/eleven/utils/GenreFetcher.java new file mode 100644 index 0000000..befc03d --- /dev/null +++ b/src/com/cyngn/eleven/utils/GenreFetcher.java @@ -0,0 +1,52 @@ +package com.cyngn.eleven.utils; + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.LoaderManager; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.View; +import android.widget.TextView; + +public class GenreFetcher implements LoaderCallbacks<Cursor> { + private static final String[] GENRE_PROJECTION = new String[] { MediaStore.Audio.Genres.NAME }; + + private Context mContext; + private int mSongId; + private TextView mTextView; + + public static void fetch(FragmentActivity activity, int songId, TextView textView) { + LoaderManager lm = activity.getSupportLoaderManager(); + lm.initLoader(0, null, new GenreFetcher(activity, songId, textView)); + } + + private GenreFetcher(Context context, int songId, TextView textView) { + mContext = context; + mSongId = songId; + mTextView = textView; + } + + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + return new CursorLoader(mContext, + MediaStore.Audio.Genres.getContentUriForAudioId("external", mSongId), + GENRE_PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { + if(mTextView != null && cursor.moveToFirst()) { + mTextView.setText(cursor.getString(0)); + mTextView.setVisibility(View.VISIBLE); + } else { + mTextView.setVisibility(View.GONE); + } + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) {} +}
\ No newline at end of file diff --git a/src/com/cyngn/eleven/utils/MusicUtils.java b/src/com/cyngn/eleven/utils/MusicUtils.java index 6b32d4d..c59dc71 100644 --- a/src/com/cyngn/eleven/utils/MusicUtils.java +++ b/src/com/cyngn/eleven/utils/MusicUtils.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.ServiceConnection; import android.database.Cursor; import android.net.Uri; -import android.os.AsyncTask; import android.os.IBinder; import android.os.RemoteException; import android.provider.BaseColumns; @@ -36,7 +35,6 @@ import android.provider.MediaStore.MediaColumns; import android.provider.Settings; import android.util.Log; import android.view.Menu; -import android.view.SubMenu; import com.cyngn.eleven.IElevenService; import com.cyngn.eleven.MusicPlaybackService; @@ -52,8 +50,6 @@ import com.devspark.appmsg.AppMsg; import java.io.File; import java.util.Arrays; -import java.util.Formatter; -import java.util.Locale; import java.util.WeakHashMap; /** @@ -1049,12 +1045,17 @@ public final class MusicUtils { } } + public static final String getSongCountForAlbum(final Context context, final long id) { + Integer i = getSongCountForAlbumInt(context, id); + return i == null ? null : Integer.toString(i); + } + /** * @param context The {@link Context} to use. * @param id The id of the album. * @return The song count for an album. */ - public static final String getSongCountForAlbum(final Context context, final long id) { + public static final Integer getSongCountForAlbumInt(final Context context, final long id) { if (id == -1) { return null; } @@ -1062,11 +1063,13 @@ public final class MusicUtils { Cursor cursor = context.getContentResolver().query(uri, new String[] { AlbumColumns.NUMBER_OF_SONGS }, null, null, null); - String songCount = null; + Integer songCount = null; if (cursor != null) { cursor.moveToFirst(); if (!cursor.isAfterLast()) { - songCount = cursor.getString(0); + if(!cursor.isNull(0)) { + songCount = cursor.getInt(0); + } } cursor.close(); cursor = null; diff --git a/src/com/cyngn/eleven/utils/NavUtils.java b/src/com/cyngn/eleven/utils/NavUtils.java index 883824c..5dbc541 100644 --- a/src/com/cyngn/eleven/utils/NavUtils.java +++ b/src/com/cyngn/eleven/utils/NavUtils.java @@ -21,10 +21,10 @@ import android.provider.MediaStore; import com.cyngn.eleven.Config; import com.cyngn.eleven.R; +import com.cyngn.eleven.ui.activities.AlbumDetailActivity; import com.cyngn.eleven.ui.activities.ArtistDetailActivity; import com.cyngn.eleven.ui.activities.HomeActivity; import com.cyngn.eleven.ui.activities.PlaylistDetailActivity; -import com.cyngn.eleven.ui.activities.ProfileActivity; import com.cyngn.eleven.ui.activities.SearchActivity; import com.cyngn.eleven.ui.activities.SettingsActivity; import com.cyngn.eleven.ui.activities.SmartPlaylistDetailActivity; @@ -71,14 +71,15 @@ public final class NavUtils { // Create a new bundle to transfer the album info final Bundle bundle = new Bundle(); bundle.putString(Config.ALBUM_YEAR, MusicUtils.getReleaseDateForAlbum(context, albumId)); + bundle.putInt(Config.SONG_COUNT, MusicUtils.getSongCountForAlbumInt(context, albumId)); bundle.putString(Config.ARTIST_NAME, artistName); bundle.putString(Config.MIME_TYPE, MediaStore.Audio.Albums.CONTENT_TYPE); bundle.putLong(Config.ID, albumId); bundle.putString(Config.NAME, albumName); // Create the intent to launch the profile activity - final Intent intent = new Intent(context, ProfileActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent intent = new Intent(context, AlbumDetailActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtras(bundle); context.startActivity(intent); } |