package com.wigwamlabs.veckify; import android.app.LoaderManager; import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import com.commonsware.cwac.loaderex.SQLiteCursorLoader; import com.example.android.undobar.UndoBarController; import com.wigwamlabs.spotify.ImageProvider; import com.wigwamlabs.spotify.Player; import com.wigwamlabs.spotify.Playlist; import com.wigwamlabs.spotify.PlaylistContainer; import com.wigwamlabs.spotify.PlaylistProvider; import com.wigwamlabs.spotify.Session; import com.wigwamlabs.spotify.ui.SpotifyImageView; import com.wigwamlabs.spotify.ui.SpotifyPlayerActivity; import com.wigwamlabs.veckify.db.AlarmEntry; import com.wigwamlabs.veckify.db.AlarmsCursor; import java.util.Calendar; import static android.view.View.GONE; import static android.view.View.VISIBLE; public class MainActivity extends SpotifyPlayerActivity implements LoaderManager.LoaderCallbacks<Cursor>, AlarmAdapter.Callback, UndoBarController.UndoListener, TimeUpdater.Callback { private final Handler mHandler = new Handler(); private PlaylistContainer mPlaylistContainer; private AlarmUtils mAlarmUtils; private SwipeDismissListView mAlarmList; private AlarmAdapter mAlarmAdapter; private View mNowPlaying; private Integer mScrollToPositionOnLoad; private Long mScrollToIdOnLoad; private UndoBarController mUndoBarController; private TimeUpdater mTimeUpdater; private PlaylistProvider mPlaylistProvider; @Override public void onCreate(Bundle savedInstanceState) { Debug.logLifecycle("MainActivity.onCreate()"); super.onCreate(savedInstanceState); mAlarmUtils = new AlarmUtils(this); initUi(); mTimeUpdater = new TimeUpdater(mHandler, this); bindSpotifyService(); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { Debug.logLifecycle("MainActivity.onSaveInstanceState()"); super.onSaveInstanceState(outState); mUndoBarController.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { Debug.logLifecycle("MainActivity.onRestoreInstanceState()"); super.onRestoreInstanceState(savedInstanceState); mUndoBarController.onRestoreInstanceState(savedInstanceState); } @Override protected void onResume() { Debug.logLifecycle("MainActivity.onResume()"); super.onResume(); mTimeUpdater.start(); } @Override protected void onPause() { Debug.logLifecycle("MainActivity.onPause()"); super.onPause(); mTimeUpdater.stop(); } @Override protected void onDestroy() { Debug.logLifecycle("MainActivity.onDestroy()"); super.onDestroy(); if (mPlaylistProvider != null) { mPlaylistProvider.destroy(); mPlaylistProvider = null; } if (mPlaylistContainer != null) { mPlaylistContainer.destroy(); mPlaylistContainer = null; } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.addAlarm: onAddAlarm(); return true; case R.id.offlineSync: startActivity(new Intent(this, OfflinePlaylistsActivity.class)); return true; case R.id.settings: startActivity(new Intent(this, SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } private void initUi() { setContentView(R.layout.activity_main); // alarms getLoaderManager().initLoader(R.id.loaderAlarms, null, this); mAlarmAdapter = new AlarmAdapter(this, this); mAlarmAdapter.setEnablePlaylistPickers(mPlaylistContainer != null); mAlarmList = (SwipeDismissListView) findViewById(R.id.alarmList); mAlarmList.setAdapter(mAlarmAdapter); mAlarmList.setCallback(new SwipeDismissListView.Callback() { @Override public boolean canDismiss(int position) { return true; } @Override public void onDismiss(SwipeDismissListView swipeDismissListView, int[] reverseSortedPositions) { final long[] ids = new long[reverseSortedPositions.length]; for (int i = 0; i < ids.length; i++) { ids[i] = mAlarmAdapter.getItemId(reverseSortedPositions[i]); } onDeleteAlarms(ids); } }); // undo mUndoBarController = new UndoBarController(findViewById(R.id.undobar), this); // now playing mNowPlaying = findViewById(R.id.nowPlaying); mNowPlaying.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, NowPlayingActivity.class)); } }); setTrackImage((SpotifyImageView) findViewById(R.id.trackImage), ImageProvider.SIZE_NORMAL); setTrackArtists((TextView) findViewById(R.id.trackArtists)); setTrackName((TextView) findViewById(R.id.trackName)); setTrackProgress((ProgressBar) findViewById(R.id.trackProgress)); setResumeButton(findViewById(R.id.resumeButton)); setPauseButton(findViewById(R.id.pauseButton)); setNextButton(findViewById(R.id.nextButton)); } @Override protected void onSpotifySessionAttached(Session spotifySession) { super.onSpotifySessionAttached(spotifySession); setAutoLogin(true); mPlaylistProvider = new PlaylistProvider(spotifySession); mAlarmAdapter.setPlaylistProvider(mPlaylistProvider); } @Override public void onConnectionStateUpdated(int state) { super.onConnectionStateUpdated(state); if (state != Session.CONNECTION_STATE_LOGGED_OUT && mPlaylistContainer == null) { mPlaylistContainer = getSpotifySession().getPlaylistContainer(); mAlarmAdapter.setEnablePlaylistPickers(true); } } public PlaylistContainer getPlaylistContainer() { return mPlaylistContainer; } @Override public void onStateChanged(int state) { super.onStateChanged(state); final boolean showNowPlaying = (state == Player.STATE_PLAYING || state == Player.STATE_PAUSED_USER || state == Player.STATE_PAUSED_NOISY || state == Player.STATE_PAUSED_AUDIOFOCUS); mNowPlaying.setVisibility(showNowPlaying ? VISIBLE : GONE); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { switch (id) { case R.id.loaderAlarms: return AlarmsCursor.getAllAlarmsLoader(this, ((Application) getApplication()).getDb()); } return null; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { final AlarmsCursor alarm = (AlarmsCursor) data; mAlarmUtils.reschedule(this, alarm); mAlarmAdapter.changeCursor(alarm); if (mScrollToPositionOnLoad != null) { mAlarmList.smoothScrollToPosition(mScrollToPositionOnLoad.intValue()); mScrollToPositionOnLoad = null; } if (mScrollToIdOnLoad != null) { final long id = mScrollToIdOnLoad.longValue(); int pos = 0; for (boolean hasItem = alarm.moveToFirst(); hasItem; hasItem = alarm.moveToNext()) { if (id == alarm._id()) { mAlarmList.smoothScrollToPosition(pos); break; } pos++; } mScrollToIdOnLoad = null; } } @Override public void onLoaderReset(Loader<Cursor> loader) { mAlarmAdapter.changeCursor(null); } private SQLiteCursorLoader getAlarmLoader() { final Loader<Cursor> loader = getLoaderManager().getLoader(R.id.loaderAlarms); return (SQLiteCursorLoader) loader; } @Override public void onTimeUpdated(Calendar cal) { // time to alarm is updated mAlarmAdapter.notifyDataSetChanged(); } private void onAddAlarm() { final AlarmEntry entry = AlarmEntry.createNew(); entry.insert(getAlarmLoader()); mScrollToPositionOnLoad = mAlarmAdapter.getCount(); } private void onDeleteAlarms(long[] ids) { final AlarmEntry entry = new AlarmEntry(); entry.setDeleted(true); entry.update(getAlarmLoader(), ids); mAlarmAdapter.setItemsDeleted(ids); UndoAction undoAction = (UndoAction) mUndoBarController.getUndoToken(); if (undoAction == null) { undoAction = new UndoAction(ids); } else { undoAction.add(ids); } mUndoBarController.showUndoBar(false, getString(R.string.alarm_deleted, undoAction.ids.length), undoAction); } @Override public void onUndo(Parcelable token) { if (token == null) { return; } final UndoAction action = (UndoAction) token; final long[] ids = action.ids; final AlarmEntry entry = new AlarmEntry(); entry.setDeleted(false); entry.update(getAlarmLoader(), ids); mAlarmAdapter.setItemsUndeleted(ids); mScrollToIdOnLoad = ids[0]; } @Override public void onAlarmEntryChanged(long alarmId, AlarmEntry entry, boolean enableIfPossible) { if (enableIfPossible) { if (entry.hasPlaylist() && entry.getTime() != null) { entry.setEnabled(true); } } entry.update(getAlarmLoader(), alarmId); } @Override public void onPickTime(long alarmId, AlarmEntry entry) { final TimePickerDialogFragment fragment = TimePickerDialogFragment.create(alarmId, entry); fragment.show(getFragmentManager(), "time-picker"); } @Override public void onPickRepeatDays(long alarmId, AlarmEntry entry) { final RepeatDaysPickerFragment fragment = RepeatDaysPickerFragment.create(alarmId, entry); fragment.show(getFragmentManager(), "repeatdays-picker"); } @Override public void onPickPlaylist(long alarmId, AlarmEntry entry, String playlistLink) { final PlaylistPickerFragment fragment = PlaylistPickerFragment.create(alarmId, entry, playlistLink); fragment.show(getFragmentManager(), "playlist-picker"); } @Override public void onPickVolume(long alarmId, AlarmEntry entry) { final VolumePickerFragment fragment = VolumePickerFragment.create(alarmId, entry); fragment.show(getFragmentManager(), "volume-picker"); } @Override public void onSetTts(long alarmId, AlarmEntry entry) { final TtsSettingsFragment fragment = TtsSettingsFragment.create(alarmId, entry); fragment.show(getFragmentManager(), "tts-settings"); } @Override public boolean onDownloadPlaylist(String playlistLink) { final Playlist playlist = mPlaylistProvider.getPlaylist(playlistLink); if (playlist != null) { playlist.setOfflineMode(getSpotifySession(), true); return true; } return false; } private static class UndoAction implements Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public UndoAction createFromParcel(Parcel in) { return new UndoAction(in); } @Override public UndoAction[] newArray(int size) { return new UndoAction[size]; } }; long[] ids; public UndoAction(long[] ids) { this.ids = ids; } public UndoAction(Parcel in) { ids = new long[in.readInt()]; in.readLongArray(ids); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(ids.length); dest.writeLongArray(ids); } public void add(long[] newIds) { final long[] oldIds = ids; ids = new long[oldIds.length + newIds.length]; System.arraycopy(oldIds, 0, ids, 0, oldIds.length); System.arraycopy(newIds, 0, ids, oldIds.length, newIds.length); } } }