/**
* Copyright (c) 2013-2014. Francisco Contreras, Holland Salazar.
* Copyright (c) 2015. Tobias Strebitzer, Francisco Contreras, Holland Salazar.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* Neither the name of the Baker Framework nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/
package com.bakerframework.baker.view;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.bakerframework.baker.BakerApplication;
import com.bakerframework.baker.activity.ShelfActivity;
import com.bakerframework.baker.events.ArchiveIssueCompleteEvent;
import com.bakerframework.baker.events.DownloadIssueCompleteEvent;
import com.bakerframework.baker.events.DownloadIssueErrorEvent;
import com.bakerframework.baker.events.DownloadIssueProgressEvent;
import com.bakerframework.baker.events.ExtractIssueCompleteEvent;
import com.bakerframework.baker.events.ExtractIssueErrorEvent;
import com.bakerframework.baker.events.ExtractIssueProgressEvent;
import com.bakerframework.baker.events.IssueDataUpdatedEvent;
import com.bakerframework.baker.helper.ImageLoaderHelper;
import com.bakerframework.baker.jobs.ArchiveIssueJob;
import com.bakerframework.baker.jobs.ParseBookJsonJob;
import com.bakerframework.baker.model.Issue;
import com.bakerframework.baker.R;
import com.bakerframework.baker.settings.Configuration;
import org.solovyev.android.checkout.*;
import de.greenrobot.event.EventBus;
public class IssueCardView extends LinearLayout {
private Issue issue;
private boolean readable = false;
private final int UI_STATE_INITIAL = 0;
private final int UI_STATE_DOWNLOAD = 1;
private final int UI_STATE_EXTRACT = 2;
private final int UI_STATE_READY = 3;
private final int UI_STATE_ARCHIVE = 4;
private final int UI_STATE_ERROR = 5;
// Layout elements
LinearLayout uiIdleActionsContainer;
LinearLayout uiPurchaseActionsContainer;
LinearLayout uiReadyActionsContainer;
LinearLayout uiProgressBarContainer;
ImageView uiCoverImage;
ProgressBar uiProgressBar;
TextView uiProgressText;
TextView uiTitleText;
TextView uiInfoText;
TextView uiDateText;
TextView uiSizeText;
Button uiBuyIssueButton;
Button uiReadIssueButton;
Button uiArchiveIssueButton;
Button uiDownloadIssueButton;
private Activity parentActivity;
/**
* Creates a reference to the parent / shelf activity
*
* @param parentActivity the parent Activity.
*/
public IssueCardView(Context parentActivity, Issue issue) {
super(parentActivity);
this.parentActivity = (Activity)parentActivity;
this.issue = issue;
}
public IssueCardView(Context context) {
super(context);
}
/**
* Initialize the view
*/
public void init(final Context context) {
// Prepare and inflate layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.issue_card_view, this, true);
// Register UI elements
uiIdleActionsContainer = (LinearLayout) findViewById(R.id.idle_actions_container);
uiPurchaseActionsContainer = (LinearLayout) findViewById(R.id.purchase_actions_container);
uiReadyActionsContainer = (LinearLayout) findViewById(R.id.ready_actions_container);
uiProgressBarContainer = (LinearLayout) findViewById(R.id.progress_bar_container);
uiProgressText = (TextView) findViewById(R.id.progress_text);
uiCoverImage = (ImageView) findViewById(R.id.cover_image);
uiProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
uiTitleText = (TextView) findViewById(R.id.title_text);
uiInfoText = (TextView) findViewById(R.id.info_text);
uiDateText = (TextView) findViewById(R.id.date_text);
uiSizeText = (TextView) findViewById(R.id.size_text);
uiBuyIssueButton = (Button) findViewById(R.id.buy_issue_button);
uiReadIssueButton = (Button) findViewById(R.id.read_issue_button);
uiArchiveIssueButton = (Button) findViewById(R.id.archive_issue_button);
uiDownloadIssueButton = (Button) findViewById(R.id.download_issue_button);
// Download cover
ImageLoaderHelper.getImageLoader(context).displayImage(issue.getCover(), uiCoverImage);
// Initialize cover click handler
uiCoverImage.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (readable && !issue.isDownloading()) {
readIssue();
}
}
});
// Initialize purchase button click handler
uiBuyIssueButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) { purchaseIssue(); }
});
// Initialize download button click handler
uiDownloadIssueButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) { downloadIssue(); }
});
// Initialize read button click handler
uiReadIssueButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
readIssue();
}
});
// Initialize archive button click handler
uiArchiveIssueButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
archiveIssue();
}
});
// Initialize event listener
EventBus.getDefault().register(this);
// Redraw UI
redraw();
}
public void redraw() {
uiTitleText.setText(issue.getTitle());
uiInfoText.setText(issue.getInfo());
uiDateText.setText(issue.getDate());
if(issue.hasPrice()) {
uiBuyIssueButton.setText(issue.getPrice());
}
if (issue.getSize() == 0) {
uiSizeText.setVisibility(View.GONE);
} else {
uiSizeText.setText(issue.getSizeMB() + " MB");
}
// Prepare actions
if (issue.isExtracted()) {
setUIState(UI_STATE_READY);
readable = true;
}else if(issue.getExtractJob() != null && !issue.getExtractJob().isCompleted()) {
setUIState(UI_STATE_EXTRACT);
readable = false;
}else if(issue.isDownloading()){
setUIState(UI_STATE_DOWNLOAD);
readable = false;
}else{
setUIState(UI_STATE_INITIAL);
readable = false;
}
requestLayout();
}
public Issue getIssue() {
return issue;
}
private void purchaseIssue() {
if (!issue.isPurchased()) {
final ActivityCheckout checkout = ((ShelfActivity) parentActivity).getShelfCheckout();
checkout.whenReady(new Checkout.ListenerAdapter() {
@Override
public void onReady(@NonNull BillingRequests requests) {
if(issue.getSku() != null) {
requests.purchase(issue.getSku(), Configuration.getUserId(), checkout.getPurchaseFlow());
BakerApplication.getInstance().getPluginManager().onIssuePurchaseClicked(issue);
}
}
});
}
}
private void downloadIssue() {
if (BakerApplication.getInstance().isNetworkConnected()) {
setUIState(UI_STATE_DOWNLOAD);
issue.startDownloadIssueJob();
BakerApplication.getInstance().getPluginManager().onIssueDownloadClicked(issue);
}else {
((ShelfActivity) this.parentActivity).openConnectionDialog();
}
}
/**
* Deletes and issue from the user device.
*/
private void archiveIssue() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(R.string.msg_confirmation)
.setMessage(R.string.msg_confirmation_delete_text)
.setIcon(android.R.drawable.ic_dialog_alert)
.setNegativeButton(R.string.msg_no, null)
.setPositiveButton(R.string.msg_yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Update UI
setUIState(UI_STATE_ARCHIVE);
// Create and trigger archive task
ArchiveIssueJob archiveIssueJob = new ArchiveIssueJob(issue);
BakerApplication.getInstance().getJobManager().addJobInBackground(archiveIssueJob);
BakerApplication.getInstance().getPluginManager().onIssueArchiveClicked(issue);
}
}).show();
}
/**
* Change the views to start reading the issue.
*/
private void readIssue() {
ParseBookJsonJob parseBookJsonJob = new ParseBookJsonJob(issue);
BakerApplication.getInstance().getJobManager().addJobInBackground(parseBookJsonJob);
BakerApplication.getInstance().getPluginManager().onIssueReadClicked(issue);
}
/**
* Start the unzipping task for an issue. Also handles the controls update.
*/
public void extractZip() {
setUIState(UI_STATE_EXTRACT);
issue.startExtractIssueJob();
}
private void setUIState(int uiState) {
switch (uiState) {
case UI_STATE_INITIAL:
uiReadyActionsContainer.setVisibility(View.GONE);
if(issue.hasPrice() && !issue.isPurchased()) {
uiPurchaseActionsContainer.setVisibility(View.VISIBLE);
uiIdleActionsContainer.setVisibility(View.GONE);
}else{
uiPurchaseActionsContainer.setVisibility(View.GONE);
uiIdleActionsContainer.setVisibility(View.VISIBLE);
}
uiProgressText.setVisibility(View.GONE);
uiProgressBarContainer.setVisibility(View.GONE);
uiProgressText.setText(null);
break;
case UI_STATE_DOWNLOAD:
uiIdleActionsContainer.setVisibility(View.GONE);
uiReadyActionsContainer.setVisibility(View.GONE);
uiPurchaseActionsContainer.setVisibility(View.GONE);
uiProgressText.setVisibility(View.VISIBLE);
uiProgressBarContainer.setVisibility(View.VISIBLE);
uiProgressText.setText(R.string.msg_issue_downloading);
break;
case UI_STATE_EXTRACT:
uiIdleActionsContainer.setVisibility(View.GONE);
uiReadyActionsContainer.setVisibility(View.GONE);
uiPurchaseActionsContainer.setVisibility(View.GONE);
uiProgressText.setVisibility(View.VISIBLE);
uiProgressBarContainer.setVisibility(View.VISIBLE);
uiProgressText.setText(R.string.msg_issue_extracting);
break;
case UI_STATE_READY:
uiIdleActionsContainer.setVisibility(View.GONE);
uiReadyActionsContainer.setVisibility(View.VISIBLE);
uiPurchaseActionsContainer.setVisibility(View.GONE);
uiProgressText.setVisibility(View.GONE);
uiProgressBarContainer.setVisibility(View.GONE);
uiProgressText.setText(null);
break;
case UI_STATE_ARCHIVE:
uiIdleActionsContainer.setVisibility(View.GONE);
uiReadyActionsContainer.setVisibility(View.GONE);
uiProgressText.setVisibility(View.VISIBLE);
uiProgressBarContainer.setVisibility(View.VISIBLE);
uiProgressText.setText(R.string.msg_issue_deleting);
break;
case UI_STATE_ERROR:
uiIdleActionsContainer.setVisibility(View.VISIBLE);
uiReadyActionsContainer.setVisibility(View.GONE);
uiPurchaseActionsContainer.setVisibility(View.GONE);
uiProgressText.setVisibility(View.VISIBLE);
uiProgressBarContainer.setVisibility(View.GONE);
break;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(ExtractIssueCompleteEvent event) {
if(event.getIssue() == issue) {
setUIState(UI_STATE_READY);
readable = true;
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(ExtractIssueErrorEvent event) {
if(event.getIssue() == issue) {
setUIState(UI_STATE_INITIAL);
readable = false;
Toast.makeText(getContext(), "Could not extract this issue.", Toast.LENGTH_LONG).show();
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(ExtractIssueProgressEvent event) {
if(event.getIssue() == issue) {
uiProgressText.setText(parentActivity.getString(R.string.msg_issue_extracting) + ": " + String.valueOf(event.getProgress()) + "%");
uiProgressBar.setProgress(event.getProgress());
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(DownloadIssueCompleteEvent event) {
if(event.getIssue() == issue) {
// Trigger unzipping
extractZip();
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(DownloadIssueErrorEvent event) {
if(event.getIssue() == issue) {
uiProgressText.setText(getContext().getString(R.string.err_download_task_io));
setUIState(UI_STATE_ERROR);
Toast.makeText(this.parentActivity, getContext().getString(R.string.err_download_task_io), Toast.LENGTH_LONG).show();
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(DownloadIssueProgressEvent event) {
if(event.getIssue() == issue) {
uiProgressText.setText(parentActivity.getString(R.string.msg_issue_downloading) + ": " + event.getProgress() + "% (" + String.valueOf(event.getBytesSoFar() / 1048576) + " MB)");
uiProgressBar.setProgress(event.getProgress());
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(IssueDataUpdatedEvent event) {
if(event.getIssue() == issue) {
redraw();
}
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(ArchiveIssueCompleteEvent event) {
if(event.getIssue() == issue) {
readable = false;
setUIState(UI_STATE_INITIAL);
}
}
}