1package de.gultsch.chat.ui;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.List;
7
8import de.gultsch.chat.R;
9import de.gultsch.chat.R.id;
10import de.gultsch.chat.entities.Account;
11import de.gultsch.chat.entities.Contact;
12import de.gultsch.chat.entities.Conversation;
13import de.gultsch.chat.entities.Message;
14import de.gultsch.chat.utils.UIHelper;
15import android.net.Uri;
16import android.os.Bundle;
17import android.app.AlertDialog;
18import android.app.FragmentTransaction;
19import android.app.NotificationManager;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.Intent;
23import android.graphics.Typeface;
24import android.support.v4.widget.SlidingPaneLayout;
25import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
26import android.util.Log;
27import android.view.KeyEvent;
28import android.view.LayoutInflater;
29import android.view.Menu;
30import android.view.MenuItem;
31import android.view.View;
32import android.view.ViewGroup;
33import android.view.inputmethod.InputMethodManager;
34import android.widget.AdapterView;
35import android.widget.AdapterView.OnItemClickListener;
36import android.widget.ArrayAdapter;
37import android.widget.ListView;
38import android.widget.PopupMenu;
39import android.widget.PopupMenu.OnMenuItemClickListener;
40import android.widget.TextView;
41import android.widget.ImageView;
42
43public class ConversationActivity extends XmppActivity {
44
45 public static final String VIEW_CONVERSATION = "viewConversation";
46 public static final String CONVERSATION = "conversationUuid";
47
48 public static final int INSERT_CONTACT = 0x9889;
49
50 protected SlidingPaneLayout spl;
51
52 private List<Conversation> conversationList = new ArrayList<Conversation>();
53 private Conversation selectedConversation = null;
54 private ListView listView;
55
56 private boolean paneShouldBeOpen = true;
57 private ArrayAdapter<Conversation> listAdapter;
58
59 private OnConversationListChangedListener onConvChanged = new OnConversationListChangedListener() {
60
61 @Override
62 public void onConversationListChanged() {
63 final Conversation currentConv = getSelectedConversation();
64 conversationList.clear();
65 conversationList.addAll(xmppConnectionService
66 .getConversations());
67 runOnUiThread(new Runnable() {
68
69 @Override
70 public void run() {
71 updateConversationList();
72 if(paneShouldBeOpen) {
73 if (conversationList.size() >= 1) {
74 swapConversationFragment();
75 } else {
76 startActivity(new Intent(getApplicationContext(), NewConversationActivity.class));
77 finish();
78 }
79 }
80 ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
81 if (selectedFragment!=null) {
82 selectedFragment.updateMessages();
83 }
84 }
85 });
86 }
87 };
88
89 private DialogInterface.OnClickListener addToRoster = new DialogInterface.OnClickListener() {
90
91 @Override
92 public void onClick(DialogInterface dialog, int which) {
93 String jid = getSelectedConversation().getContactJid();
94 Account account = getSelectedConversation().getAccount();
95 String name = jid.split("@")[0];
96 Contact contact = new Contact(account, name, jid, null);
97 xmppConnectionService.createContact(contact);
98 }
99 };
100 private boolean contactInserted = false;
101
102
103 public List<Conversation> getConversationList() {
104 return this.conversationList;
105 }
106
107 public Conversation getSelectedConversation() {
108 return this.selectedConversation;
109 }
110
111 public ListView getConversationListView() {
112 return this.listView;
113 }
114
115 public SlidingPaneLayout getSlidingPaneLayout() {
116 return this.spl;
117 }
118
119 public boolean shouldPaneBeOpen() {
120 return paneShouldBeOpen;
121 }
122
123 public void updateConversationList() {
124 if (conversationList.size() >= 1) {
125 Collections.sort(this.conversationList, new Comparator<Conversation>() {
126 @Override
127 public int compare(Conversation lhs, Conversation rhs) {
128 return (int) (rhs.getLatestMessage().getTimeSent() - lhs.getLatestMessage().getTimeSent());
129 }
130 });
131 }
132 this.listView.invalidateViews();
133 }
134
135 @Override
136 protected void onCreate(Bundle savedInstanceState) {
137
138 super.onCreate(savedInstanceState);
139
140 setContentView(R.layout.fragment_conversations_overview);
141
142 listView = (ListView) findViewById(R.id.list);
143
144 this.listAdapter = new ArrayAdapter<Conversation>(this,
145 R.layout.conversation_list_row, conversationList) {
146 @Override
147 public View getView(int position, View view, ViewGroup parent) {
148 if (view == null) {
149 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
150 view = (View) inflater.inflate(
151 R.layout.conversation_list_row, null);
152 }
153 Conversation conv = getItem(position);
154 TextView convName = (TextView) view.findViewById(R.id.conversation_name);
155 convName.setText(conv.getName());
156 TextView convLastMsg = (TextView) view.findViewById(R.id.conversation_lastmsg);
157 convLastMsg.setText(conv.getLatestMessage().getBody());
158
159 if(!conv.isRead()) {
160 convName.setTypeface(null,Typeface.BOLD);
161 convLastMsg.setTypeface(null,Typeface.BOLD);
162 } else {
163 convName.setTypeface(null,Typeface.NORMAL);
164 convLastMsg.setTypeface(null,Typeface.NORMAL);
165 }
166
167 ((TextView) view.findViewById(R.id.conversation_lastupdate))
168 .setText(UIHelper.readableTimeDifference(getItem(position).getLatestMessage().getTimeSent()));
169
170 Uri profilePhoto = getItem(position).getProfilePhotoUri();
171 ImageView imageView = (ImageView) view.findViewById(R.id.conversation_image);
172 if (profilePhoto!=null) {
173 imageView.setImageURI(profilePhoto);
174 } else {
175 imageView.setImageBitmap(UIHelper.getUnknownContactPicture(getItem(position).getName(),200));
176 }
177
178
179 ((ImageView) view.findViewById(R.id.conversation_image))
180 .setImageURI(getItem(position).getProfilePhotoUri());
181 return view;
182 }
183
184 };
185
186 listView.setAdapter(this.listAdapter);
187
188 listView.setOnItemClickListener(new OnItemClickListener() {
189
190 @Override
191 public void onItemClick(AdapterView<?> arg0, View clickedView,
192 int position, long arg3) {
193 paneShouldBeOpen = false;
194 if (selectedConversation != conversationList.get(position)) {
195 selectedConversation = conversationList.get(position);
196 swapConversationFragment(); //.onBackendConnected(conversationList.get(position));
197 } else {
198 spl.closePane();
199 }
200 }
201 });
202 spl = (SlidingPaneLayout) findViewById(id.slidingpanelayout);
203 spl.setParallaxDistance(150);
204 spl.setShadowResource(R.drawable.es_slidingpane_shadow);
205 spl.setSliderFadeColor(0);
206 spl.setPanelSlideListener(new PanelSlideListener() {
207
208 @Override
209 public void onPanelOpened(View arg0) {
210 paneShouldBeOpen = true;
211 getActionBar().setDisplayHomeAsUpEnabled(false);
212 getActionBar().setTitle(R.string.app_name);
213 invalidateOptionsMenu();
214
215 InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
216
217 View focus = getCurrentFocus();
218
219 if (focus != null) {
220
221 inputManager.hideSoftInputFromWindow(
222 focus.getWindowToken(),
223 InputMethodManager.HIDE_NOT_ALWAYS);
224 }
225 }
226
227 @Override
228 public void onPanelClosed(View arg0) {
229 paneShouldBeOpen = false;
230 if (conversationList.size() > 0) {
231 getActionBar().setDisplayHomeAsUpEnabled(true);
232 getActionBar().setTitle(getSelectedConversation().getName());
233 invalidateOptionsMenu();
234 if (!getSelectedConversation().isRead()) {
235 getSelectedConversation().markRead();
236 updateConversationList();
237 }
238 }
239 }
240
241 @Override
242 public void onPanelSlide(View arg0, float arg1) {
243 // TODO Auto-generated method stub
244
245 }
246 });
247 }
248
249 @Override
250 public boolean onCreateOptionsMenu(Menu menu) {
251 getMenuInflater().inflate(R.menu.conversations, menu);
252 MenuItem menuSecure = (MenuItem) menu.findItem(R.id.action_security);
253
254 if (spl.isOpen()) {
255 ((MenuItem) menu.findItem(R.id.action_archive)).setVisible(false);
256 ((MenuItem) menu.findItem(R.id.action_details)).setVisible(false);
257 menuSecure.setVisible(false);
258 } else {
259 ((MenuItem) menu.findItem(R.id.action_add)).setVisible(false);
260 if (this.getSelectedConversation()!=null) {
261 if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
262 ((MenuItem) menu.findItem(R.id.action_security)).setVisible(false);
263 menuSecure.setVisible(false);
264 ((MenuItem) menu.findItem(R.id.action_archive)).setTitle("Leave conference");
265 } else {
266 if (this.getSelectedConversation().getLatestMessage().getEncryption() != Message.ENCRYPTION_NONE) {
267 menuSecure.setIcon(R.drawable.ic_action_secure);
268 }
269 }
270 }
271 }
272 return true;
273 }
274
275 @Override
276 public boolean onOptionsItemSelected(MenuItem item) {
277 switch (item.getItemId()) {
278 case android.R.id.home:
279 spl.openPane();
280 break;
281 case R.id.action_settings:
282 startActivity(new Intent(this, SettingsActivity.class));
283 break;
284 case R.id.action_accounts:
285 startActivity(new Intent(this, ManageAccountActivity.class));
286 break;
287 case R.id.action_add:
288 startActivity(new Intent(this, NewConversationActivity.class));
289 break;
290 case R.id.action_archive:
291 Conversation conv = getSelectedConversation();
292 conv.setStatus(Conversation.STATUS_ARCHIVED);
293 paneShouldBeOpen = true;
294 spl.openPane();
295 xmppConnectionService.archiveConversation(conv);
296 selectedConversation = conversationList.get(0);
297 break;
298 case R.id.action_details:
299 DialogContactDetails details = new DialogContactDetails();
300 Contact contact = this.getSelectedConversation().getContact();
301 if (contact != null) {
302 contact.setAccount(this.selectedConversation.getAccount());
303 details.setContact(contact);
304 details.show(getFragmentManager(), "details");
305 } else {
306 String jid = getSelectedConversation().getContactJid();
307 AlertDialog.Builder builder = new AlertDialog.Builder(this);
308 builder.setTitle(jid);
309 builder.setMessage("The contact is not in your roster. Would you like to add it.");
310 builder.setNegativeButton("Cancel", null);
311 builder.setPositiveButton("Add",addToRoster);
312 builder.create().show();
313 }
314 break;
315 case R.id.action_security:
316 final Conversation selConv = getSelectedConversation();
317 View menuItemView = findViewById(R.id.action_security);
318 PopupMenu popup = new PopupMenu(this, menuItemView);
319 final ConversationFragment fragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
320 if (fragment!=null) {
321 popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
322
323 @Override
324 public boolean onMenuItemClick(MenuItem item) {
325 switch (item.getItemId()) {
326 case R.id.encryption_choice_none:
327 selConv.nextMessageEncryption = Message.ENCRYPTION_NONE;
328 item.setChecked(true);
329 break;
330 case R.id.encryption_choice_otr:
331 selConv.nextMessageEncryption = Message.ENCRYPTION_OTR;
332 item.setChecked(true);
333 break;
334 case R.id.encryption_choice_pgp:
335 selConv.nextMessageEncryption = Message.ENCRYPTION_PGP;
336 item.setChecked(true);
337 break;
338 default:
339 selConv.nextMessageEncryption = Message.ENCRYPTION_NONE;
340 break;
341 }
342 fragment.updateChatMsgHint();
343 return true;
344 }
345 });
346 popup.inflate(R.menu.encryption_choices);
347 switch (selConv.nextMessageEncryption) {
348 case Message.ENCRYPTION_NONE:
349 popup.getMenu().findItem(R.id.encryption_choice_none).setChecked(true);
350 break;
351 case Message.ENCRYPTION_OTR:
352 popup.getMenu().findItem(R.id.encryption_choice_otr).setChecked(true);
353 break;
354 case Message.ENCRYPTION_PGP:
355 popup.getMenu().findItem(R.id.encryption_choice_pgp).setChecked(true);
356 break;
357 default:
358 popup.getMenu().findItem(R.id.encryption_choice_none).setChecked(true);
359 break;
360 }
361 popup.show();
362 }
363
364 break;
365 default:
366 break;
367 }
368 return super.onOptionsItemSelected(item);
369 }
370
371 protected ConversationFragment swapConversationFragment() {
372 ConversationFragment selectedFragment = new ConversationFragment();
373
374 FragmentTransaction transaction = getFragmentManager()
375 .beginTransaction();
376 transaction.replace(R.id.selected_conversation, selectedFragment,"conversation");
377 transaction.commit();
378 return selectedFragment;
379 }
380
381 @Override
382 public boolean onKeyDown(int keyCode, KeyEvent event) {
383 if (keyCode == KeyEvent.KEYCODE_BACK) {
384 if (!spl.isOpen()) {
385 spl.openPane();
386 return false;
387 }
388 }
389 return super.onKeyDown(keyCode, event);
390 }
391
392 public void onStart() {
393 super.onStart();
394 NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
395 nm.cancelAll();
396 if (conversationList.size()>=1) {
397 onConvChanged.onConversationListChanged();
398 }
399 }
400
401 @Override
402 protected void onStop() {
403 Log.d("gultsch","called on stop in conversation activity");
404 if (xmppConnectionServiceBound) {
405 xmppConnectionService.removeOnConversationListChangedListener();
406 }
407 super.onStop();
408 }
409
410 @Override
411 void onBackendConnected() {
412
413 xmppConnectionService.setOnConversationListChangedListener(this.onConvChanged);
414
415 if (conversationList.size()==0) {
416 conversationList.clear();
417 conversationList.addAll(xmppConnectionService
418 .getConversations());
419
420 this.updateConversationList();
421 }
422
423 if ((getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) {
424 if (getIntent().getType().equals(
425 ConversationActivity.VIEW_CONVERSATION)) {
426 handledViewIntent = true;
427
428 String convToView = (String) getIntent().getExtras().get(CONVERSATION);
429
430 for(int i = 0; i < conversationList.size(); ++i) {
431 if (conversationList.get(i).getUuid().equals(convToView)) {
432 selectedConversation = conversationList.get(i);
433 }
434 }
435 paneShouldBeOpen = false;
436 swapConversationFragment();
437 }
438 } else {
439 if (xmppConnectionService.getAccounts().size() == 0) {
440 startActivity(new Intent(this, ManageAccountActivity.class));
441 finish();
442 } else if (conversationList.size() <= 0) {
443 //add no history
444 startActivity(new Intent(this, NewConversationActivity.class));
445 finish();
446 } else {
447 spl.openPane();
448 //find currently loaded fragment
449 ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
450 if (selectedFragment!=null) {
451 Log.d("gultsch","ConversationActivity. found old fragment.");
452 selectedFragment.onBackendConnected();
453 } else {
454 Log.d("gultsch","conversationactivity. no old fragment found. creating new one");
455 selectedConversation = conversationList.get(0);
456 Log.d("gultsch","selected conversation is #"+selectedConversation);
457 swapConversationFragment();
458 }
459 }
460 }
461 }
462
463 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
464 if (requestCode==INSERT_CONTACT) {
465 Log.d("xmppService","contact inserted");
466 this.contactInserted = true;
467 }
468 }
469}