package com.abewy.android.apps.klyph.fragment; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.ListView; import com.abewy.android.apps.klyph.Klyph; import com.abewy.android.apps.klyph.KlyphBundleExtras; import com.abewy.android.apps.klyph.KlyphNotification; import com.abewy.android.apps.klyph.KlyphPreferences; import com.abewy.android.apps.klyph.R; import com.abewy.android.apps.klyph.adapter.MultiObjectAdapter; import com.abewy.android.apps.klyph.core.fql.FriendRequest; import com.abewy.android.apps.klyph.core.fql.Notification; import com.abewy.android.apps.klyph.core.graph.GraphObject; import com.abewy.android.apps.klyph.core.request.Response; import com.abewy.android.apps.klyph.core.util.AttrUtil; import com.abewy.android.apps.klyph.facebook.IFbPermissionCallback; import com.abewy.android.apps.klyph.facebook.IFbPermissionWorker; import com.abewy.android.apps.klyph.request.AsyncRequest; import com.abewy.android.apps.klyph.request.AsyncRequest.Query; import com.abewy.klyph.items.Header; import com.facebook.Session; import com.haarman.listviewanimations.itemmanipulation.OnDismissCallback; import com.haarman.listviewanimations.itemmanipulation.SwipeDismissAdapter; import com.haarman.listviewanimations.itemmanipulation.SwipeDismissListViewTouchListener; public class Notifications extends KlyphFragment implements IFbPermissionCallback { public static interface NotificationsListener { public void onNewNotifications(); } private static final List<String> PERMISSIONS = Arrays.asList("manage_notifications"); private static final String PENDING_PUBLISH_KEY = "pendingPublishReauthorization"; private boolean pendingAnnounce = false; private long lastUpdateTime = 0; private int unreadCount; private boolean loggedIn = false; private MenuItem refreshItem; public Notifications() { setRequestType(Query.NOTIFICATIONS); setNewestRequestType(Query.NOTIFICATIONS); } @Override protected int getCustomLayout() { return R.layout.fragment_notifications; } @Override public void onCreate(Bundle savedInstanceState) { setRequestType(Query.NOTIFICATIONS); setNewestRequestType(Query.NOTIFICATIONS); super.onCreate(savedInstanceState); setHasOptionsMenu(false); if (savedInstanceState != null) { pendingAnnounce = savedInstanceState.getBoolean(PENDING_PUBLISH_KEY, false); } setAutoLoad(false); } @Override protected void attachViewToPullToRefresh() { } @Override protected void attachViewToPullToRefresh(View view) { } @Override protected int getRefreshMenuItemPosition() { if (unreadCount > 0) return super.getRefreshMenuItemPosition(); return getResources().getInteger(R.integer.right_menu_notification_icon_position); } /* * @Override * protected KlyphPullToRefreshListView onCreatePullToRefreshListView(LayoutInflater inflater, Bundle savedInstanceState) * { * return (KlyphPullToRefreshListView) inflater.inflate(R.layout.list_notifications, null); * } */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); NotificationSwipeDismissAdapter swAdapter = new NotificationSwipeDismissAdapter(new MultiObjectAdapter(getListView()), new OnDismissCallback() { @Override public void onDismiss(AbsListView arg0, int[] positions) { for (int i : positions) { if (getAdapter().getItem(i) instanceof Notification) { Notification notification = (Notification) getAdapter().getItem(i); setNotificationRead(notification); } } List<GraphObject> list = new ArrayList<GraphObject>(); for (GraphObject o : getAdapter().getItems()) { if (!(o instanceof Header)) { list.add(o); } } populate(list); } }); swAdapter.setAbsListView(getListView()); setListAdapter(swAdapter); // setListAdapter(new MultiObjectAdapter(getListView())); defineEmptyText(R.string.empty_list_no_notification); setListVisible(false); setRequestType(Query.NOTIFICATIONS); loggedIn = true; new Handler().postDelayed(new Runnable() { public void run() { loadNotifications(); } }, 2000); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { refreshItem = menu.add(Menu.NONE, R.id.menu_refresh, 1, R.string.refresh); refreshItem.setIcon(AttrUtil.getResourceId(getActivity(), R.attr.refreshIcon)).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); setActionBarRefreshItemLoading(isLoading()); super.onCreateOptionsMenu(menu, inflater); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); if (unreadCount > 0 && menu.findItem(R.id.menu_dismiss) == null) { MenuItem item = menu.add(Menu.NONE, R.id.menu_dismiss, 1, "Dismiss"); item.setIcon(AttrUtil.getResourceId(getActivity(), R.attr.dismissNotificationsIcon)); item.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS); } } protected void setActionBarRefreshItemLoading(boolean loading) { if (refreshItem != null) { if (loading == true) { refreshItem.setActionView(R.layout.actionbar_item_refresh); } else { refreshItem.setActionView(null); } } } @Override protected void startLoading() { setActionBarRefreshItemLoading(true); super.startLoading(); } @Override protected void endLoading() { setActionBarRefreshItemLoading(true); super.endLoading(); } @Override protected void endLoadingNewest() { setActionBarRefreshItemLoading(false); super.endLoadingNewest(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.menu_dismiss) { List<GraphObject> list = new ArrayList<GraphObject>(); List<List<AsyncRequest>> batchs = new ArrayList<List<AsyncRequest>>(); List<AsyncRequest> requests = new ArrayList<AsyncRequest>(); batchs.add(requests); for (GraphObject o : getAdapter().getItems()) { if (o instanceof Notification || o instanceof FriendRequest) { if (o instanceof Notification) { Notification n = (Notification) o; if (requests.size() == 40) { requests = new ArrayList<AsyncRequest>(); batchs.add(requests); } requests.add(new AsyncRequest(Query.POST_READ_NOTIFICATION, n.getNotification_id(), "", null)); n.setIs_unread(false); } list.add(o); } } populate(list); unreadCount = 0; getActivity().invalidateOptionsMenu(); for (List<AsyncRequest> batch : batchs) { if (batch.size() > 0) AsyncRequest.executeBatch(batch); } ((NotificationsListener) getActivity()).onNewNotifications(); return true; } else if (item.getItemId() == R.id.menu_refresh) { onRefreshClicked(); return true; } return super.onOptionsItemSelected(item); } public void onOpenPane() { KlyphPreferences.setLastCheckedNotificationTime(new Date().getTime() / 1000); // If last update greater than 1 min, do an update if ((new Date().getTime() - lastUpdateTime > 1 * 60 * 1000) && hasPermissions()) { loadNotifications(); } } public int getNewNotificationsCount() { List<Notification> list = new ArrayList<Notification>(); for (GraphObject o : getAdapter().getItems()) { if (o instanceof Notification) { if (((Notification) o).getIs_unread() == true) { list.add((Notification) o); } } } long lastCheckedTime = KlyphPreferences.getLastCheckedNotificationTime(); int count = 0; for (Notification notification : list) { long nTime = 0; try { nTime = Long.parseLong(notification.getUpdated_time()); } catch (NumberFormatException e) { } if (nTime > lastCheckedTime) count++; } return count; } public int getUnreadCount() { int count = 0; if (getAdapter() != null) { for (GraphObject o : getAdapter().getItems()) { if (o instanceof Notification) { Notification n = (Notification) o; if (n.getIs_unread() == true) count++; } } } return count; } private boolean hasPermissions() { Session session = Session.getActiveSession(); List<String> permissions = session.getPermissions(); return permissions.containsAll(PERMISSIONS); } @Override public void load() { loadNotifications(); } public void reset() { if (getAdapter() != null) getAdapter().clear(); setIsFirstLoad(true); } @Override public void onCancelPermissions() { defineEmptyText(R.string.notifications_permissions_denied); populate(new ArrayList<GraphObject>()); pendingAnnounce = false; } @Override protected void populate(List<GraphObject> data) { getAdapter().clear(false); List<GraphObject> readNotifications = new ArrayList<GraphObject>(); List<GraphObject> unreadNotifications = new ArrayList<GraphObject>(); List<GraphObject> friendRequests = new ArrayList<GraphObject>(); for (GraphObject graphObject : data) { if (graphObject instanceof Notification) { if (((Notification) graphObject).getIs_unread() == true) { unreadNotifications.add(graphObject); } else { readNotifications.add(graphObject); } } else { friendRequests.add(graphObject); } } List<GraphObject> list = new ArrayList<GraphObject>(); unreadCount = unreadNotifications.size(); if (unreadNotifications.size() > 0) { unreadNotifications.get(unreadNotifications.size() - 1).setShowDivider(false); Header nTitle = new Header(); nTitle.setName(getString(R.string.notifications_unread_header_title, unreadNotifications.size())); list.add(nTitle); list.addAll(unreadNotifications); } if (readNotifications.size() > 0) { readNotifications.get(readNotifications.size() - 1).setShowDivider(false); Header nTitle = new Header(); nTitle.setName(getString(R.string.notifications_read_header_title)); list.add(nTitle); list.addAll(readNotifications); } if (friendRequests.size() > 0) { friendRequests.get(friendRequests.size() - 1).setShowDivider(false); Header fTitle = new Header(); fTitle.setName(getString(R.string.notifications_friend_request_header_title)); list.add(fTitle); list.addAll(friendRequests); } super.populate(list); lastUpdateTime = new Date().getTime(); setActionBarRefreshItemLoading(false); ((NotificationsListener) getActivity()).onNewNotifications(); // getActivity().supportInvalidateOptionsMenu(); /* * if (data.size() > 0) * setOffset(((Notification) data.get(data.size() - 1)).getCreated_time()); */ } @Override protected void populateNewest(List<GraphObject> data) { populate(data); } @Override public void onPermissionsChange() { if (pendingAnnounce) { loadNotifications(); } } private void loadNotifications() { pendingAnnounce = false; if (!hasPermissions()) { pendingAnnounce = true; requestExtendedPermissions(Session.getActiveSession()); return; } defineEmptyText(R.string.empty_list_no_notification); setIsFirstLoad(true); super.load(); } private void requestExtendedPermissions(Session session) { if (getActivity() != null) ((IFbPermissionWorker) getActivity()).requestPublishPermissions(this, PERMISSIONS); } @Override public void onSaveInstanceState(Bundle bundle) { super.onSaveInstanceState(bundle); bundle.putBoolean(PENDING_PUBLISH_KEY, pendingAnnounce); } @Override public void onListItemClick(ListView gridView, View view, int position, long id) { GraphObject graphObject = getAdapter().getItem(position); if (graphObject instanceof Notification) { Notification notification = (Notification) graphObject; if (notification.getIs_unread() == true) { setNotificationRead(notification); ((NotificationsListener) getActivity()).onNewNotifications(); } Intent intent = KlyphNotification.getIntentForNotification(getActivity(), notification); if (intent != null) { startActivity(intent); } } else if (graphObject instanceof FriendRequest) { /* * new AsyncRequest(Query.POST_READ_NOTIFICATION, ((FriendRequest) graphObject).getUid_from(), "", new AsyncRequest.Callback() { * * @Override * public void onComplete(Response response) * { * Log.d("NotificationsNotifications", "result " + response.getError()); * } * }).execute(); */ startActivity(Klyph.getIntentForGraphObject(getActivity(), graphObject)); } } private void setNotificationRead(Notification notification) { notification.setIs_unread(false); new AsyncRequest(Query.POST_READ_NOTIFICATION, notification.getNotification_id(), "", new AsyncRequest.Callback() { @Override public void onComplete(Response response) { Log.d("NotificationsNotifications", "result " + response.getError()); } }).execute(); } @Override protected void onRefreshClicked() { if (!isLoading()) { setActionBarRefreshItemLoading(true); loadNewest(); } } @Override public void onPause() { try { getActivity().unregisterReceiver(mMessageReceiver); getActivity().unregisterReceiver(mNotificationStatusChangeReceiver); } catch (IllegalArgumentException e) { } super.onPause(); } public void onLoggedOut() { loggedIn = false; } @Override public void onDestroy() { super.onDestroy(); refreshItem = null; } @Override public void onResume() { super.onResume(); getActivity().registerReceiver(mMessageReceiver, new IntentFilter(KlyphBundleExtras.NOTIFICATION_EVENT)); getActivity().registerReceiver(mMessageReceiver, new IntentFilter("com.abewy.android.apps.klyph.action.NOTIFICATION_STATUS_CHANGE")); // Update list in case some items have been read if (getAdapter() != null) { List<GraphObject> list = new ArrayList<GraphObject>(); for (GraphObject o : getAdapter().getItems()) { if (o instanceof Notification || o instanceof FriendRequest) list.add(o); } populate(list); } // If last update greater than 1 min, do an update if ((new Date().getTime() - lastUpdateTime > 1 * 60 * 1000) || KlyphPreferences.hasNotificationReadStatusChanged()) { KlyphPreferences.setNotificationReadStatusChanged(false); if (hasPermissions() && loggedIn == true) { loadNotifications(); } } } private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (hasPermissions() && !isLoading()) loadNotifications(); } }; private BroadcastReceiver mNotificationStatusChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (hasPermissions() && !isLoading()) loadNotifications(); } }; private static class NotificationSwipeDismissAdapter extends SwipeDismissAdapter { private OnDismissCallback mCallback; public NotificationSwipeDismissAdapter(BaseAdapter baseAdapter, OnDismissCallback callback) { super(baseAdapter, callback); mCallback = callback; } @Override public void setAbsListView(AbsListView listView) { super.setAbsListView(listView); listView.setOnTouchListener(new NotificationSwipeDismissListViewTouchListener(listView, mCallback)); } } private static class NotificationSwipeDismissListViewTouchListener extends SwipeDismissListViewTouchListener { private AbsListView mListView; public NotificationSwipeDismissListViewTouchListener(AbsListView listView, OnDismissCallback callback) { super(listView, callback); mListView = listView; } @Override public boolean onTouch(View view, MotionEvent motionEvent) { int childCount = mListView.getChildCount(); View child, downView = null; Rect rect = new Rect(); int[] listViewCoords = new int[2]; mListView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; for (int i = 0; i < childCount; i++) { child = mListView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { downView = child; break; } } if (downView != null) { int position = mListView.getPositionForView(downView); Object o = mListView.getAdapter().getItem(position); if (o instanceof Notification) { Notification n = (Notification) o; if (n.getIs_unread() == false) return false; else mListView.requestDisallowInterceptTouchEvent(true); } else { return false; } } return super.onTouch(view, motionEvent); } } }