Manage orientation changes better (restore status text on thawing).
[bliper.git] / src / pl / blip / divide / bliper / Dashboard.java
blobe4a4546e34c8081e8b3495e2b359df05a42774e1
1 package pl.blip.divide.bliper;
3 import java.util.concurrent.Executors;
4 import java.util.concurrent.ScheduledExecutorService;
5 import java.util.concurrent.TimeUnit;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
9 import pl.blip.divide.bliper.DashboardView.DashboardAdapter;
10 import android.app.Activity;
11 import android.content.AsyncQueryHandler;
12 import android.content.ContentValues;
13 import android.content.Intent;
14 import android.database.Cursor;
15 import android.net.Uri;
16 import android.os.Bundle;
17 import android.view.KeyEvent;
18 import android.view.View;
19 import android.view.View.OnClickListener;
20 import android.view.View.OnFocusChangeListener;
21 import android.widget.AdapterView;
22 import android.widget.Button;
23 import android.widget.EditText;
24 import android.widget.ImageView;
25 import android.widget.TextView;
26 import android.widget.Toast;
27 import android.widget.AdapterView.OnItemClickListener;
28 import android.widget.TextView.OnEditorActionListener;
30 public class Dashboard extends Activity {
31 public class SendListener implements OnClickListener, OnEditorActionListener {
32 public void onClick(View v) {
33 doSend();
36 private void doSend() {
37 if (newStatus == null)
38 return;
39 newStatus = insertingStatus = myStatusView.getText().toString();
41 final ContentValues cv = new ContentValues();
42 cv.put("update[body]", newStatus);
43 myselfHandler.startInsert(0, null, Blip.Updates.CONTENT_URI, cv);
46 @Override
47 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
48 if (event == null || event.getAction() != KeyEvent.ACTION_UP)
49 return true;
50 doSend();
51 return true;
55 private ImageView myAvatarView;
57 private String currentStatus = null;
58 private String newStatus = null;
59 private String insertingStatus = null;
61 private class MyselfHandler extends AsyncQueryHandler {
62 private final String[] PROJECTION = { "current_status/body", "avatar/url_50" };
63 private final int BODY_COLUMN = 0, AVATAR_COLUMN = 1;
64 private Uri uri;
66 public MyselfHandler(String login) {
67 super(getContentResolver());
68 this.uri = Uri.withAppendedPath(Blip.Users.CONTENT_URI, login);
71 private void startQuery() {
72 startQuery(0, null, uri, PROJECTION, null, null, null);
75 @Override
76 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
77 super.onQueryComplete(token, cookie, cursor);
79 if (cursor == null || !cursor.moveToFirst()) {
80 if (!initialized) {
81 Toast.makeText(Dashboard.this, R.string.connection_unsuccessful, Toast.LENGTH_LONG).show();
82 finish();
84 return;
87 if (!initialized)
88 finishInitializing();
90 currentStatus = cursor.getString(BODY_COLUMN);
92 if (!myStatusView.hasFocus() && newStatus == null)
93 myStatusView.setText(currentStatus);
95 if (myAvatarView != null)
96 myAvatarView.setImageURI(Uri.withAppendedPath(Blip.CONTENT_URI, cursor.getString(AVATAR_COLUMN)));
99 @Override
100 protected void onInsertComplete(int token, Object cookie, Uri uri) {
101 super.onInsertComplete(token, cookie, uri);
103 if (uri != null) {
104 if (!insertingStatus.matches("^>>?.*:.*"))
105 currentStatus = insertingStatus;
106 newStatus = null;
107 updateMyStatus(true);
108 updateMyStatus(myStatusView.hasFocus());
110 if (updatesView != null)
111 updatesView.updateNow();
116 private String login;
117 private boolean initialized = false;
118 private EditText myStatusView;
119 private MyselfHandler myselfHandler;
120 private ScheduledExecutorService executor;
121 private DashboardView updatesView;
122 private OnFocusChangeListener myStatusViewFocusWatcher = new OnFocusChangeListener() {
123 @Override
124 public void onFocusChange(View v, boolean hasFocus) {
125 updateMyStatus(hasFocus);
129 private Button sendButton;
131 private SendListener sendListener = new SendListener();
133 @Override
134 protected void onCreate(Bundle savedInstanceState) {
135 super.onCreate(savedInstanceState);
137 login = Blip.getUsername(this);
139 if (login == null) {
140 Intent i = new Intent(this, LoginActivity.class);
141 startActivity(i);
142 finish();
143 return;
146 myselfHandler = new MyselfHandler(login);
147 myselfHandler.startQuery();
149 setContentView(R.layout.dashboard);
150 myStatusView = (EditText) findViewById(R.id.status);
153 @Override
154 protected void onRestoreInstanceState(Bundle savedInstanceState) {
155 super.onRestoreInstanceState(savedInstanceState);
157 // in case we were just thawed by Android, retrieve the status
158 final String status = myStatusView.getText().toString();
159 if (status.length() > 0)
160 newStatus = status;
163 public void updateMyStatus(boolean hasFocus) {
164 if (hasFocus) {
165 if (newStatus == null) {
166 newStatus = "";
167 myStatusView.setText(newStatus);
169 myStatusView.setBackgroundResource(android.R.drawable.edit_text);
170 myStatusView.setTextColor(getResources().getColorStateList(android.R.color.primary_text_light));
171 } else {
172 newStatus = myStatusView.getText().toString();
173 if (newStatus == null || newStatus.length() == 0) {
174 newStatus = null;
175 myStatusView.setText(currentStatus);
176 myStatusView.setBackgroundResource(R.drawable.textfield_default_dormant);
177 myStatusView.setTextColor(getResources().getColorStateList(R.drawable.custom_status_textfield_color));
181 // TODO make it extract values from XML or whatever
182 myStatusView.setPadding(5, 2, 37, 5);
185 public void finishInitializing() {
186 setTitle(R.string.dashboard);
188 myAvatarView = (ImageView) findViewById(R.id.avatar);
189 updatesView = (DashboardView) findViewById(R.id.updates);
190 sendButton = (Button) findViewById(R.id.send);
192 myStatusView.setOnFocusChangeListener(myStatusViewFocusWatcher);
193 myStatusView.setOnEditorActionListener(sendListener);
195 updatesView.bindDashboard();
196 updatesView.startUpdating();
197 updatesView.setOnItemClickListener(new OnItemClickListener() {
198 @Override
199 public void onItemClick(AdapterView<?> view, View itemView, int position, long id) {
200 tryToQuote(position);
204 sendButton.setOnClickListener(sendListener);
205 sendButton.requestFocus();
207 initialized = true;
210 protected void tryToQuote(int position) {
211 Cursor c = (Cursor) updatesView.getAdapter().getItem(position);
212 final String type = c.getString(DashboardAdapter.TYPE_COLUMN);
213 String user = c.getString(DashboardAdapter.AUTHOR_COLUMN);
214 if (user.equals(login)) {
215 final String recipient = c.getString(DashboardAdapter.RECIPIENT_COLUMN);
216 if (recipient != null)
217 user = recipient;
218 else
219 return;
222 final StringBuilder messageBuilder = new StringBuilder();
223 if (type.equals(Blip.PRIVATE_MESSAGE_TYPE))
224 messageBuilder.append(">>" + user + ": ");
225 else
226 messageBuilder.append(">" + user + ": ");
228 if (newStatus != null) {
229 newStatus = myStatusView.getText().toString();
230 Matcher m = Pattern.compile("^>>?.*?: *(.*)$").matcher(newStatus);
231 if (m.matches())
232 messageBuilder.append(m.group(1));
235 myStatusView.requestFocus();
236 newStatus = messageBuilder.toString();
237 myStatusView.setText(newStatus);
238 myStatusView.setSelection(newStatus.length());
241 private void scheduleQuerying() {
242 executor = Executors.newSingleThreadScheduledExecutor();
243 Runnable requeryMyselfCommand = new Runnable() {
244 @Override
245 public void run() {
246 myselfHandler.startQuery();
249 executor.scheduleAtFixedRate(requeryMyselfCommand, 20, 20, TimeUnit.SECONDS);
252 @Override
253 protected void onPause() {
254 super.onPause();
255 MessagePoller.startPolling(this);
258 @Override
259 protected void onResume() {
260 super.onResume();
261 MessagePoller.stopPolling(this);
264 @Override
265 protected void onStop() {
266 super.onStop();
267 executor.shutdownNow();
268 if (updatesView != null)
269 updatesView.stopUpdating();
272 @Override
273 protected void onStart() {
274 super.onStart();
276 myselfHandler.startQuery();
277 scheduleQuerying();
279 if (updatesView != null)
280 updatesView.startUpdating();
283 @Override
284 public void onUserInteraction() {
285 super.onUserInteraction();
286 updatesView.onUserInteraction();