/*
* Copyright (C) 2015 Jorge Ruesga
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ruesga.android.wallpapers.photophase.widgets;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask.Status;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.ruesga.android.wallpapers.photophase.R;
import com.ruesga.android.wallpapers.photophase.model.Album;
import com.ruesga.android.wallpapers.photophase.tasks.AsyncPictureLoaderTask;
import com.ruesga.android.wallpapers.photophase.tasks.AsyncPictureLoaderTask.AsyncPictureLoaderRunnable;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* A view that contains the view of the info of an album
*/
public class AlbumInfoView extends RelativeLayout
implements OnClickListener, OnMenuItemClickListener {
/**
* A convenient listener for receive events of the AlbumPictures class
*/
public interface CallbacksListener {
/**
* Invoked when an album was selected
*
* @param album The album
*/
void onAlbumSelected(Album album);
/**
* Invoked when an album was deselected
*
* @param album The album
*/
void onAlbumDeselected(Album album);
/**
* Invoked when an all of the picture of the album were selected
*
* @param album The album
*/
void onAllPicturesSelected(Album album);
/**
* Invoked when an all of the picture of the album were deselected
*
* @param album The album
*/
void onAllPicturesDeselected(Album album);
}
/**
* A CastService proxy
*/
public interface CastProxy {
/**
* Returns whether there are near devices to cast
*/
boolean hasNearDevices();
/**
* Send this album to the cast device
*/
void cast(Album album);
/**
* Enqueue this album to be send to the cast device
*/
void enqueue(Album album);
}
private class OnPictureLoaded extends AsyncPictureLoaderTask.OnPictureLoaded {
public OnPictureLoaded(Album album) {
super(album);
}
@Override
public void onPictureLoaded(Object o, Drawable drawable) {
((Album)o).setIcon(drawable);
}
}
private List<CallbacksListener> mCallbacks;
private Album mAlbum;
private AsyncPictureLoaderRunnable mTask;
private ImageView mIcon;
private TextView mSelectedItems;
private TextView mName;
private TextView mItems;
private View mOverflowButton;
private boolean mAlbumMode;
private CastProxy mCastProxy;
private DisplayMetrics mMetrics;
/**
* Constructor of <code>AlbumInfoView</code>.
*
* @param context The current context
*/
public AlbumInfoView(Context context) {
super(context);
init();
}
/**
* Constructor of <code>AlbumInfoView</code>.
*
* @param context The current context
* @param attrs The attributes of the XML tag that is inflating the view.
*/
public AlbumInfoView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* Constructor of <code>AlbumInfoView</code>.
*
* @param context The current context
* @param attrs The attributes of the XML tag that is inflating the view.
* @param defStyle The default style to apply to this view. If 0, no style
* will be applied (beyond what is included in the theme). This may
* either be an attribute resource, whose value will be retrieved
* from the current theme, or an explicit style resource.
*/
public AlbumInfoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
* Method that initializes the internal references
*/
private void init() {
mCallbacks = new ArrayList<>();
mAlbumMode = true;
mMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(mMetrics);
}
/**
* Method that set the album mode
*
* @param albumMode The album mode
*/
public void setAlbumMode(boolean albumMode) {
this.mAlbumMode = albumMode;
}
/**
* Method that adds the class that will be listen for events of this class
*
* @param callback The callback class
*/
public void addCallBackListener(CallbacksListener callback) {
this.mCallbacks.add(callback);
}
public void setCastProxy(CastProxy castProxy) {
mCastProxy = castProxy;
}
/**
* {@inheritDoc}
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
updateView(mAlbum);
}
/**
* {@inheritDoc}
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Cancel pending tasks
if (mTask != null) {
removeCallbacks(mTask);
if (mTask.mTask.getStatus() != Status.FINISHED) {
mTask.mTask.cancel(true);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void onClick(View v) {
if (v.equals(mOverflowButton)) {
PopupMenu popup = new PopupMenu(getContext(), v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.album_actions, popup.getMenu());
onPreparePopupMenu(popup.getMenu());
popup.setOnMenuItemClickListener(this);
popup.show();
}
}
/**
* Method called prior to show the popup menu
*
* @param popup The popup menu
*/
private void onPreparePopupMenu(Menu popup) {
if (isSelected()) {
popup.findItem(R.id.mnu_select_album).setVisible(false);
} else {
popup.findItem(R.id.mnu_deselect_album).setVisible(false);
}
if (mAlbumMode) {
popup.findItem(R.id.mnu_select_all).setVisible(false);
popup.findItem(R.id.mnu_deselect_all).setVisible(false);
}
if (mCastProxy == null || !mCastProxy.hasNearDevices()) {
popup.findItem(R.id.mnu_cast).setVisible(false);
popup.findItem(R.id.mnu_enqueue).setVisible(false);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.mnu_select_album:
doSelection(true);
break;
case R.id.mnu_deselect_album:
doSelection(false);
break;
case R.id.mnu_select_all:
notifyPictureSelectionChanged(true);
break;
case R.id.mnu_deselect_all:
notifyPictureSelectionChanged(false);
break;
case R.id.mnu_cast:
mCastProxy.cast(mAlbum);
break;
case R.id.mnu_enqueue:
mCastProxy.enqueue(mAlbum);
break;
default:
return false;
}
return true;
}
/**
* Method that select/deselect the album
*
* @param selected whether the album is selected
*/
private void doSelection(boolean selected) {
setSelected(selected);
mAlbum.setSelected(selected);
mAlbum.setSelectedItems(new ArrayList<String>());
notifySelectionChanged();
updateView(mAlbum);
}
/**
* Method that notifies to all the registered callbacks that the selection
* was changed
*/
private void notifySelectionChanged() {
for (CallbacksListener callback : mCallbacks) {
if (mAlbum.isSelected()) {
callback.onAlbumSelected(mAlbum);
} else {
callback.onAlbumDeselected(mAlbum);
}
}
}
/**
* Method that notifies to all the registered callbacks that the selection
* was changed
*/
private void notifyPictureSelectionChanged(boolean selected) {
for (CallbacksListener callback : mCallbacks) {
if (selected) {
callback.onAllPicturesSelected(mAlbum);
} else {
callback.onAllPicturesDeselected(mAlbum);
}
}
}
/**
* Method that sets the album
*
* @param album The album
*/
public void setAlbum(Album album) {
mAlbum = album;
}
/**
* Method that updates the view
*
* @param album The album data
*/
@SuppressWarnings("boxing")
public void updateView(Album album) {
// Destroy the update drawable task
if (mTask != null) {
removeCallbacks(mTask);
if (mTask.mTask.getStatus() != Status.FINISHED) {
mTask.mTask.cancel(true);
}
}
// Retrieve the views references
if (mIcon == null) {
mIcon = (ImageView)findViewById(R.id.album_thumbnail);
mSelectedItems = (TextView)findViewById(R.id.album_selected_items);
mName = (TextView)findViewById(R.id.album_name);
mItems = (TextView)findViewById(R.id.album_items);
mOverflowButton = findViewById(R.id.overflow_button);
mOverflowButton.setOnClickListener(this);
}
// Update the views
if (album != null) {
Resources res = getContext().getResources();
setAlbum(album);
int selectedItems = album.getSelectedItems().size();
String count = String.valueOf(selectedItems);
if (selectedItems > 99) {
count = "99+";
}
mSelectedItems.setText(count);
mSelectedItems.setVisibility(album.isSelected() ? View.INVISIBLE : View.VISIBLE);
mName.setText(album.getName());
int items = album.getItems().size();
mItems.setText(String.format(res.getQuantityText(
R.plurals.album_number_of_pictures, items).toString(), items));
setSelected(album.isSelected());
Drawable dw = album.getIcon();
mIcon.setImageDrawable(dw);
if (dw == null) {
mIcon.setImageDrawable(null);
// Show as icon, the first picture
File f = new File(album.getItems().get(0).getPath());
AsyncPictureLoaderTask task = new AsyncPictureLoaderTask(getContext(), mIcon,
mMetrics.widthPixels, mMetrics.heightPixels, new OnPictureLoaded(album));
task.mFactor = 8;
mTask = new AsyncPictureLoaderRunnable(task, f);
ViewCompat.postOnAnimation(this, mTask);
}
}
}
}