Add multiselection

This commit is contained in:
David Schulte 2015-04-28 23:00:43 +02:00
parent 819cce3870
commit 22f53fbc0f
27 changed files with 578 additions and 80 deletions

View file

@ -0,0 +1,219 @@
/*
* 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.framework.utils;
import android.support.annotation.ColorRes;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* Selection list
*/
public class SelectionList<T> {
/**
* The selected items
*/
private List<T> mItems = new ArrayList<>();
/**
* The activity
* We need the activity to show the action mode when some items are selected
*/
private ActionBarActivity mActivity;
/**
* The action mode
*/
private ActionMode mActionMode;
/**
* The callback for the action mode
*/
private ActionMode.Callback mActionModeCallback;
/**
* The colors
*/
private @ColorRes int mResColorNormal;
private @ColorRes int mResColorSelected;
/**
* Sets the colors of the view.
* Use @SuppressWarnings("ResourceAsColor") to prevent Lint errors
* @param colorNormal Normal state
* @param colorSelected Selected state
*/
public void setColor(@ColorRes int colorNormal, @ColorRes int colorSelected) {
mResColorNormal = colorNormal;
mResColorSelected = colorSelected;
}
/**
* Sets up the action mode for this selection list
* @param activity The activity
*/
public void setupActionMode(ActionBarActivity activity, ActionMode.Callback callback) {
mActivity = activity;
mActionModeCallback = callback;
// Updates the action mode
updateActionModeMenu();
}
/**
* Set the selection state of the item
* @param item The item
* @param state The selection state
*/
public void setSelected(T item, boolean state) {
// Adds the item to the selection list
if (state && !mItems.contains(item))
mItems.add(item);
// Removes the item from the selection list
if (!state && mItems.contains(item))
mItems.remove(item);
// Updates the action mode
updateActionModeMenu();
}
/**
* Set the selection state of the item and change the item background
* @param item The item
* @param state The selection state
* @param view The view
*/
public void setSelected(T item, boolean state, View view) {
// Set the selection state
setSelected(item, state);
// Change the background
if (state)
view.setBackgroundColor(view.getResources().getColor(mResColorSelected));
else
view.setBackgroundColor(view.getResources().getColor(mResColorNormal));
}
/**
* Toggles the item
* @param item The selected item
* @return Returns whether the item is now selected
*/
public boolean toggle(T item) {
boolean state = isSelected(item);
setSelected(item, !state);
return !state;
}
/**
* Toggles the item
* @param item The selected item
* @param view The view
* @return Returns whether the item is now selected
*/
public boolean toggle(T item, View view) {
boolean state = isSelected(item);
setSelected(item, !state, view);
return !state;
}
/**
* Gets all selected items
* @return Returns a list with all selected items
*/
public List<T> getSelectedItems() {
return mItems;
}
/**
* Clears the selection
*/
public void clear() {
mItems.clear();
// Updates the action mode
updateActionModeMenu();
}
/**
* Call this after the view was created.
* This will change the background color.
* @param item The selected item
* @param view The view
*/
public void initView(T item, View view) {
// Change the background
if (isSelected(item))
view.setBackgroundColor(view.getResources().getColor(mResColorSelected));
else
view.setBackgroundColor(view.getResources().getColor(mResColorNormal));
}
/**
* Updates the action mode menu
*/
private void updateActionModeMenu() {
// Null check
if (mActionModeCallback != null && mActivity != null && !mActivity.isFinishing()) {
// Some items are selected, shows the action mode
if (mItems.size() > 0 && mActionMode == null) {
mActionMode = mActivity.startSupportActionMode(mActionModeCallback);
}
// Close the action mode
if (mItems.size() == 0 && mActionMode != null) {
// Set mActionMode to null before call finish to prevent recursion
ActionMode actionMode = mActionMode;
mActionMode = null;
// Close the action mode
actionMode.finish();
}
// Set the text
if (mActionMode != null) {
mActionMode.setTitle("TEST: " + mItems.size());
}
}
}
/**
* Gets whether the item is selected
* @param item The selected item
* @return Returns true if the item is selected
*/
public boolean isSelected(T item) {
return mItems.contains(item);
}
}

View file

@ -30,6 +30,7 @@
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".activitys.MusicTrackListActivity"

View file

@ -0,0 +1,88 @@
/*
* 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.actionmode;
import android.content.Context;
import android.support.v7.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.items.SelectedTrack;
/**
* Action mode for selected tracks
*/
public class ActionModeTitle implements ActionMode.Callback {
/**
* The context
*/
private Context mContext;
public ActionModeTitle(Context context) {
mContext = context;
}
// Called when the action mode is created; startActionMode() was called
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.action_mode_selection, menu);
return true;
}
// Called each time the action mode is shown. Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_export:
// Export all selected tracks
for(SelectedTrack selectedTrack : SelectedTrack.getSelectionList().getSelectedItems()) {
selectedTrack.export(mContext);
}
mode.finish();
return true;
default:
return false;
}
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
// Clears the selection
SelectedTrack.getSelectionList().clear();
}
}

View file

@ -31,6 +31,8 @@ import android.view.MenuItem;
import de.arcus.framework.crashhandler.CrashHandler;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.fragments.MusicTrackDetailFragment;
import de.arcus.playmusiclib.PlayMusicManager;
import de.arcus.playmusiclib.items.MusicTrackList;
/**
@ -69,12 +71,25 @@ public class MusicTrackDetailActivity extends ActionBarActivity {
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putLong(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID,
getIntent().getLongExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, 0));
// Loads the track list
long id = getIntent().getLongExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, 0);
String type = getIntent().getStringExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE);
arguments.putString(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE,
getIntent().getStringExtra(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE));
PlayMusicManager playMusicManager = PlayMusicManager.getInstance();
if (playMusicManager != null) {
MusicTrackList musicTrackList = MusicTrackList.deserialize(playMusicManager, id, type);
// Sets the title
setTitle(musicTrackList.getTitle());
}
// Puts the track list information to the fragment
arguments.putLong(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_ID, id);
arguments.putString(MusicTrackDetailFragment.ARG_MUSIC_TRACK_LIST_TYPE, type);
// Loads the fragment
MusicTrackDetailFragment fragment = new MusicTrackDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()

View file

@ -34,6 +34,7 @@ import android.widget.TextView;
import java.util.List;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.items.SelectedTrack;
import de.arcus.playmusicexporter2.utils.ImageViewLoader;
import de.arcus.playmusiclib.items.MusicTrack;
@ -131,10 +132,10 @@ public class MusicTrackAdapter extends ArrayAdapter<MusicTrack> {
// Shows the artwork
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);
ImageViewLoader.loadImage(imageView, artworkPath, R.drawable.cd_case);
}
// Sets the title
@ -150,6 +151,9 @@ public class MusicTrackAdapter extends ArrayAdapter<MusicTrack> {
// Track is available?
view.setEnabled(musicTrack.isOfflineAvailable());
// Selected state
SelectedTrack.getSelectionList().initView(new SelectedTrack(musicTrack.getId()), view);
return view;
}

View file

@ -90,17 +90,11 @@ public class MusicTrackListAdapter extends ArrayAdapter<MusicTrackList> {
// Final for the callback
imageView = (ImageView)view.findViewById(R.id.image_music_track_artwork);
// Default icon
imageView.setImageResource(R.drawable.cd_case);
// Gets the artwork
String artworkPath = musicTrackList.getArtworkPath();
if (artworkPath != null) {
ImageViewLoader.loadImage(imageView, artworkPath);
}
// Loads the artwork
ImageViewLoader.loadImage(imageView, artworkPath, R.drawable.cd_case);
return view;
}

View file

@ -22,10 +22,10 @@
package de.arcus.playmusicexporter2.fragments;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -35,8 +35,9 @@ import android.widget.ListView;
import android.widget.TextView;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.actionmode.ActionModeTitle;
import de.arcus.playmusicexporter2.adapter.MusicTrackAdapter;
import de.arcus.playmusicexporter2.services.ExportService;
import de.arcus.playmusicexporter2.items.SelectedTrack;
import de.arcus.playmusicexporter2.utils.ImageViewLoader;
import de.arcus.playmusicexporter2.utils.MusicPathBuilder;
import de.arcus.playmusiclib.PlayMusicManager;
@ -87,6 +88,9 @@ public class MusicTrackDetailFragment extends Fragment {
mMusicTrackList = MusicTrackList.deserialize(playMusicManager, id, type);
}
}
// Setup the selection list for this activity
SelectedTrack.getSelectionList().setupActionMode((ActionBarActivity)getActivity(), new ActionModeTitle(getActivity()));
}
@Override
@ -109,10 +113,11 @@ public class MusicTrackDetailFragment extends Fragment {
// 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);
// Loads the artwork
ImageViewLoader.loadImage(imageView, artworkPath, R.drawable.cd_case);
// Sets the title
textView = (TextView)headerView.findViewById(R.id.text_music_track_list_title);
@ -132,6 +137,7 @@ public class MusicTrackDetailFragment extends Fragment {
listView.setItemsCanFocus(false);
// Click on one list item
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@ -145,23 +151,15 @@ public class MusicTrackDetailFragment extends Fragment {
// 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;
Intent intent = new Intent(MusicTrackDetailFragment.this.getActivity(), ExportService.class);
// Puts the export parameter
intent.putExtra(ExportService.ARG_EXPORT_TRACK_ID, musicTrack.getId());
intent.putExtra(ExportService.ARG_EXPORT_PATH, path);
// Starts the service
MusicTrackDetailFragment.this.getActivity().startService(intent);
//playMusicManager.exportMusicTrack(musicTrack, path);
// Toggles the music track
SelectedTrack.getSelectionList().toggle(new SelectedTrack(musicTrack.getId(), path), view);
}
}
}

View file

@ -0,0 +1,103 @@
/*
* 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.items;
import android.content.Context;
import android.content.Intent;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusicexporter2.services.ExportService;
import de.arcus.framework.utils.SelectionList;
/**
* The selected track
*/
public class SelectedTrack {
/**
* The instance of the selection
*/
private static SelectionList<SelectedTrack> selectionList;
/**
* Gets the latest instance of the track selection.
* Creates a new one if it doesn't exist.
* @return The instance
*/
@SuppressWarnings("ResourceAsColor")
public static SelectionList<SelectedTrack> getSelectionList() {
// Create a new instance
if (selectionList == null) {
selectionList = new SelectionList<>();
// Sets the color resources
selectionList.setColor(R.color.button_navigation_drawer_normal, R.color.button_navigation_drawer_selected);
}
return selectionList;
}
/**
* Type of the track
*/
private long mId;
/**
* The path of the track
*/
private String mPath;
public SelectedTrack(long id) {
mId = id;
}
public SelectedTrack(long id, String path) {
mId = id;
mPath = path;
}
/**
* Adds the track to the export list
*/
public void export(Context context) {
Intent intent = new Intent(context, ExportService.class);
// Puts the export parameter
intent.putExtra(ExportService.ARG_EXPORT_TRACK_ID, mId);
intent.putExtra(ExportService.ARG_EXPORT_PATH, mPath);
// Starts the service
context.startService(intent);
}
@Override
public boolean equals(Object o) {
// Compares two selected tracks
if (o instanceof SelectedTrack) {
SelectedTrack other = (SelectedTrack)o;
return mId == other.mId;
}
return super.equals(o);
}
}

View file

@ -24,6 +24,7 @@ package de.arcus.playmusicexporter2.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
@ -64,6 +65,11 @@ public class ImageViewLoader {
*/
private String mNewImagePath;
/**
* The default image of the image view
*/
private int mDefaultImage;
/**
* @return Gets the path of the image we want to load
*/
@ -71,13 +77,14 @@ public class ImageViewLoader {
return mImagePath;
}
public static void loadImage(ImageView imageView, String path) {
public static void loadImage(ImageView imageView, String path, int defaultImage) {
// Checks for an old artwork loader on this image view
ImageViewLoader imageViewLoader = (ImageViewLoader)imageView.getTag();
if (imageViewLoader == null) {
imageViewLoader = new ImageViewLoader(imageView, path);
if (path == null) path = "";
if (imageViewLoader == null) {
imageViewLoader = new ImageViewLoader(imageView, path, defaultImage);
// Save the loader in the tag
// If someone wants to load another artwork to this view
@ -95,68 +102,85 @@ public class ImageViewLoader {
* @param imageView The image view we want to set
* @param path The path to load
*/
private ImageViewLoader(ImageView imageView, String path) {
private ImageViewLoader(ImageView imageView, String path, int defaultImage) {
mImageView = new WeakReference<>(imageView);
mImagePath = path;
mDefaultImage = defaultImage;
}
/**
* Loads the image asynchronously
*/
private void loadImage() {
mIsLoading = true;
// Show the default icon while loading
final ImageView imageViewDefault = mImageView.get();
if (imageViewDefault != null) {
// Sets the bitmap in the UI thread
Runnable runnable = new Runnable() {
@Override
public void run() {
// Default icon
imageViewDefault.setImageResource(mDefaultImage);
}
};
imageViewDefault.post(runnable);
}
// Be careful! Don't scroll to fast! This will spam the superuser to do list!
SuperUserTools.fileReadToByteArrayAsync(mImagePath, new SuperUserCommandCallback() {
@Override
public void onFinished(SuperUserCommand command) {
if (!TextUtils.isEmpty(mImagePath)) {
mIsLoading = true;
final ImageView imageView = mImageView.get();
// Be careful! Don't scroll to fast! This will spam the superuser to do list!
SuperUserTools.fileReadToByteArrayAsync(mImagePath, new SuperUserCommandCallback() {
@Override
public void onFinished(SuperUserCommand command) {
if (imageView != null) {
final ImageView imageView = mImageView.get();
// Success
if (command.commandWasSuccessful()) {
// Binary data
byte[] bitmapData = command.getStandardOutputBinary();
if (imageView != null) {
// Loads the bitmap
try {
// We already want to load a new image, so we don't need to set this
if (mNewImagePath == null) {
// Loads the bitmap
final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
// Success
if (command.commandWasSuccessful()) {
// Binary data
byte[] bitmapData = command.getStandardOutputBinary();
// The the bitmap in the UI thread
Runnable runnable = new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
};
imageView.post(runnable);
// Loads the bitmap
try {
// We already want to load a new image, so we don't need to set this
if (mNewImagePath == null) {
// Loads the bitmap
final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
// Sets the bitmap in the UI thread
Runnable runnable = new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
};
imageView.post(runnable);
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} else {
// File not found
imageView.setImageResource(R.drawable.cd_case);
}
} else {
// File not found
imageView.setImageResource(R.drawable.cd_case);
}
mIsLoading = false;
// Loads the next image
if (mNewImagePath != null) {
mImagePath = mNewImagePath;
mNewImagePath = null;
loadImage();
}
}
mIsLoading = false;
// Loads the next image
if (mNewImagePath != null) {
mImagePath = mNewImagePath;
mNewImagePath = null;
loadImage();
}
}
});
});
}
}
/**
@ -165,7 +189,9 @@ public class ImageViewLoader {
*/
private void updateImage(String path) {
// The same artwork; nothing to do
if (path.equals(mImagePath)) return;
if (path.equals(mImagePath)) {
return;
}
if (mIsLoading) {
mNewImagePath = path;

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 969 B

View file

@ -45,7 +45,7 @@
android:text="1"
android:id="@+id/text_music_track_number"
android:gravity="center"
android:textSize="16dp"
android:textSize="16sp"
android:textColor="@color/text_music_number" />
<TextView

View file

@ -75,5 +75,6 @@
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,39 @@
<?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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto/">
<item android:id="@+id/action_export"
android:title="@string/action_export"
android:icon="@drawable/ic_action_save"
app:showAsAction="ifRoom" />
<item android:id="@+id/action_share"
android:title="@string/action_share"
android:icon="@drawable/ic_action_share"
app:showAsAction="ifRoom" />
<item android:id="@+id/action_play"
android:title="@string/action_play"
android:icon="@drawable/ic_action_play"
app:showAsAction="ifRoom" />
</menu>

View file

@ -51,4 +51,8 @@
<string name="notification_export_finished_summery">%1$d Titel wurden erfolgreich exportiert!</string>
<string name="notification_export_finished_title">Export abgeschlossen!</string>
<string name="search">Suchen</string>
<string name="button_export_group">Alle Titel exportieren</string>
<string name="action_export">Exportieren</string>
<string name="action_play">Wiedergeben</string>
<string name="action_share">Teilen</string>
</resources>

View file

@ -26,6 +26,10 @@
<string name="app_name">Play Music Exporter</string>
<string name="title_track_detail">Track Detail</string>
<string name="action_export">Export</string>
<string name="action_play">Play</string>
<string name="action_share">Share</string>
<string name="navigation_drawer_open">Open drawer</string>
<string name="navigation_drawer_close">Close drawer</string>
@ -45,6 +49,7 @@
<string name="notification_export_finished_single_summery">Track was exported successfully!</string>
<string name="search">Search</string>
<string name="button_export_group">Export all tracks</string>
<string name="settings_category_export">Export settings</string>
<string name="settings_category_extra">Extras</string>

View file

@ -29,6 +29,7 @@
<item name="colorAccent">@color/application_main</item>
<item name="colorPrimaryDark">@color/application_main_dark</item>
<item name="actionBarStyle">@style/AppTheme.ActionBar</item>
<item name="actionModeBackground">@color/application_main</item>
</style>
<style name="AppTheme.ActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse">