~cmiller/ubuntuone-android-music/experimental-flipping-ui

223 by sindre_mehus
Android: Nicer html in help.
1
/*
2
 This file is part of Subsonic.
3
4
 Subsonic is free software: you can redistribute it and/or modify
5
 it under the terms of the GNU General Public License as published by
6
 the Free Software Foundation, either version 3 of the License, or
7
 (at your option) any later version.
8
9
 Subsonic is distributed in the hope that it will be useful,
10
 but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 GNU General Public License for more details.
13
14
 You should have received a copy of the GNU General Public License
15
 along with Subsonic.  If not, see <http://www.gnu.org/licenses/>.
16
17
 Copyright 2009 (C) Sindre Mehus
18
 */
19
118 by sindre_mehus
Android: Changed package name.
20
package net.sourceforge.subsonic.androidapp.activity;
21
533 by Chad Miller
Use FrameLayout in landscape also.
22
import android.app.Activity;
417 by sindre_mehus
U1M: Authenication.
23
import android.app.AlertDialog;
533 by Chad Miller
Use FrameLayout in landscape also.
24
import android.content.Context;
417 by sindre_mehus
U1M: Authenication.
25
import android.content.DialogInterface;
118 by sindre_mehus
Android: Changed package name.
26
import android.content.Intent;
417 by sindre_mehus
U1M: Authenication.
27
import android.content.SharedPreferences;
28
import android.net.Uri;
418 by sindre_mehus
U1M: Authenication.
29
import android.os.Build;
118 by sindre_mehus
Android: Changed package name.
30
import android.os.Bundle;
494 by Chad Miller
Add debug menu support when /sdcard//subsonic/showdebugmenu file exists.
31
import android.os.Environment;
118 by sindre_mehus
Android: Changed package name.
32
import android.preference.PreferenceManager;
533 by Chad Miller
Use FrameLayout in landscape also.
33
import android.util.Log;
261 by sindre_mehus
Android: Refactor server selection.
34
import android.view.ContextMenu;
533 by Chad Miller
Use FrameLayout in landscape also.
35
import android.view.KeyEvent;
287 by sindre_mehus
Android: Main layout.
36
import android.view.LayoutInflater;
437.1.2 by Chad Miller
Declutter the screen. Exit and help buttons should be in the menu, not always visible in the top.
37
import android.view.Menu;
278 by sindre_mehus
Android: Created playlist + search tabs.
38
import android.view.MenuItem;
529 by Chad Miller
first of initial UI revolution
39
import android.view.MotionEvent;
118 by sindre_mehus
Android: Changed package name.
40
import android.view.View;
533 by Chad Miller
Use FrameLayout in landscape also.
41
import android.view.ViewGroup;
118 by sindre_mehus
Android: Changed package name.
42
import android.view.Window;
533 by Chad Miller
Use FrameLayout in landscape also.
43
import android.widget.AdapterView;
529 by Chad Miller
first of initial UI revolution
44
import android.widget.ArrayAdapter;
533 by Chad Miller
Use FrameLayout in landscape also.
45
import android.widget.ImageView;
287 by sindre_mehus
Android: Main layout.
46
import android.widget.ListView;
533 by Chad Miller
Use FrameLayout in landscape also.
47
import android.widget.ProgressBar;
48
import android.widget.SlidingDrawer;
223 by sindre_mehus
Android: Nicer html in help.
49
import android.widget.TextView;
529 by Chad Miller
first of initial UI revolution
50
import android.widget.ViewFlipper;
533 by Chad Miller
Use FrameLayout in landscape also.
51
import net.sourceforge.subsonic.androidapp.domain.Artist;
52
import net.sourceforge.subsonic.androidapp.domain.Indexes;
388 by sindre_mehus
Android: Minor bugfixes in offline mode.
53
import net.sourceforge.subsonic.androidapp.service.DownloadService;
168 by sindre_mehus
Android: Refactored big time.
54
import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
533 by Chad Miller
Use FrameLayout in landscape also.
55
import net.sourceforge.subsonic.androidapp.service.MusicService;
56
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
57
import net.sourceforge.subsonic.androidapp.util.ArtistAdapter;
58
import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
406.1.51 by sindre_mehus
Android: Update SackOfViewsAdapter, use MergeAdapter instead in MainActivity.
59
import net.sourceforge.subsonic.androidapp.util.Constants;
60
import net.sourceforge.subsonic.androidapp.util.MergeAdapter;
533 by Chad Miller
Use FrameLayout in landscape also.
61
import net.sourceforge.subsonic.androidapp.util.MainActivityBackgroundTask;
193 by sindre_mehus
Android: Improved offline mode.
62
import net.sourceforge.subsonic.androidapp.util.Util;
412 by sindre_mehus
U1M: Use proper import for R resource class.
63
import net.sourceforge.subsonic.u1m.R;
279 by sindre_mehus
Android: Button bar + theme.
64
519 by Chad Miller
Start adding analytics to Music app. I don't know how some of these traits will graph, so I'll revisit these later.
65
import net.sourceforge.subsonic.u1m.androidapp.Analytics;
66
import com.google.android.apps.analytics.GoogleAnalyticsTracker;
67
494 by Chad Miller
Add debug menu support when /sdcard//subsonic/showdebugmenu file exists.
68
import java.io.File;
414 by sindre_mehus
U1M: Hidden server settings.
69
import java.util.ArrayList;
279 by sindre_mehus
Android: Button bar + theme.
70
import java.util.Arrays;
533 by Chad Miller
Use FrameLayout in landscape also.
71
import java.util.LinkedList;
72
import java.util.List;
118 by sindre_mehus
Android: Changed package name.
73
529 by Chad Miller
first of initial UI revolution
74
public class MainActivity extends Activity implements View.OnTouchListener {
75
	private static final String TAG = MainActivity.class.getSimpleName();
76
77
	private long startupTime;
78
	private float beginTouchX = 0;
530 by Chad Miller
Add some data to test with. Open drawer.
79
	private float beginTouchY = 0;
529 by Chad Miller
first of initial UI revolution
80
	private ViewFlipper vf;
81
	private int vfArtistsChildIndex;
82
	private int vfSongsChildIndex;
535 by Chad Miller
Fix indentation.
83
	private boolean destroyed;
533 by Chad Miller
Use FrameLayout in landscape also.
84
85
	private ListView artistsListView;
537 by Chad Miller
Start to plug in the song list.
86
	private ListView songsListView;
529 by Chad Miller
first of initial UI revolution
87
531 by Chad Miller
Use a FrameLayout so the SlidingDrawer works.
88
	private TextView songsListTitle;
89
529 by Chad Miller
first of initial UI revolution
90
	/**
91
	 * Called when the activity is first created.
92
	 */
93
	@Override
94
	public void onCreate(Bundle savedInstanceState) {
95
		super.onCreate(savedInstanceState);
96
		setContentView(R.layout.new_main);
97
537 by Chad Miller
Start to plug in the song list.
98
		this.artistsListView = (ListView) findViewById(R.id.artists_list);
529 by Chad Miller
first of initial UI revolution
99
		vf = (ViewFlipper) findViewById(R.id.top_flipper);
100
101
		if (vf == null) {
102
			Log.e(TAG, "no vf");
103
		} else {
104
			vfArtistsChildIndex = vf.indexOfChild(findViewById(R.id.top_flipper_child_artists));
105
			vfSongsChildIndex = vf.indexOfChild(findViewById(R.id.top_flipper_child_songs));
106
			vf.setOnTouchListener(this);
107
		}
108
537 by Chad Miller
Start to plug in the song list.
109
		songsListTitle = new TextView(this);
110
		//songsListTitle.setHint("unset");  // FIXME string resource
111
		this.songsListView = (ListView) findViewById(R.id.songs_grouped_by_albums_list);
112
		//this.songsListView.addHeaderView(songsListTitle);
113
		this.songsListView.setFastScrollEnabled(true);
114
		this.songsListView.setOnTouchListener(this);
115
533 by Chad Miller
Use FrameLayout in landscape also.
116
		final TextView artistsListTitle = new TextView(this);
537 by Chad Miller
Start to plug in the song list.
117
		this.artistsListView = (ListView) findViewById(R.id.artists_list);
118
		artistsListTitle.setText("Artists");  // FIXME string resource
119
		this.artistsListView.addHeaderView(artistsListTitle);
120
		this.artistsListView.setFastScrollEnabled(true);
121
		this.artistsListView.setOnTouchListener(this);
122
		this.artistsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
531 by Chad Miller
Use a FrameLayout so the SlidingDrawer works.
123
			@Override
533 by Chad Miller
Use FrameLayout in landscape also.
124
			public void onItemClick(AdapterView parent, View view, int position, long id) {
537 by Chad Miller
Start to plug in the song list.
125
				final Artist pickedArtist = (Artist) parent.getItemAtPosition(position);
126
				MainActivity.this.songsListTitle.setText(pickedArtist.getName());
531 by Chad Miller
Use a FrameLayout so the SlidingDrawer works.
127
				MainActivity.this.flipToSongs();
537 by Chad Miller
Start to plug in the song list.
128
				loadSongs(MainActivity.this.songsListView, pickedArtist.getId());
531 by Chad Miller
Use a FrameLayout so the SlidingDrawer works.
129
			}
130
		});
537 by Chad Miller
Start to plug in the song list.
131
		loadArtists(this.artistsListView);
530 by Chad Miller
Add some data to test with. Open drawer.
132
533 by Chad Miller
Use FrameLayout in landscape also.
133
		final SlidingDrawer playQueueSlidingDrawer = (SlidingDrawer) findViewById(R.id.play_queue_drawer);
529 by Chad Miller
first of initial UI revolution
134
135
		super.onCreate(savedInstanceState);
136
	}
137
138
	@Override
139
	public boolean onKeyDown(int keyCode, KeyEvent event)  {
140
		final int currentFlipperPosition;
141
		if (vf != null) {
142
			currentFlipperPosition = vf.getDisplayedChild(); 
143
		} else {
144
			currentFlipperPosition = -1; 
145
		}
146
		if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
147
			if ((vf != null) && (currentFlipperPosition != vfArtistsChildIndex)) {
148
				flipToArtists();
149
				return true;
150
			}
151
		}
152
		if (keyCode == KeyEvent.KEYCODE_SEARCH) {
153
			exposeSearchBar();
154
			if ((vf != null) && (currentFlipperPosition != vfSongsChildIndex)) {
155
				flipToSongs();
156
			}
157
			return true;
158
		}
159
		return super.onKeyDown(keyCode, event);
160
	}
161
537 by Chad Miller
Start to plug in the song list.
162
	private void loadSongs(ListView songsListView, String artistId) {
163
		Log.v(TAG, String.format("loadSongs(%s, %s)", songsListView, artistId));
164
	}
533 by Chad Miller
Use FrameLayout in landscape also.
165
166
	private void loadArtists(ListView artistList) {
167
		final List<Artist> artists = new LinkedList<Artist>();
168
		artistList.setAdapter(new ArtistAdapter(this, artists));
169
170
		final MusicService musicService = MusicServiceFactory.getMusicService(MainActivity.this);
171
		Indexes cacheResult = null;
172
		try {
173
			cacheResult =  musicService.getFastIndexes(MainActivity.this);
174
		} catch (Exception ex) {
175
			Log.d(TAG, "Loading cache for view adapter failed", ex);
176
		}
177
178
		final long lastModified;
179
		if (cacheResult != null) {
180
			artists.addAll(cacheResult.getShortcuts());
181
			artists.addAll(cacheResult.getArtists());
182
			lastModified = cacheResult.getLastModified();
183
		} else {
184
			lastModified = 0L;
185
			Log.d(TAG, "There is no usable cache of artists.");
186
		}
187
188
		BackgroundTask<Indexes> task = new MainActivityBackgroundTask<Indexes>(this) {
189
			@Override
190
			protected Indexes doInBackground() throws Throwable {
191
				boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
192
				return musicService.getIndexes(refresh, MainActivity.this, this, lastModified);
193
			}
194
195
			@Override
196
			protected void done(Indexes freshResult) {
197
				artists.clear();  // !?
198
				if (freshResult != null) {
199
					// A Set would be so much better.  TODO
200
					artists.addAll(freshResult.getShortcuts());
201
					artists.addAll(freshResult.getArtists());
202
				} else {
203
					Log.i(TAG, "No fresh artists to update view with.");
204
				}
205
			}
206
		};
207
		task.execute();
208
	}
209
210
	public void setProgressVisible(boolean visible) {
211
		View view = findViewById(R.id.tab_progress);
212
		if (view != null) {
213
			view.setVisibility(visible ? View.VISIBLE : View.GONE);
214
		}
215
216
		if (! visible) {
217
			updateProgress(null);
218
		}
219
	}
220
221
	public void updateProgress(String message) {
222
		ImageView refreshIcon = (ImageView) findViewById(R.id.refresh_icon);
223
		ProgressBar progressBar = (ProgressBar) findViewById(R.id.loading_progress);
224
		TextView headerDescriptionView = (TextView) findViewById(R.id.header_description);
225
226
		if (headerDescriptionView == null) {
227
			// Some screens do not have headers for the progress or state or verb for reload.
228
			return;
229
		}
230
231
		if (message != null) {
232
			headerDescriptionView.setText(message);
233
			if (refreshIcon != null) { refreshIcon.setVisibility(View.GONE); }
234
			if (progressBar != null) { progressBar.setVisibility(View.VISIBLE); }
235
		} else {
236
			headerDescriptionView.setText(getResources().getString(R.string.select_artist_refresh));
237
			if (refreshIcon != null) { refreshIcon.setVisibility(View.VISIBLE); }
238
			if (progressBar != null) { progressBar.setVisibility(View.GONE); }
239
		}
240
	}
241
242
	public boolean isDestroyed() {
243
		return destroyed;
244
	}
245
246
	@Override
247
	protected void onDestroy() {
248
		super.onDestroy();
249
//		if (this.tracker != null) {
250
//			this.tracker.dispatch();
251
//			this.tracker.stop();
252
//		}
253
		destroyed = true;
254
	}
255
529 by Chad Miller
first of initial UI revolution
256
	void exposeSearchBar() { }
257
258
	@Override
259
	public boolean onTouch(View view, MotionEvent motion) {
530 by Chad Miller
Add some data to test with. Open drawer.
260
		if (vf == null) {
261
			return false;
262
		}
529 by Chad Miller
first of initial UI revolution
263
		final int currentFlipperPosition = vf.getDisplayedChild(); 
264
		final int flipperPositionCount = vf.getChildCount(); 
265
		switch (motion.getAction()) {
266
			case MotionEvent.ACTION_DOWN:
267
				{
268
					beginTouchX = motion.getX();
530 by Chad Miller
Add some data to test with. Open drawer.
269
					beginTouchY = motion.getY();
529 by Chad Miller
first of initial UI revolution
270
					return true;
271
				}
272
			case MotionEvent.ACTION_UP:
273
				{
530 by Chad Miller
Add some data to test with. Open drawer.
274
					final float nowTouchX = motion.getX();
275
					final float nowTouchY = motion.getY();
276
					final float deltaX = nowTouchX - beginTouchX;
277
					final float deltaY = nowTouchY - beginTouchY;
278
					if (Math.abs(deltaY) > Math.abs(deltaX)) {
279
						// More up/down distance than right/left distance.
280
						return false;
281
					}
537 by Chad Miller
Start to plug in the song list.
282
					//Log.d(TAG, "touch delta X is " + deltaX);
530 by Chad Miller
Add some data to test with. Open drawer.
283
					if (Math.abs(deltaX) < 40) { // TODO What threshold?
284
						return false;
285
					}
529 by Chad Miller
first of initial UI revolution
286
					if (nowTouchX > beginTouchX) {
287
						if (currentFlipperPosition != vfArtistsChildIndex) {
288
							flipToArtists();
530 by Chad Miller
Add some data to test with. Open drawer.
289
							return true;
529 by Chad Miller
first of initial UI revolution
290
						}
291
					}
292
					if (nowTouchX < beginTouchX) {
293
						if (currentFlipperPosition != vfSongsChildIndex) {
294
							flipToSongs();
530 by Chad Miller
Add some data to test with. Open drawer.
295
							return true;
529 by Chad Miller
first of initial UI revolution
296
						}
297
					} 
298
				}
299
		}
300
		return false;
301
	}
302
303
	void flipToDestination(int targetView) {
537 by Chad Miller
Start to plug in the song list.
304
		//Log.d(TAG, "at pos " + vf.getDisplayedChild() + "and want pos " + targetView);
529 by Chad Miller
first of initial UI revolution
305
		while (vf.getDisplayedChild() > targetView) {
306
			vf.setInAnimation(MainActivity.this, R.anim.transition_in_right);
307
			vf.setOutAnimation(MainActivity.this, R.anim.transition_out_right);
308
			vf.showPrevious();
309
		}
310
		while (vf.getDisplayedChild() < targetView) {
311
			vf.setInAnimation(MainActivity.this, R.anim.transition_in_left);
312
			vf.setOutAnimation(MainActivity.this, R.anim.transition_out_left);
313
			vf.showNext();
314
		}
315
	}
316
317
	void flipToArtists() {
318
		flipToDestination(vfArtistsChildIndex);
319
	}
320
321
	void flipToSongs() {
322
		flipToDestination(vfSongsChildIndex);
323
	}
324
442 by Chad Miller
Bump version for official release.
325
}