Add rating in music track

More ui improvments
This commit is contained in:
David Schulte 2015-02-06 21:59:23 +01:00
parent 471528a496
commit d8a79e6900
60 changed files with 1514 additions and 269 deletions

View file

@ -243,17 +243,6 @@ public class SuperUserCommand {
mThread.start();
}
/**
* Execute the command asynchronously.
* Please notice that the commands will only executed one after another.
* The command will wait until the su process is free.
* @param callback The callback instance
* @param activity Set the activity to execute the callback on the UI thread
*/
public void executeAsync(SuperUserCommandCallback callback, Activity activity) {
}
/**
* Execute the command and return whether the command was executed.
* It will only return false if the app wasn't granted superuser permissions, like {@link #superuserWasSuccessful()}.

View file

@ -32,7 +32,7 @@
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".TrackListActivity"
android:name=".activitys.MusicTrackListActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -41,12 +41,12 @@
</intent-filter>
</activity>
<activity
android:name=".TrackDetailActivity"
android:name=".activitys.MusicTrackDetailActivity"
android:label="@string/title_track_detail"
android:parentActivityName=".TrackListActivity" >
android:parentActivityName=".activitys.MusicTrackListActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".TrackListActivity" />
android:value=".activitys.MusicTrackListActivity" />
</activity>
<meta-data android:name="crashhandler.email" android:value="mail@david-schulte.de" />

View file

@ -1,156 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.crashhandler.CrashHandler;
import de.arcus.playmusiclib.PlayMusicManager;
import de.arcus.playmusiclib.datasources.AlbumDataSource;
import de.arcus.playmusiclib.datasources.PlaylistDataSource;
import de.arcus.playmusiclib.enums.ID3v2Version;
import de.arcus.playmusiclib.items.MusicTrackList;
/**
* An activity representing a list of Tracks. This activity
* has different presentations for handset and tablet-size devices. On
* handsets, the activity presents a list of items, which when touched,
* lead to a {@link TrackDetailActivity} representing
* item details. On tablets, the activity presents the list of items and
* item details side-by-side using two vertical panes.
* <p/>
* The activity makes heavy use of fragments. The list of items is a
* {@link TrackListFragment} and the item details
* (if present) is a {@link TrackDetailFragment}.
* <p/>
* This activity also implements the required
* {@link TrackListFragment.Callbacks} interface
* to listen for item selections.
*/
public class TrackListActivity extends ActionBarActivity
implements TrackListFragment.Callbacks {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track_list);
// Adds the crash handler to this class
CrashHandler.addCrashHandler(this);
Logger.getInstance().logVerbose("Activity", "onCreate(" + this.getLocalClassName() + ")");
// Setup ActionBar
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.app_name);
}
if (findViewById(R.id.track_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((TrackListFragment) getSupportFragmentManager()
.findFragmentById(R.id.track_list))
.setActivateOnItemClick(true);
}
// Gets the running instance
PlayMusicManager playMusicManager = PlayMusicManager.getInstance();
// Create a new instance
if (playMusicManager == null) {
playMusicManager = new PlayMusicManager(this);
try {
// Simple play ground
playMusicManager.startUp();
playMusicManager.setOfflineOnly(true);
// Setup ID3
playMusicManager.setID3Enable(true);
playMusicManager.setID3EnableArtwork(true);
playMusicManager.setID3EnableFallback(true);
playMusicManager.setID3v2Version(ID3v2Version.ID3v23);
} catch (Exception e) {
Logger.getInstance().logError("Test", e.toString());
}
}
// Load all albums to the list
AlbumDataSource albumDataSource = new AlbumDataSource(playMusicManager);
//PlaylistDataSource playlistDataSource = new PlaylistDataSource(playMusicManager);
albumDataSource.setOfflineOnly(true);
((TrackListFragment) getSupportFragmentManager()
.findFragmentById(R.id.track_list)).setMusicTrackList(albumDataSource.getAll());
}
/**
* Callback method from {@link TrackListFragment.Callbacks}
* indicating that the item with the given ID was selected.
*/
@Override
public void onItemSelected(MusicTrackList musicTrackList) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putLong(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, musicTrackList.getMusicTrackListID());
arguments.putString(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE, musicTrackList.getMusicTrackListType());
TrackDetailFragment fragment = new TrackDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.track_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, TrackDetailActivity.class);
detailIntent.putExtra(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, musicTrackList.getMusicTrackListID());
detailIntent.putExtra(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE, musicTrackList.getMusicTrackListType());
startActivity(detailIntent);
}
}
}

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2;
package de.arcus.playmusicexporter2.activitys;
import android.content.Intent;
import android.os.Bundle;
@ -28,17 +28,20 @@ import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.fragments.MusicTrackDetailFragment;
/**
* An activity representing a single Track detail screen. This
* activity is only used on handset devices. On tablet-size devices,
* item details are presented side-by-side with a list of items
* in a {@link TrackListActivity}.
* in a {@link MusicTrackListActivity}.
* <p/>
* This activity is mostly just a 'shell' activity containing nothing
* more than a {@link TrackDetailFragment}.
* more than a {@link de.arcus.playmusicexporter2.fragments.MusicTrackDetailFragment}.
*/
public class TrackDetailActivity extends ActionBarActivity {
public class MusicTrackDetailActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -62,13 +65,13 @@ public class TrackDetailActivity extends ActionBarActivity {
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putLong(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID,
getIntent().getLongExtra(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, 0));
arguments.putLong(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID,
getIntent().getLongExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, 0));
arguments.putString(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE,
getIntent().getStringExtra(TrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE));
arguments.putString(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE,
getIntent().getStringExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE));
TrackDetailFragment fragment = new TrackDetailFragment();
MusicTrackDetailFragment fragment = new MusicTrackDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.track_detail_container, fragment)
@ -87,7 +90,7 @@ public class TrackDetailActivity extends ActionBarActivity {
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, TrackListActivity.class));
NavUtils.navigateUpTo(this, new Intent(this, MusicTrackListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);

View file

@ -0,0 +1,216 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2.activitys;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.crashhandler.CrashHandler;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.fragments.MusicTrackDetailFragment;
import de.arcus.playmusicexporter2.fragments.MusicTrackListFragment;
import de.arcus.playmusicexporter2.fragments.NavigationDrawerFragment;
import de.arcus.playmusiclib.PlayMusicManager;
import de.arcus.playmusiclib.datasources.AlbumDataSource;
import de.arcus.playmusiclib.datasources.ArtistDataSource;
import de.arcus.playmusiclib.datasources.PlaylistDataSource;
import de.arcus.playmusiclib.enums.ID3v2Version;
import de.arcus.playmusiclib.items.MusicTrackList;
/**
* An activity representing a list of Tracks. This activity
* has different presentations for handset and tablet-size devices. On
* handsets, the activity presents a list of items, which when touched,
* lead to a {@link MusicTrackDetailActivity} representing
* item details. On tablets, the activity presents the list of items and
* item details side-by-side using two vertical panes.
* <p/>
* The activity makes heavy use of fragments. The list of items is a
* {@link de.arcus.playmusicexporter2.fragments.MusicTrackListFragment} and the item details
* (if present) is a {@link de.arcus.playmusicexporter2.fragments.MusicTrackDetailFragment}.
* <p/>
* This activity also implements the required
* {@link de.arcus.playmusicexporter2.fragments.MusicTrackListFragment.Callbacks} interface
* to listen for item selections.
*/
public class MusicTrackListActivity extends ActionBarActivity
implements MusicTrackListFragment.Callbacks
, NavigationDrawerFragment.NavigationDrawerCallbacks {
@Override
public void onViewTypeChanged(NavigationDrawerFragment.ViewType viewType) {
loadList(viewType);
}
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
private PlayMusicManager mPlayMusicManager;
private NavigationDrawerFragment mNavigationDrawerFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track_list);
// Adds the crash handler to this class
CrashHandler.addCrashHandler(this);
Logger.getInstance().logVerbose("Activity", "onCreate(" + this.getLocalClassName() + ")");
// Setup ActionBar
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.app_name);
}
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setOnListViewChanged(this);
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
if (findViewById(R.id.track_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((MusicTrackListFragment) getSupportFragmentManager()
.findFragmentById(R.id.track_list))
.setActivateOnItemClick(true);
}
// Gets the running instance
mPlayMusicManager = PlayMusicManager.getInstance();
// Create a new instance
if (mPlayMusicManager == null) {
mPlayMusicManager = new PlayMusicManager(this);
try {
// Simple play ground
mPlayMusicManager.startUp();
mPlayMusicManager.setOfflineOnly(true);
// Setup ID3
mPlayMusicManager.setID3Enable(true);
mPlayMusicManager.setID3EnableArtwork(true);
mPlayMusicManager.setID3EnableFallback(true);
mPlayMusicManager.setID3v2Version(ID3v2Version.ID3v23);
} catch (Exception e) {
Logger.getInstance().logError("Test", e.toString());
}
}
loadList(NavigationDrawerFragment.ViewType.Album);
}
/**
* Loads the music list with the current view type
*/
private void loadList(NavigationDrawerFragment.ViewType viewType) {
// Manager is not loaded
if (mPlayMusicManager == null) return;
// Gets the music list fragment
MusicTrackListFragment musicTrackListFragment = (MusicTrackListFragment) getSupportFragmentManager()
.findFragmentById(R.id.track_list);
switch(viewType) {
case Album:
// Load all albums to the list
AlbumDataSource dataSourceAlbum = new AlbumDataSource(mPlayMusicManager);
dataSourceAlbum.setOfflineOnly(true);
musicTrackListFragment.setMusicTrackList(dataSourceAlbum.getAll());
break;
case Artist:
// Load all artists to the list
ArtistDataSource dataSourceArtist = new ArtistDataSource(mPlayMusicManager);
dataSourceArtist.setOfflineOnly(true);
musicTrackListFragment.setMusicTrackList(dataSourceArtist.getAll());
break;
case Playlist:
// Load all playlists to the list
PlaylistDataSource dataSourcePlaylist = new PlaylistDataSource(mPlayMusicManager);
dataSourcePlaylist.setOfflineOnly(true);
musicTrackListFragment.setMusicTrackList(dataSourcePlaylist.getAll());
break;
case Rated:
// Load all reated albums to the list
AlbumDataSource dataSourceRatedAlbum = new AlbumDataSource(mPlayMusicManager);
dataSourceRatedAlbum.setOfflineOnly(true);
dataSourceRatedAlbum.setRatedOnly(true);
musicTrackListFragment.setMusicTrackList(dataSourceRatedAlbum.getAll());
break;
}
}
/**
* Callback method from {@link de.arcus.playmusicexporter2.fragments.MusicTrackListFragment.Callbacks}
* indicating that the item with the given ID was selected.
*/
@Override
public void onItemSelected(MusicTrackList musicTrackList) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putLong(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, musicTrackList.getMusicTrackListID());
arguments.putString(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE, musicTrackList.getMusicTrackListType());
MusicTrackDetailFragment fragment = new MusicTrackDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.track_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, MusicTrackDetailActivity.class);
detailIntent.putExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, musicTrackList.getMusicTrackListID());
detailIntent.putExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE, musicTrackList.getMusicTrackListType());
startActivity(detailIntent);
}
}
}

View file

@ -23,17 +23,19 @@
package de.arcus.playmusicexporter2.adapter;
import android.content.Context;
import android.database.DataSetObserver;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.utils.ImageViewLoader;
import de.arcus.playmusiclib.items.MusicTrack;
/**
@ -45,6 +47,19 @@ public class MusicTrackAdapter extends ArrayAdapter<MusicTrack> {
*/
private Context mContext;
/**
* If this is set the music track shows it artwork instead of the track number
*/
private boolean mShowArtworks = true;
public boolean getShowArtwok() {
return mShowArtworks;
}
public void setShowArtworks(boolean showArtworks) {
mShowArtworks = showArtworks;
}
/**
* Create a new track adapter
* @param context The app context
@ -77,9 +92,10 @@ public class MusicTrackAdapter extends ArrayAdapter<MusicTrack> {
view = inflater.inflate(R.layout.adapter_music_track, parent, false);
}
TextView textView;
// Set the track number
// Sets the track number
textView = (TextView)view.findViewById(R.id.text_music_track_number);
long trackPosition = musicTrack.getTrackNumber();
@ -92,12 +108,39 @@ public class MusicTrackAdapter extends ArrayAdapter<MusicTrack> {
textView.setText("");
textView.setTextColor(mContext.getResources().getColor(musicTrack.isOfflineAvailable() ? R.color.text_music_number : R.color.text_music_disable_number));
// Set the title
// Sets the disc number
textView = (TextView)view.findViewById(R.id.text_music_track_disc_number);
textView.setText("CD " + musicTrack.getDiscNumber());
// Don't show the disc number if this is a playlist or artist list
if (musicTrack.getDiscNumber() > 0 && TextUtils.isEmpty(musicTrack.getContainerName()))
textView.setVisibility(View.VISIBLE);
else
textView.setVisibility(View.GONE);
textView.setTextColor(mContext.getResources().getColor(musicTrack.isOfflineAvailable() ? R.color.text_music_disc_number : R.color.text_music_disable_disc_number));
if (mShowArtworks) {
view.findViewById(R.id.relative_layout_number).setVisibility(View.GONE);
view.findViewById(R.id.relative_layout_artwork).setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.relative_layout_number).setVisibility(View.VISIBLE);
view.findViewById(R.id.relative_layout_artwork).setVisibility(View.GONE);
}
if (mShowArtworks) {
ImageView imageView = (ImageView) view.findViewById(R.id.image_music_track_artwork);
imageView.setImageResource(R.drawable.cd_case);
String artworkPath = musicTrack.getArtworkPath();
if (artworkPath != null)
ImageViewLoader.loadImage(imageView, artworkPath);
}
// Sets the title
textView = (TextView)view.findViewById(R.id.text_music_track_title);
textView.setText(musicTrack.getTitle());
textView.setTextColor(mContext.getResources().getColor(musicTrack.isOfflineAvailable() ? R.color.text_music_title : R.color.text_music_disable_title));
// Set the artist
// Sets the artist
textView = (TextView)view.findViewById(R.id.text_music_track_artist);
textView.setText(musicTrack.getArtist());
textView.setTextColor(mContext.getResources().getColor(musicTrack.isOfflineAvailable() ? R.color.text_music_description : R.color.text_music_disable_description));

View file

@ -23,20 +23,17 @@
package de.arcus.playmusicexporter2.adapter;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.List;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.utils.ImageViewLoader;
import de.arcus.playmusiclib.items.MusicTrack;
import de.arcus.playmusiclib.items.MusicTrackList;
/**

View file

@ -20,30 +20,35 @@
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2;
package de.arcus.playmusicexporter2.fragments;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.adapter.MusicTrackAdapter;
import de.arcus.playmusicexporter2.utils.ImageViewLoader;
import de.arcus.playmusicexporter2.utils.MusicPathBuilder;
import de.arcus.playmusiclib.PlayMusicManager;
import de.arcus.playmusiclib.items.MusicTrack;
import de.arcus.playmusiclib.items.MusicTrackList;
/**
* A fragment representing a single Track detail screen.
* This fragment is either contained in a {@link TrackListActivity}
* in two-pane mode (on tablets) or a {@link TrackDetailActivity}
* This fragment is either contained in a {@link de.arcus.playmusicexporter2.activitys.MusicTrackListActivity}
* in two-pane mode (on tablets) or a {@link de.arcus.playmusicexporter2.activitys.MusicTrackDetailActivity}
* on handsets.
*/
public class TrackDetailFragment extends Fragment {
public class MusicTrackDetailFragment extends Fragment {
/**
* The fragment argument representing the item ID that this fragment
* represents.
@ -60,7 +65,7 @@ public class TrackDetailFragment extends Fragment {
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public TrackDetailFragment() {
public MusicTrackDetailFragment() {
}
@Override
@ -90,32 +95,67 @@ public class TrackDetailFragment extends Fragment {
// Show the dummy content as text in a TextView.
if (mMusicTrackList != null) {
final ListView listView = (ListView)rootView.findViewById(R.id.list_music_track);
final MusicTrackAdapter musicTrackAdapter = new MusicTrackAdapter(getActivity());
musicTrackAdapter.setShowArtworks(mMusicTrackList.getShowArtworkInTrack());
MusicTrackAdapter musicTrackAdapter = new MusicTrackAdapter(getActivity());
View headerView = inflater.inflate(R.layout.header_music_track_list, listView, false);
headerView.setEnabled(false);
TextView textView;
ImageView imageView;
// Sets the artwork image
imageView = (ImageView)headerView.findViewById(R.id.image_music_track_artwork);
imageView.setImageResource(R.drawable.cd_case);
String artworkPath = mMusicTrackList.getArtworkPath();
if (artworkPath != null)
ImageViewLoader.loadImage(imageView, artworkPath);
// Sets the title
textView = (TextView)headerView.findViewById(R.id.text_music_track_list_title);
textView.setText(mMusicTrackList.getTitle());
// Sets the description
textView = (TextView)headerView.findViewById(R.id.text_music_track_list_description);
textView.setText(mMusicTrackList.getDescription());
listView.addHeaderView(headerView);
musicTrackAdapter.setList(mMusicTrackList.getMusicTrackList());
listView.setAdapter(musicTrackAdapter);
listView.setDrawSelectorOnTop(false);
//listView.setDrawSelectorOnTop(false);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
listView.setItemsCanFocus(false);
Log.d("onItemSelected", "pos: " + position);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d("onItemClick", "pos: " + position);
listView.setItemChecked(position, true);
// The header is not clicked
if (position > 0) {
// We need to subtract the header view
position -= 1;
// Gets the selected track
MusicTrack musicTrack = musicTrackAdapter.getItem(position);
// Track is available
if (musicTrack.isOfflineAvailable()) {
// Build the path
String path = MusicPathBuilder.Build(musicTrack, "{album-artist}/{album}/{disc=CD $}/{no=$$.} {title}.mp3");
// Path to the public music folder
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + "/" + path;
PlayMusicManager playMusicManager = PlayMusicManager.getInstance();
if (playMusicManager != null) {
playMusicManager.exportMusicTrack(musicTrack, path);
}
}
}
}
});
}

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2;
package de.arcus.playmusicexporter2.fragments;
import android.app.Activity;
import android.os.Bundle;
@ -39,12 +39,12 @@ import de.arcus.playmusiclib.items.MusicTrackList;
* A list fragment representing a list of Tracks. This fragment
* also supports tablet devices by allowing list items to be given an
* 'activated' state upon selection. This helps indicate which item is
* currently being viewed in a {@link TrackDetailFragment}.
* currently being viewed in a {@link MusicTrackDetailFragment}.
* <p/>
* Activities containing this fragment MUST implement the {@link Callbacks}
* interface.
*/
public class TrackListFragment extends ListFragment {
public class MusicTrackListFragment extends ListFragment {
/**
* The serialization (saved instance state) Bundle key representing the
@ -91,7 +91,7 @@ public class TrackListFragment extends ListFragment {
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public TrackListFragment() {
public MusicTrackListFragment() {
}
/**

View file

@ -0,0 +1,391 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2.fragments;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import de.arcus.playmusicexporter2.R;
/**
* Fragment used for managing interactions for and presentation of a navigation drawer.
* See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
* design guidelines</a> for a complete explanation of the behaviors implemented here.
*/
public class NavigationDrawerFragment extends Fragment {
/**
* Remember the position of the selected item.
*/
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
/**
* Per the design guidelines, you should show the drawer on launch until the user manually
* expands it. This shared preference tracks this.
*/
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
/**
* A pointer to the current callbacks instance (the Activity).
*/
private NavigationDrawerCallbacks mCallbacks;
/**
* Helper component that ties the action bar to the navigation drawer.
*/
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private View mFragmentContainerView;
private int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState;
private boolean mUserLearnedDrawer;
private Button mButtonTypeAlbum;
private Button mButtonTypeArtist;
private Button mButtonTypePlaylist;
private Button mButtonTypeRated;
private Button mButtonSettings;
public enum ViewType {
Album, Artist, Playlist, Rated
}
private ViewType mViewType;
/**
* @return Gets the current view type
*/
public ViewType getViewType() {
return mViewType;
}
/**
* @param viewType Sets the current view type
*/
private void setViewType(ViewType viewType) {
// Change the ui
setButtonActive(mButtonTypeAlbum, viewType == ViewType.Album);
setButtonActive(mButtonTypeArtist, viewType == ViewType.Artist);
setButtonActive(mButtonTypePlaylist, viewType == ViewType.Playlist);
setButtonActive(mButtonTypeRated, viewType == ViewType.Rated);
if (viewType != mViewType)
if (mCallbacks != null) mCallbacks.onViewTypeChanged(viewType);
mViewType = viewType;
// Close the drawer
if (mDrawerLayout != null)
mDrawerLayout.closeDrawers();
}
public NavigationDrawerFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Read in the flag indicating whether or not the user has demonstrated awareness of the
// drawer. See PREF_USER_LEARNED_DRAWER for details.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Indicate that this fragment would like to influence the set of actions in the action bar.
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_navigation_drawer, container, false);
// Gets all buttons
mButtonTypeAlbum = (Button)view.findViewById(R.id.button_type_album);
mButtonTypeArtist = (Button)view.findViewById(R.id.button_type_artist);
mButtonTypePlaylist = (Button)view.findViewById(R.id.button_type_playlist);
mButtonTypeRated = (Button)view.findViewById(R.id.button_type_rated);
mButtonSettings = (Button)view.findViewById(R.id.button_setting);
// Set the default
setViewType(ViewType.Album);
// Click on album
mButtonTypeAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setViewType(ViewType.Album);
}
});
// Click on artist
mButtonTypeArtist.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setViewType(ViewType.Artist);
}
});
// Click on playlist
mButtonTypePlaylist.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setViewType(ViewType.Playlist);
}
});
// Click on rated
mButtonTypeRated.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setViewType(ViewType.Rated);
}
});
// Color the settings button
setButtonActive(mButtonSettings, false);
return view;
}
/**
* Format the button
* @param button The button
* @param active Active
*/
public void setButtonActive(Button button, boolean active) {
// Gets the button
//Button button = (Button)parentView.findViewById(resID);
int colorText;
int colorBackground;
// Button is active
if (active) {
// Gets the active color
colorText = getResources().getColor(R.color.button_navigation_drawer_text_active);
colorBackground = getResources().getColor(R.color.button_navigation_drawer_active);
} else {
// Gets the normal color
colorText = getResources().getColor(R.color.button_navigation_drawer_text);
colorBackground = getResources().getColor(R.color.button_navigation_drawer_normal);
}
// Sets the color
button.setBackgroundColor(colorBackground);
button.setTextColor(colorText);
button.getCompoundDrawables()[0].setColorFilter(colorText, PorterDuff.Mode.MULTIPLY);
}
public boolean isDrawerOpen() {
return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
}
public void setOnListViewChanged(NavigationDrawerCallbacks callback) {
mCallbacks = callback;
}
/**
* Users of this fragment must call this method to set up the navigation drawer interactions.
*
* @param fragmentId The android:id of this fragment in its activity's layout.
* @param drawerLayout The DrawerLayout containing this fragment's UI.
*/
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view with items and click listener
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the navigation drawer and the action bar app icon.
mDrawerToggle = new ActionBarDrawerToggle(
getActivity(), /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
R.string.navigation_drawer_close /* "close drawer" description for accessibility */
) {
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
if (!mUserLearnedDrawer) {
// The user manually opened the drawer; store this flag to prevent auto-showing
// the navigation drawer automatically in the future.
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).commit();
}
getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
};
// If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
}
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Forward the new configuration the drawer toggle component.
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// If the drawer is open, show the global app actions in the action bar. See also
// showGlobalContextActionBar, which controls the top-left area of the action bar.
if (mDrawerLayout != null && isDrawerOpen()) {
//inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
/*if (item.getItemId() == R.id.action_example) {
Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
return true;
}*/
return super.onOptionsItemSelected(item);
}
/**
* Per the navigation drawer design guidelines, updates the action bar to show the global app
* 'context', rather than just what's in the current screen.
*/
private void showGlobalContextActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.app_name);
}
private ActionBar getActionBar() {
return ((ActionBarActivity) getActivity()).getSupportActionBar();
}
/**
* Callbacks interface that all activities using this fragment must implement.
*/
public static interface NavigationDrawerCallbacks {
/**
* Called when an item in the navigation drawer is selected.
*/
void onViewTypeChanged(ViewType viewType);
}
}

View file

@ -0,0 +1,191 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.playmusicexporter2.utils;
import android.text.TextUtils;
import de.arcus.framework.logger.Logger;
import de.arcus.playmusiclib.items.MusicTrack;
/**
* Helper class te create a path by a user defined structure
*/
public class MusicPathBuilder {
/**
* Hides the constructor
*/
private MusicPathBuilder() {}
/**
* Generates a path from a user defined patter
* @param musicTrack The music track data
* @param patter The patter
* @return Returns the file path
*/
public static String Build(MusicTrack musicTrack, String patter)
{
String path = "";
int pos = 0;
// While there is an open tag
while (patter.indexOf('{', pos) >= 0)
{
// Gets the start and the end of the tag
int posStart = patter.indexOf('{', pos);
int posEnd = patter.indexOf('}', posStart);
// Gets the equal sign
int posEqual = patter.indexOf('=', posStart);
// Adds the part between this tag and the last one to the path
path += patter.substring(pos, posStart);
if (posEnd >= 0) {
// Name of the tag
String name;
String value = "";
// There is an equal sign
if (posEqual >= 0 && posEqual < posEnd) {
name = patter.substring(posStart + 1, posEqual);
} else {
name = patter.substring(posStart + 1, posEnd);
}
// Trim and lower
name = name.trim().toLowerCase();
// Gets the values
switch (name) {
case "album-artist":
if (!TextUtils.isEmpty(musicTrack.getAlbumArtist()))
value = musicTrack.getAlbumArtist();
break;
case "album":
if (!TextUtils.isEmpty(musicTrack.getAlbum()))
value = musicTrack.getAlbum();
break;
case "group":
if (!TextUtils.isEmpty(musicTrack.getContainerName()))
value = musicTrack.getContainerName();
break;
case "artist":
if (!TextUtils.isEmpty(musicTrack.getArtist()))
value = musicTrack.getArtist();
break;
case "title":
if (!TextUtils.isEmpty(musicTrack.getTitle()))
value = musicTrack.getTitle();
break;
case "disc":
if (musicTrack.getDiscNumber() > 0)
value = String.valueOf(musicTrack.getDiscNumber());
break;
case "no":
if (musicTrack.getTrackNumber() > 0)
value = String.valueOf(musicTrack.getTrackNumber());
break;
case "year":
if (!TextUtils.isEmpty(musicTrack.getYear()))
value = musicTrack.getYear();
break;
case "genre":
if (!TextUtils.isEmpty(musicTrack.getGenre()))
value = musicTrack.getGenre();
break;
default:
// Unknown tag
Logger.getInstance().logWarning("MusicPathBuilder", "Unknown tag '" + name + "'");
break;
}
// Equal sign exists
if (posEqual >= 0 && posEqual < posEnd && !TextUtils.isEmpty(value)) {
String format = patter.substring(posEqual + 1, posEnd);
// Gets the insert sign
int posInsertStart = format.indexOf('$');
if (posInsertStart >= 0) {
int posInsertEnd = posInsertStart + 1;
// Search the end
while(posInsertEnd < format.length() && format.charAt(posInsertEnd) == '$') {
posInsertEnd ++;
}
// Fill Zeros
while(value.length() < posInsertEnd - posInsertStart) {
value = "0" + value;
}
// Adds the rest of the format to the value
value = format.substring(0, posInsertStart) + value + format.substring(posInsertEnd);
} else {
// Missing insert sign
Logger.getInstance().logWarning("MusicPathBuilder", "Cloud not find replace symbol ('$') of format attribute in tag '" + name + "'");
}
}
// Adds the value
path += cleanFilename(value);
pos = posEnd + 1;
} else {
path += "{";
pos = posStart + 1;
Logger.getInstance().logWarning("MusicPathBuilder", "Cloud not find end symbol ('}') of the tag in patter '" + patter + "'");
}
}
// Insert end
path += patter.substring(pos, patter.length());
// Remove double slash
while(path.contains("//"))
path = path.replace("//", "/");
// Return path
return path;
}
/**
* Removes forbidden chars in the filename
* @param filename The filename
* @return Returns the new clean filename
*/
public static String cleanFilename(String filename)
{
// Forbidden chars
filename = filename.replace('\\', '-');
filename = filename.replace(':', '-');
filename = filename.replace('*', '-');
filename = filename.replace('?', '-');
filename = filename.replace('"', '-');
filename = filename.replace('<', '-');
filename = filename.replace('>', '-');
filename = filename.replace('|', '-');
return filename;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/button_navigation_drawer_hover">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/button_navigation_drawer_normal"/>
</shape>
</item>
</ripple>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/button_navigation_drawer_hover">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/button_navigation_drawer_selected"/>
</shape>
</item>
</ripple>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_navigation_drawer_normal"
android:state_selected="false"
android:state_pressed="false"/>
<item android:drawable="@drawable/button_navigation_drawer_selected"
android:state_selected="false"
android:state_pressed="true"/>
<item android:drawable="@drawable/button_navigation_drawer_selected"
android:state_selected="true"
android:state_pressed="false"/>
<item android:drawable="@drawable/button_navigation_drawer_selected"
android:state_selected="true"
android:state_pressed="true"/>
</selector>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/button_navigation_drawer_normal"/>
</shape>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/button_navigation_drawer_selected"/>
</shape>

View file

@ -20,8 +20,38 @@
~ THE SOFTWARE.
-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/track_list"
android:name="de.arcus.playmusicexporter2.TrackListFragment" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".TrackListActivity"
tools:layout="@android:layout/list_content" />
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".TrackListActivity">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<fragment android:id="@+id/track_list"
android:name="de.arcus.playmusicexporter2.fragments.MusicTrackListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TrackListActivity"
tools:layout="@android:layout/list_content" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="@+id/navigation_drawer"
android:layout_width="@dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="de.arcus.playmusicexporter2.fragments.NavigationDrawerFragment"
tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>

View file

@ -20,31 +20,51 @@
~ THE SOFTWARE.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal" android:orientation="horizontal"
android:showDividers="middle" tools:context=".TrackListActivity">
<!--
This layout is a two-pane layout for the Tracks
master/detail flow.
See res/values-large/refs.xml and
res/values-sw600dp/refs.xml for an example of layout aliases
that replace the single-pane version of the layout with
this two-pane version.
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".TrackListActivity">
For more on layout aliases, see:
http://developer.android.com/training/multiscreen/screensizes.html#TaskUseAliasFilters
-->
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal" android:orientation="horizontal"
android:showDividers="middle" tools:context=".TrackListActivity">
<fragment android:id="@+id/track_list"
android:name="de.arcus.playmusicexporter2.TrackListFragment" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_weight="1.5"
tools:layout="@android:layout/list_content" />
<!--
This layout is a two-pane layout for the Tracks
master/detail flow.
See res/values-large/refs.xml and
res/values-sw600dp/refs.xml for an example of layout aliases
that replace the single-pane version of the layout with
this two-pane version.
<FrameLayout android:id="@+id/track_detail_container" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_weight="3" />
For more on layout aliases, see:
http://developer.android.com/training/multiscreen/screensizes.html#TaskUseAliasFilters
-->
<fragment android:id="@+id/track_list"
android:name="de.arcus.playmusicexporter2.fragments.MusicTrackListFragment" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_weight="1.5"
tools:layout="@android:layout/list_content" />
</LinearLayout>
<FrameLayout android:id="@+id/track_detail_container" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_weight="3" />
</LinearLayout>
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="@+id/navigation_drawer"
android:layout_width="@dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="de.arcus.playmusicexporter2.fragments.NavigationDrawerFragment"
tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>

View file

@ -24,29 +24,65 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingTop="16dp"
android:paddingBottom="16dp">
android:gravity="center_vertical">
<TextView
android:layout_width="64dp"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="1"
android:id="@+id/text_music_track_number"
android:gravity="center"
android:layout_centerVertical="true"
android:textSize="20dp"
android:textColor="@color/text_music_number" />
android:id="@+id/relative_layout_left"
android:layout_centerVertical="true">
<RelativeLayout
android:layout_width="@dimen/music_track_artwork_size"
android:layout_height="wrap_content"
android:id="@+id/relative_layout_number"
android:layout_centerVertical="true">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="1"
android:id="@+id/text_music_track_number"
android:gravity="center"
android:textSize="16dp"
android:textColor="@color/text_music_number" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="CD 1"
android:id="@+id/text_music_track_disc_number"
android:layout_below="@+id/text_music_track_number"
android:gravity="center" />
</RelativeLayout>
<RelativeLayout
android:layout_width="@dimen/music_track_artwork_size"
android:layout_height="@dimen/music_track_artwork_size"
android:id="@+id/relative_layout_artwork"
android:layout_marginRight="16dp">
<ImageView
android:layout_width="@dimen/music_track_artwork_size"
android:layout_height="@dimen/music_track_artwork_size"
android:id="@+id/image_music_track_artwork"
android:scaleType="centerCrop" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/text_music_track_number"
android:layout_toEndOf="@+id/text_music_track_number"
android:paddingLeft="8dp"
android:layout_toEndOf="@+id/relative_layout_left"
android:paddingRight="8dp"
android:id="@+id/relativeLayout">
android:id="@+id/relative_layout_title"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/relative_layout_left"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:layout_width="wrap_content"

View file

@ -30,10 +30,15 @@
android:layout_width="@dimen/music_track_list_artwork_size"
android:layout_height="@dimen/music_track_list_artwork_size"
android:id="@+id/image_music_track_artwork"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:scaleType="centerCrop" />
android:scaleType="centerCrop"
android:src="@drawable/cd_case" />
<ImageView
android:layout_width="@dimen/music_track_list_artwork_size"
android:layout_height="@dimen/music_track_list_artwork_size"
android:id="@+id/image_music_track_artwork_overlay"
android:scaleType="centerCrop"
android:src="@drawable/cd_overlay" />
<RelativeLayout
android:layout_width="fill_parent"

View file

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:background="@color/navigation_drawer_background">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_type_album"
android:drawableStart="@drawable/ic_type_album"
android:text="@string/title_view_album"
android:id="@+id/button_type_album"
style="@style/AppTheme.Button" />
<Button
style="@style/AppTheme.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_type_artist"
android:drawableStart="@drawable/ic_type_artist"
android:text="@string/title_view_artist"
android:id="@+id/button_type_artist" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_type_playlist"
android:drawableStart="@drawable/ic_type_playlist"
android:text="@string/title_view_playlist"
android:id="@+id/button_type_playlist"
style="@style/AppTheme.Button" />
<Button
style="@style/AppTheme.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_type_rated"
android:drawableStart="@drawable/ic_type_rated"
android:text="@string/title_view_rated"
android:id="@+id/button_type_rated" />
<Button
style="@style/AppTheme.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:drawableLeft="@drawable/ic_action_settings"
android:drawableStart="@drawable/ic_action_settings"
android:text="@string/title_settings"
android:id="@+id/button_setting" />
</LinearLayout>

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/music_track_list_header_artwork_size"
android:id="@+id/relative_layout_header">
<ImageView
android:layout_width="@dimen/music_track_list_header_artwork_size"
android:layout_height="@dimen/music_track_list_header_artwork_size"
android:id="@+id/image_music_track_artwork"
android:scaleType="centerCrop"
android:src="@drawable/cd_case" />
<ImageView
android:layout_width="@dimen/music_track_list_header_artwork_size"
android:layout_height="@dimen/music_track_list_header_artwork_size"
android:id="@+id/image_music_track_artwork_overlay"
android:scaleType="centerCrop"
android:src="@drawable/cd_overlay" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_toRightOf="@+id/image_music_track_artwork"
android:layout_toEndOf="@+id/image_music_track_artwork"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/text_music_track_list_title"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:maxLines="2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="@+id/text_music_track_list_description"
android:layout_below="@+id/text_music_track_list_title"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/text_music_track_list_title"
android:layout_alignEnd="@+id/text_music_track_list_title"
android:maxLines="2" />
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<string name="app_name">Play Music Exporter</string>
<string name="navigation_drawer_close">Drawer schließen</string>
<string name="view_type_selection_title">Ansicht</string>
<string name="title_view_rated">Positiv bewertet</string>
<string name="title_view_playlist">Playlists</string>
<string name="title_view_artist">Interpreten</string>
<string name="title_view_album">Alben</string>
<string name="navigation_drawer_open">Drawer öffnen</string>
<string name="title_track_detail">Titeldetails</string>
<string name="title_settings">Einstellungen</string>
</resources>

View file

@ -26,10 +26,22 @@
<color name="application_main_dark">#e65100</color>
<color name="text_music_number">#ff000000</color>
<color name="text_music_disc_number">#88000000</color>
<color name="text_music_title">#ff000000</color>
<color name="text_music_description">#88000000</color>
<color name="text_music_disable_number">#44000000</color>
<color name="text_music_disable_disc_number">#22000000</color>
<color name="text_music_disable_title">#44000000</color>
<color name="text_music_disable_description">#22000000</color>
<color name="navigation_drawer_background">#f5f5f5</color>
<color name="button_navigation_drawer_normal">#00000000</color>
<color name="button_navigation_drawer_selected">#11000000</color>
<color name="button_navigation_drawer_hover">#808080</color>
<color name="button_navigation_drawer_active">#11000000</color>
<color name="button_navigation_drawer_text">#88000000</color>
<color name="button_navigation_drawer_text_active">#ef6c00</color>
</resources>

View file

@ -23,4 +23,8 @@
<resources>
<dimen name="music_track_list_artwork_size">86dp</dimen>
<dimen name="music_track_list_header_artwork_size">128dp</dimen>
<dimen name="music_track_artwork_size">86dp</dimen>
<dimen name="navigation_drawer_width">280dp</dimen>
</resources>

View file

@ -26,4 +26,14 @@
<string name="app_name">Play Music Exporter</string>
<string name="title_track_detail">Track Detail</string>
<string name="navigation_drawer_open">Open drawer</string>
<string name="navigation_drawer_close">Close drawer</string>
<string name="view_type_selection_title">View</string>
<string name="title_view_album">Albums</string>
<string name="title_view_artist">Artists</string>
<string name="title_view_playlist">Playlists</string>
<string name="title_view_rated">Good rated</string>
<string name="title_settings">Settings</string>
</resources>

View file

@ -27,5 +27,24 @@
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/application_main</item>
<item name="colorPrimaryDark">@color/application_main_dark</item>
<item name="actionBarStyle">@style/AppTheme.ActionBar</item>
</style>
<style name="AppTheme.ActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<!-- Removes the shadow from the action bar -->
<item name="elevation">0dp</item>
</style>
<style name="AppTheme.Button">
<item name="android:background">@drawable/button_navigation_drawer</item>
<item name="android:buttonStyle">@null</item>
<item name="android:textColor">@color/button_navigation_drawer_text</item>
<item name="android:paddingTop">5dp</item>
<item name="android:paddingBottom">5dp</item>
<item name="android:paddingLeft">10dp</item>
<item name="android:paddingRight">10dp</item>
<item name="android:textSize">16sp</item>
<item name="android:drawablePadding">10dp</item>
<item name="android:gravity">start|center_vertical</item>
</style>
</resources>

View file

@ -38,6 +38,7 @@ import com.mpatric.mp3agic.ID3v23Tag;
import com.mpatric.mp3agic.ID3v24Tag;
import com.mpatric.mp3agic.Mp3File;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@ -437,6 +438,11 @@ public class PlayMusicManager {
}
}
// Creates the destination directory
String directory = new File(dest).getParent();
if (directory != null && !FileTools.directoryExists(directory))
FileTools.directoryCreate(directory);
// We want to export the ID3 tags
if (mID3Enable) {
// Adds the meta data
@ -536,11 +542,13 @@ public class PlayMusicManager {
tagID3v2.setPartOfSet("" + musicTrack.getDiscNumber());
tagID3v2.setYear(musicTrack.getYear());
try {
// Maybe the genre is not supported
tagID3v2.setGenreDescription(musicTrack.getGenre());
} catch (IllegalArgumentException e) {
Logger.getInstance().logWarning("TrackWriteID3", e.getMessage());
if (!TextUtils.isEmpty(musicTrack.getGenre())) {
try {
// Maybe the genre is not supported
tagID3v2.setGenreDescription(musicTrack.getGenre());
} catch (IllegalArgumentException e) {
Logger.getInstance().logWarning("TrackWriteID3", e.getMessage());
}
}
// Add the artwork to the meta data

View file

@ -62,6 +62,11 @@ public class AlbumDataSource extends DataSource<Album> {
*/
private String mSearchKey;
/**
* If this is set the data source will only load tracks which are positive rated
*/
private boolean mRatedOnly;
/**
* @return Returns whether the data source should only load offline tracks
*/
@ -90,6 +95,20 @@ public class AlbumDataSource extends DataSource<Album> {
mSearchKey = searchKey;
}
/**
* @return Returns whether the data source should only load positive rated tracks
*/
public boolean getRatedOnly() {
return mRatedOnly;
}
/**
* @param ratedOnly Sets whether the data source should only load positive rated tracks
*/
public void setRatedOnly(boolean ratedOnly) {
mRatedOnly = ratedOnly;
}
/**
* Creates a new data source
* @param playMusicManager The manager
@ -114,6 +133,10 @@ public class AlbumDataSource extends DataSource<Album> {
if (mOfflineOnly)
where = combineWhere(where, "LocalCopyPath IS NOT NULL");
// Loads only positive rated tracks
if (mRatedOnly)
where = combineWhere(where, "Rating > 0");
// Search only items which contains the key
if (!TextUtils.isEmpty(mSearchKey)) {
String searchKey = DatabaseUtils.sqlEscapeString("%" + mSearchKey + "%");

View file

@ -100,7 +100,7 @@ public abstract class DataSource<T> {
*/
protected List<T> getItems(String table, String[] columns, String where, String orderBy, String groupBy) {
// No connection; abort
if (!mPlayMusicManager.getDatabase().isOpen()) return null;
if (mPlayMusicManager.getDatabase() == null || !mPlayMusicManager.getDatabase().isOpen()) return null;
// Creates the list
List<T> items = new LinkedList<>();

View file

@ -58,6 +58,7 @@ public class MusicTrackDataSource extends DataSource<MusicTrack> {
private final static String COLUMN_TRACK_NUMBER = "MUSIC.TrackNumber";
private final static String COLUMN_DISC_NUMBER = "MUSIC.DiscNumber";
private final static String COLUMN_DURATION = "MUSIC.Duration";
private final static String COLUMN_RATING = "MUSIC.Rating";
private final static String COLUMN_ALBUM_ID = "MUSIC.AlbumId";
private final static String COLUMN_CLIENT_ID = "MUSIC.ClientId";
private final static String COLUMN_SOURCE_ID = "MUSIC.SourceId";
@ -67,7 +68,7 @@ public class MusicTrackDataSource extends DataSource<MusicTrack> {
// All columns
private final static String[] COLUMNS_ALL = { COLUMN_ID, COLUMN_SIZE,
COLUMN_LOCALCOPYPATH, COLUMN_LOCALCOPYTYPE, COLUMN_LOCALCOPYSTORAGETYPE, COLUMN_TITLE, COLUMN_ARTIST_ID, COLUMN_ARTIST, COLUMN_ALBUM_ARTIST,
COLUMN_ALBUM, COLUMN_GENRE, COLUMN_YEAR, COLUMN_TRACK_NUMBER, COLUMN_DISC_NUMBER, COLUMN_DURATION,
COLUMN_ALBUM, COLUMN_GENRE, COLUMN_YEAR, COLUMN_TRACK_NUMBER, COLUMN_DISC_NUMBER, COLUMN_DURATION, COLUMN_RATING,
COLUMN_ALBUM_ID, COLUMN_CLIENT_ID, COLUMN_SOURCE_ID, COLUMN_ARTWORK_FILE, COLUMN_CPDATA };
/**
@ -183,6 +184,7 @@ public class MusicTrackDataSource extends DataSource<MusicTrack> {
instance.setTrackNumber(cursor.getLong(getColumnsIndex(COLUMNS_ALL, COLUMN_TRACK_NUMBER)));
instance.setDiscNumber(cursor.getLong(getColumnsIndex(COLUMNS_ALL, COLUMN_DISC_NUMBER)));
instance.setDuration(cursor.getLong(getColumnsIndex(COLUMNS_ALL, COLUMN_DURATION)));
instance.setRating(cursor.getLong(getColumnsIndex(COLUMNS_ALL, COLUMN_RATING)));
instance.setAlbumId(cursor.getLong(getColumnsIndex(COLUMNS_ALL, COLUMN_ALBUM_ID)));
instance.setClientId(cursor.getString(getColumnsIndex(COLUMNS_ALL, COLUMN_CLIENT_ID)));
instance.setSourceId(cursor.getString(getColumnsIndex(COLUMNS_ALL, COLUMN_SOURCE_ID)));

View file

@ -31,7 +31,7 @@ import de.arcus.playmusiclib.PlayMusicManager;
*/
public class MusicTrack {
// Variables
private long mId, mSize, mTrackNumber, mDiscNumber, mAlbumId, mArtistId, mLocalCopyType, mLocalCopyStorageType, mDuration;
private long mId, mSize, mTrackNumber, mDiscNumber, mAlbumId, mArtistId, mLocalCopyType, mLocalCopyStorageType, mDuration, mRating;
private String mTitle, mArtist, mAlbum, mAlbumArtist, mLocalCopyPath, mGenre, mYear, mClientId, mSourceId, mArtworkFile;
private byte[] mCpData;
@ -121,6 +121,20 @@ public class MusicTrack {
this.mDuration = duration;
}
/**
* @return Gets the rating of the track
*/
public long getRating() {
return mRating;
}
/**
* @param rating Sets the rating of the track
*/
public void setRating(long rating) {
this.mRating = rating;
}
/**
* @return Gets the local copy type
*/