package org.sagemath.droid.activities;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.PopupMenu;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ProgressBar;
import android.widget.ToggleButton;
import com.github.johnpersano.supertoasts.SuperCardToast;
import com.github.johnpersano.supertoasts.SuperToast;
import com.squareup.otto.Subscribe;
import org.sagemath.droid.R;
import org.sagemath.droid.constants.StringConstants;
import org.sagemath.droid.database.SageSQLiteOpenHelper;
import org.sagemath.droid.dialogs.DeleteCellDialogFragment;
import org.sagemath.droid.dialogs.InsertDialogFragment;
import org.sagemath.droid.dialogs.InsertSpinnerDialogFragment;
import org.sagemath.droid.dialogs.ShareDialogFragment;
import org.sagemath.droid.events.*;
import org.sagemath.droid.fragments.AsyncTaskFragment;
import org.sagemath.droid.fragments.CellGroupsFragment;
import org.sagemath.droid.fragments.CodeEditorFragment;
import org.sagemath.droid.fragments.OutputViewFragment;
import org.sagemath.droid.models.database.Cell;
import org.sagemath.droid.models.database.Insert;
import org.sagemath.droid.models.gson.BaseReply;
import org.sagemath.droid.utils.BusProvider;
import org.sagemath.droid.utils.ToastUtils;
/**
* All calculations are performed and displayed here
*
* @author vbraun
* @author Rasmi.Elasmar
* @author Ralf.Stephan
* @author Nikhil Peter Raj
*/
public class SageActivity
extends
ActionBarActivity
implements
DeleteCellDialogFragment.OnDeleteListener,
ToggleButton.OnCheckedChangeListener,
AsyncTaskFragment.ServerCallbacks
, ShareDialogFragment.OnRequestOutputListener
, PopupMenu.OnMenuItemClickListener
, InsertSpinnerDialogFragment.OnInsertSelectedListener {
private static final String TAG = "SageDroid:SageActivity";
private static final String DIALOG_SHARE = "shareDialog";
private static final String FLAG_SERVER_STATE = "serverState";
private static final String ARG_ADD_INSERT = "newInsert";
private static final String ARG_PUT_INSERT = "addInsert";
private static final String TASK_FRAGMENT_TAG = "taskFragment";
private ProgressBar cellProgressBar;
private SuperCardToast toast;
private Drawable playIcon, stopIcon;
private Drawable shareIcon, shareEnableIcon;
private CodeEditorFragment codeEditorFragment;
private OutputViewFragment outputViewFragment;
private AsyncTaskFragment taskFragment;
private View dividerView;
private SageSQLiteOpenHelper helper;
private String permalinkURL = null;
private boolean isServerRunning = false;
private boolean isShareAvailable = false;
private boolean isPlayground = false;
private Cell cell;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
helper = SageSQLiteOpenHelper.getInstance(this);
BusProvider.getInstance().register(this);
setContentView(R.layout.activity_sage);
cellProgressBar = (ProgressBar) findViewById(R.id.cell_progress);
cellProgressBar.setVisibility(View.INVISIBLE);
dividerView = findViewById(R.id.dividerView);
codeEditorFragment = (CodeEditorFragment) getSupportFragmentManager()
.findFragmentById(R.id.codeFragment);
outputViewFragment = (OutputViewFragment) getSupportFragmentManager()
.findFragmentById(R.id.outputFragment);
codeEditorFragment.getCodeViewToggleButton().setOnCheckedChangeListener(this);
outputViewFragment.getOutputViewToggleButton().setOnCheckedChangeListener(this);
if (getSupportFragmentManager().findFragmentByTag(TASK_FRAGMENT_TAG) == null) {
taskFragment = AsyncTaskFragment.getInstance();
getSupportFragmentManager()
.beginTransaction()
.add(taskFragment, TASK_FRAGMENT_TAG)
.commit();
} else {
taskFragment = (AsyncTaskFragment) getSupportFragmentManager().findFragmentByTag(TASK_FRAGMENT_TAG);
}
Intent intent = getIntent();
if (intent.hasExtra(CellGroupsFragment.KEY_GROUP_PLAYGROUND)) {
//Playground setup
setTitle(getString(R.string.group_playground));
isPlayground = true;
} else if (intent.hasExtra(StringConstants.ID)) {
Long cellID = intent.getLongExtra(StringConstants.ID, -1);
if (cellID != -1) {
cell = helper.getCellbyID(cellID);
codeEditorFragment.setCell(cell);
outputViewFragment.setCell(cell);
Log.i(TAG, "Got cell " + cell.toString());
}
setTitle(cell.getTitle());
}
}
@Override
public void onReply(BaseReply reply) {
BusProvider.getInstance().post(new ReplyEvent(reply));
}
@Override
public void onComputationFinished() {
hideProgress();
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch (buttonView.getId()) {
case R.id.codeViewStateToggleButton:
if (isChecked)
performFragmentResize(R.id.codeFragment, R.id.outputFragment);
else
performFragmentRestore();
break;
case R.id.outputViewStateToggleButton:
if (isChecked)
performFragmentResize(R.id.outputFragment, R.id.codeFragment);
else
performFragmentRestore();
break;
}
}
private void performFragmentResize(int expand, int collapse) {
dividerView.setVisibility(View.GONE);
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction()
.hide(manager.findFragmentById(collapse))
.show(manager.findFragmentById(expand))
.commit();
}
private void performFragmentRestore() {
dividerView.setVisibility(View.VISIBLE);
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction()
.show(manager.findFragmentById(R.id.codeFragment))
.show(manager.findFragmentById(R.id.outputFragment))
.commit();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem shareItem = menu.findItem(R.id.menu_share);
MenuItem runStateItem = menu.findItem(R.id.menu_run);
MenuItem saveItem = menu.findItem(R.id.menu_save);
if (playIcon == null) {
//Cache to avoid overhead
playIcon = getResources().getDrawable(R.drawable.ic_action_av_play);
stopIcon = getResources().getDrawable(R.drawable.ic_action_av_stop);
shareIcon = getResources().getDrawable(R.drawable.ic_action_social_share);
shareEnableIcon = getResources().getDrawable(R.drawable.ic_action_social_share_enabled);
}
if (isPlayground) {
saveItem.setEnabled(false);
}
if (isServerRunning) {
runStateItem.setIcon(stopIcon);
} else {
runStateItem.setIcon(playIcon);
}
if (isShareAvailable && !isServerRunning) {
shareItem.setIcon(shareEnableIcon);
} else {
shareItem.setIcon(shareIcon);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu_activity_sage, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_run:
startExecution();
return true;
case R.id.menu_insert:
View popUpView = findViewById(R.id.menu_insert);
showPopup(popUpView);
return true;
case R.id.menu_save:
codeEditorFragment.saveCurrentInput();
return true;
case R.id.menu_share:
shareClicked();
return true;
case R.id.menu_help:
startActivity(new Intent(this, HelpActivity.class));
return true;
case R.id.menu_settings:
startActivity(new Intent(this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
public void showPopup(View v) {
PopupMenu popupMenu = new PopupMenu(this, v);
MenuInflater menuInflater = popupMenu.getMenuInflater();
menuInflater.inflate(R.menu.menu_insert_popup, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(this);
popupMenu.show();
}
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.menu_insert_spinner:
InsertSpinnerDialogFragment insertDialog = InsertSpinnerDialogFragment.newInstance();
insertDialog.show(getSupportFragmentManager(), ARG_PUT_INSERT);
insertDialog.setOnInsertSelectedListener(this);
break;
case R.id.menu_add_insert:
InsertDialogFragment dialog = InsertDialogFragment.newInstance(null);
dialog.show(getSupportFragmentManager(), ARG_ADD_INSERT);
break;
case R.id.menu_manage_insert:
startActivity(new Intent(this, ManageInsertActivity.class));
break;
}
return true;
}
@Override
public void onInsertSelected(Insert insert) {
codeEditorFragment.getCodeView().paste(insert.getInsertText());
}
@Override
public void onDelete() {
finish();
}
@Override
public void onRequestOutput() {
Log.i(TAG, "Output Requested");
outputViewFragment.saveOutputToImage();
}
@SuppressWarnings("unused")
@Subscribe
public void onRun(CodeReceivedEvent event) {
if (event.isForRun()) {
Log.i(TAG, "Received Query: " + event.getReceivedCode());
String query = event.getReceivedCode();
taskFragment.query(query);
}
}
private void shareClicked() {
if (!isShareAvailable && !isServerRunning) {
ToastUtils.getAlertToast(this, R.string.toast_share_unavailable, SuperToast.Duration.SHORT).show();
} else if (isServerRunning) {
ToastUtils.getAlertToast(this, R.string.toast_share_server_running, SuperToast.Duration.SHORT).show();
} else {
ShareDialogFragment shareDialogFragment = ShareDialogFragment.getInstance(permalinkURL);
shareDialogFragment.show(getSupportFragmentManager(), DIALOG_SHARE);
}
}
private void startExecution() {
if (isServerRunning) {
//Computation already running, stop
cancelComputation();
} else {
//Check for Network Connection
if (!isConnected()) {
ToastUtils.getAlertToast(this, R.string.toast_network_error, SuperToast.Duration.MEDIUM).show();
} else {
isShareAvailable = false;
isServerRunning = false;
permalinkURL = null;
ActivityCompat.invalidateOptionsMenu(this);
outputViewFragment.getOutputView().clear();
codeEditorFragment.getCodeView().getEditorText(true);
}
}
}
private void cancelComputation() {
isShareAvailable = false;
ActivityCompat.invalidateOptionsMenu(this);
hideProgress();
outputViewFragment.getOutputView().clear();
taskFragment.cancel();
}
private boolean isConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
@SuppressWarnings("unused")
@Subscribe
public void onShareEvent(ShareAvailableEvent event) {
isShareAvailable = true;
permalinkURL = event.getShareURL();
ActivityCompat.invalidateOptionsMenu(this);
}
@SuppressWarnings("unused")
@Subscribe
public void onInteractFinished(InteractFinishEvent event) {
hideProgress();
}
@SuppressWarnings("unused")
@Subscribe
public void onInteractDisconnected(ServerDisconnectEvent event) {
Log.i(TAG, "Interact Disconnected, Showing Message");
//Hide Progress Bar, if it is showing
hideProgress();
//Prepare a Toast
toast = new SuperCardToast((SageActivity.this));
toast.setBackground(SuperToast.Background.RED);
toast.setTextColor(Color.BLACK);
toast.setDuration(3000);
toast.setIcon(android.R.drawable.ic_dialog_alert, SuperToast.IconPosition.LEFT);
toast.setSwipeToDismiss(true);
switch (event.getDisconnectType()) {
case DISCONNECT_INTERACT:
runOnUiThread(new Runnable() {
@Override
public void run() {
toast.setText(getString(R.string.toast_error_interact_timeout));
toast.show();
}
});
break;
case DISCONNECT_HTTP_ERROR:
runOnUiThread(new Runnable() {
@Override
public void run() {
toast.setText(getString(R.string.toast_error_websocket_disconnected));
toast.show();
}
});
break;
case DISCONNECT_TIMEOUT:
runOnUiThread(new Runnable() {
@Override
public void run() {
toast.setText(getString(R.string.toast_error_timeout));
toast.show();
}
});
}
}
@Override
protected void onResume() {
super.onResume();
BusProvider.getInstance().register(this);
}
@Override
protected void onPause() {
super.onPause();
BusProvider.getInstance().unregister(this);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(FLAG_SERVER_STATE, isServerRunning);
}
@Override
public void onBackPressed() {
if(taskFragment!=null){
taskFragment.closeWebSockets();
}
super.onBackPressed();
}
public void showProgress() {
if (!cellProgressBar.isShown()) {
cellProgressBar.setVisibility(View.VISIBLE);
isServerRunning = true;
ActivityCompat.invalidateOptionsMenu(this);
}
}
public void hideProgress() {
if (cellProgressBar.isShown()) {
cellProgressBar.setVisibility(View.INVISIBLE);
isServerRunning = false;
ActivityCompat.invalidateOptionsMenu(this);
}
}
@SuppressWarnings("unused")
@Subscribe
public void onProgressUpdate(ProgressEvent progressEvent) {
Log.i(TAG, "Received Progress Update: " + progressEvent.getProgressState());
if (progressEvent.getProgressState().equals(StringConstants.ARG_PROGRESS_START)) {
showProgress();
} else if (progressEvent.getProgressState().equals(StringConstants.ARG_PROGRESS_END)) {
hideProgress();
}
}
}