package edu.grinnell.kdic;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.support.design.widget.NavigationView;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Stack;
import edu.grinnell.kdic.schedule.GetSchedule;
import edu.grinnell.kdic.schedule.Schedule;
import edu.grinnell.kdic.schedule.ScheduleFragment;
import edu.grinnell.kdic.visualizer.VisualizeFragment;
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
Toolbar navigationToolbar;
Toolbar playbackToolbar;
ImageView playPauseButton;
DrawerLayout drawerLayout;
NavigationView navigationView;
Stack<Integer> backStack;
VisualizeFragment visualizeFragment;
ScheduleFragment scheduleFragment;
FavoritesFragment favoritesFragment;
// for RadioService
RadioService radioService;
boolean boundToRadioService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Because we have bound to an explicit
// service that is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
RadioService.RadioBinder binder = (RadioService.RadioBinder) service;
radioService = binder.getService();
boundToRadioService = true;
// if the stream is playing, then stop the notification
if (radioService.isPlaying()) {
radioService.hideNotification();
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
}
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "onServiceDisconnected");
boundToRadioService = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the layout to use
setContentView(R.layout.activity_main);
setupNavigation(); // setup the nav drawer and navigation functionality
setupFragments(savedInstanceState);
setupPlaybackToolbar(); // setup the playback toolbar
// update the schedule if connected to internet
if (NetworkState.isOnline(this))
updateSchedule();
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart");
// bind to the radio service
Intent intent = new Intent(this, RadioService.class);
startService(intent);
bindService(intent, mConnection, BIND_AUTO_CREATE);
if (backStack.peek() != R.id.visualizer)
updateShowNamePlaybackToolbar();
}
@Override
protected void onResume() {
super.onResume();
// if the stream is playing, then stop the notification
if (boundToRadioService && radioService.isPlaying()) {
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
}
}
@Override
protected void onStop() {
super.onStop();
// if the stream is playing, then start the notification
if (boundToRadioService && radioService.isPlaying())
radioService.showNotification();
// unbind the radio service
unbindService(mConnection);
boundToRadioService = false;
}
private void setupPlaybackToolbar() {
playbackToolbar = (Toolbar) findViewById(R.id.playback_toolbar);
View.OnClickListener onToggleVisualizeFragment = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!radioService.isLoading()) {
if (backStack.peek() != R.id.visualizer) {
showVisualizeFragment();
backStack.add(R.id.visualizer);
} else {
hideVisualizeFragment();
backStack.pop();
}
updateNavigationView();
}
}
};
playbackToolbar.setNavigationOnClickListener(onToggleVisualizeFragment);
playbackToolbar.setOnClickListener(onToggleVisualizeFragment);
playPauseButton = (ImageView) findViewById(R.id.ib_play_pause);
playPauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (radioService.isPlaying()) {
// pause
radioService.pause();
// switch to play icon
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
} else {
// play
if (NetworkState.isOnline(MainActivity.this)) {
if (!radioService.isLoading()) {
if (radioService.isLoaded()) {
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
playPauseButton.clearAnimation();
} else {
playPauseButton.setImageResource(R.drawable.ic_loading_spinner);
// rotation to use for loading icon
RotateAnimation rotate;
// different center point for rotation if playPauseButton is in the
// center of the screen
if (backStack.peek() != R.id.visualizer)
rotate = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
else {
float shiftX = playbackToolbar.getWidth() / -2 + playPauseButton.getWidth();
float shiftY = playbackToolbar.getHeight() / 2;
rotate = new RotateAnimation(0, 360, shiftX, shiftY);
}
rotate.setDuration(1000);
rotate.setRepeatCount(Animation.INFINITE);
rotate.setInterpolator(new LinearInterpolator());
playPauseButton.startAnimation(rotate);
}
radioService.setRunOnStreamPrepared(new Runnable() {
@Override
public void run() {
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
playPauseButton.clearAnimation();
}
});
radioService.play();
}
} else {
showNoInternetDialog();
}
}
}
});
}
private void setupFragments(Bundle savedInstanceState) {
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
scheduleFragment = new ScheduleFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
scheduleFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment, scheduleFragment, ScheduleFragment.TAG)
.commit();
backStack.add(R.id.schedule);
SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFS, 0);
if (sharedPreferences.getBoolean(Constants.FIRST_RUN, true)) {
GetSchedule getSchedule = new GetSchedule(MainActivity.this, scheduleFragment);
getSchedule.execute();
sharedPreferences.edit().putBoolean(Constants.FIRST_RUN, false).apply();
}
visualizeFragment = new VisualizeFragment();
}
}
private void setupNavigation() {
// get toolbar and nav drawer
navigationToolbar = (Toolbar) findViewById(R.id.toolbar_main);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
// set toolbar as actionbar
setSupportActionBar(navigationToolbar);
// initialize navigation drawer
navigationToolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp);
navigationToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
// set up backstack
backStack = new Stack<>();
// set onclick listeners to navigation menu items
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
if (backStack.peek() != menuItem.getItemId()) {
if (backStack.peek() == R.id.visualizer) {
hideVisualizeFragment();
backStack.pop();
}
backStack.push(menuItem.getItemId());
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
switch (menuItem.getItemId()) {
case R.id.schedule:
ft.replace(R.id.fragment, scheduleFragment, ScheduleFragment.TAG)
.addToBackStack(null)
.commit();
break;
case R.id.visualizer:
showVisualizeFragment();
break;
case R.id.favorites:
ft.replace(R.id.fragment,
favoritesFragment == null ? new FavoritesFragment() : favoritesFragment,
FavoritesFragment.TAG)
.addToBackStack(null)
.commit();
break;
case R.id.blog:
ft.replace(R.id.fragment, new BlogWebViewFragment(), BlogWebViewFragment.TAG)
.addToBackStack(null)
.commit();
break;
case R.id.about:
ft.replace(R.id.fragment, new AboutFragment(), AboutFragment.TAG)
.addToBackStack(null)
.commit();
break;
default:
break;
}
}
// close the drawer after something is clicked
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
}
public void updateNavigationView() {
navigationView.setCheckedItem(backStack.peek());
}
public void hideVisualizeFragment() {
if (!radioService.isLoading()) {
// hide visualize fragment
playbackToolbar.setNavigationIcon(R.drawable.ic_keyboard_arrow_up_white_24dp);
updateShowNamePlaybackToolbar();
getSupportFragmentManager().popBackStack();
// move the play button to the right
final float shiftAmnt = (playbackToolbar.getWidth() - playPauseButton.getWidth()) / 2;
TranslateAnimation animation = new TranslateAnimation(0, shiftAmnt, 0, 0);
animation.setDuration(200);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.setFillAfter(false);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
playPauseButton.setTranslationX(0);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
playPauseButton.startAnimation(animation);
// move the info onto the screen
AlphaAnimation alphaAnimation = new AlphaAnimation(0f, 1f);
alphaAnimation.setDuration(200);
alphaAnimation.setStartOffset(100);
alphaAnimation.setFillAfter(true);
alphaAnimation.setInterpolator(new AccelerateInterpolator());
findViewById(R.id.ll_show_info).startAnimation(alphaAnimation);
}
}
public void showVisualizeFragment() {
if (!radioService.isLoading()) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_in_bottom, R.anim.fade_out, R.anim.fade_in, R.anim.slide_out_bottom)
.replace(R.id.fragment, visualizeFragment, VisualizeFragment.TAG)
.addToBackStack(null)
.commit();
((TextView) findViewById(R.id.tv_playback_show_name)).setText("");
((TextView) findViewById(R.id.tv_playback_show_time)).setText("");
playbackToolbar.setNavigationIcon(R.drawable.ic_keyboard_arrow_down_white_24dp);
// move the play button to the middle
final float shiftAmnt = (playbackToolbar.getWidth() - playPauseButton.getWidth()) / 2;
TranslateAnimation animation = new TranslateAnimation(shiftAmnt, 0, 0, 0);
animation.setDuration(200);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.setFillAfter(true);
playPauseButton.setTranslationX(-1 * shiftAmnt);
playPauseButton.startAnimation(animation);
// move the info off the screen
AlphaAnimation alphaAnimation = new AlphaAnimation(1f, 0f);
alphaAnimation.setDuration(300);
alphaAnimation.setStartOffset(100);
alphaAnimation.setFillAfter(true);
alphaAnimation.setInterpolator(new AccelerateInterpolator());
findViewById(R.id.ll_show_info).startAnimation(alphaAnimation);
}
}
/**
* Update the show name in the bottom playback toolbar to the current show
*/
public void updateShowNamePlaybackToolbar() {
TextView showName = (TextView) findViewById(R.id.tv_playback_show_name);
TextView showTime = (TextView) findViewById(R.id.tv_playback_show_time);
Show curShow = Schedule.getCurrentShow(this);
if (curShow == null) {
showName.setText("Auto Play");
showTime.setVisibility(View.GONE);
} else {
showName.setText(curShow.getTitle());
showTime.setText("Started at " + curShow.getTime());
showTime.setVisibility(View.VISIBLE);
}
}
/**
* Create and show an alert dialog warning about no internet connection
*/
public void showNoInternetDialog() {
new AlertDialog.Builder(this)
.setTitle("No Internet Connection")
.setMessage("Connect to the internet to play the live stream.")
.setPositiveButton("OK", null)
.setIcon(R.drawable.ic_warning_black_24dp)
.show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.update_schedule) {
updateSchedule();
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateSchedule() {
GetSchedule getSchedule = new GetSchedule(MainActivity.this, scheduleFragment);
getSchedule.execute();
}
@Override
public void onBackPressed() {
if (backStack.size() > 1) {
int menuId = backStack.pop();
updateNavigationView();
if (menuId == R.id.visualizer) {
hideVisualizeFragment();
return;
}
}
super.onBackPressed();
}
@Override
protected void onDestroy() {
Log.d(TAG, "MainActivity Destroyed.");
super.onDestroy();
}
}