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