diff --git a/app/app-fdroid-release-1.4.9-beta-6.apk b/app/app-fdroid-release-1.4.9-beta-6.apk new file mode 100644 index 000000000..246002bfc Binary files /dev/null and b/app/app-fdroid-release-1.4.9-beta-6.apk differ diff --git a/app/app-fdroid-release-federatedtm-stream.apk b/app/app-fdroid-release-federatedtm-stream.apk new file mode 100644 index 000000000..03fc59def Binary files /dev/null and b/app/app-fdroid-release-federatedtm-stream.apk differ diff --git a/app/app-safetynet-release-1.4.9-beta-6.apk b/app/app-safetynet-release-1.4.9-beta-6.apk new file mode 100644 index 000000000..b9945c41b Binary files /dev/null and b/app/app-safetynet-release-1.4.9-beta-6.apk differ diff --git a/app/build.gradle b/app/build.gradle index 0164ec4c5..d72feae38 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "fr.gouv.etalab.mastodon" minSdkVersion 15 targetSdkVersion 25 - versionCode 54 - versionName "1.4.9-beta-6" + versionCode 55 + versionName "1.4.9-beta-7" } buildTypes { release { diff --git a/app/src/fdroid/java/fr.gouv.etalab.mastodon/activities/MainActivity.java b/app/src/fdroid/java/fr.gouv.etalab.mastodon/activities/MainActivity.java index 643fe909e..232db4ac2 100644 --- a/app/src/fdroid/java/fr.gouv.etalab.mastodon/activities/MainActivity.java +++ b/app/src/fdroid/java/fr.gouv.etalab.mastodon/activities/MainActivity.java @@ -99,8 +99,6 @@ import fr.gouv.etalab.mastodon.fragments.TabLayoutSettingsFragment; import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import mastodon.etalab.gouv.fr.mastodon.R; -import static fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment.tempNotifications; -import static fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment.tempStatuses; import static fr.gouv.etalab.mastodon.helper.Helper.CHANGE_THEME_INTENT; import static fr.gouv.etalab.mastodon.helper.Helper.CHANGE_USER_INTENT; import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT; @@ -132,15 +130,15 @@ public class MainActivity extends AppCompatActivity private RelativeLayout main_app_container; private Stack stackBack = new Stack<>(); - private DisplayStatusFragment homeFragment; + private DisplayStatusFragment homeFragment, federatedFragment, localFragment; private DisplayNotificationsFragment notificationsFragment; - private BroadcastReceiver receive_data; + private BroadcastReceiver receive_data, receive_federated_data, receive_local_data; private boolean display_local, display_global; public static int countNewStatus = 0; public static int countNewNotifications = 0; private String userIdService; private Intent streamingIntent; - public static boolean broadCastRegistred = false; + public static String lastHomeId = null, lastNotificationId = null; public MainActivity() { } @@ -151,50 +149,6 @@ public class MainActivity extends AppCompatActivity final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - receive_data = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Bundle b = intent.getExtras(); - StreamingService.EventStreaming eventStreaming = (StreamingService.EventStreaming) intent.getSerializableExtra("eventStreaming"); - userIdService = b.getString("userIdService", null); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - if( userIdService != null && userIdService.equals(userId)) { - if (eventStreaming == StreamingService.EventStreaming.NOTIFICATION) { - Notification notification = b.getParcelable("data"); - if (notificationsFragment != null) { - notificationsFragment.refresh(notification); - } else { - tempNotifications.add(notification); - } - } else if (eventStreaming == StreamingService.EventStreaming.UPDATE) { - Status status = b.getParcelable("data"); - if (homeFragment != null) { - homeFragment.refresh(status); - } else { - tempStatuses.add(status); - } - } else if (eventStreaming == StreamingService.EventStreaming.DELETE) { - String id = b.getString("id"); - if (notificationsFragment != null) { - if (notificationsFragment.getUserVisibleHint()) { - - } else { - - } - } - } - updateNotifCounter(); - updateHomeCounter(); - } - } - }; - streamingIntent = new Intent(this, StreamingService.class); - startService(streamingIntent); - - if( !broadCastRegistred) { - LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA)); - broadCastRegistred = true; - } @@ -725,7 +679,6 @@ public class MainActivity extends AppCompatActivity * @param intent Intent - intent related to a notification in top bar */ private boolean mamageNewIntent(Intent intent){ - if( intent == null || intent.getExtras() == null ) return false; @@ -754,6 +707,12 @@ public class MainActivity extends AppCompatActivity matchingIntent = true; }else if( extras.getInt(INTENT_ACTION) == CHANGE_USER_INTENT){ unCheckAllMenuItems(navigationView); + if( tabLayout.getTabAt(0) != null) + //noinspection ConstantConditions + tabLayout.getTabAt(0).select(); + if( !toolbar_search.isIconified() ) { + toolbar_search.setIconified(true); + } matchingIntent = true; } }else if( Intent.ACTION_SEND.equals(action) && type != null ) { @@ -896,10 +855,105 @@ public class MainActivity extends AppCompatActivity //Proceeds to update of the authenticated account if(Helper.isLoggedIn(getApplicationContext())) new UpdateAccountInfoByIDAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if( lastHomeId != null && homeFragment != null){ + homeFragment.retrieveMissingToots(lastHomeId); + } + if( lastNotificationId != null && notificationsFragment != null){ + notificationsFragment.retrieveMissingNotifications(lastNotificationId); + } } + @Override + public void onStart(){ + super.onStart(); + final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + receive_federated_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + userIdService = b.getString("userIdService", null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if( userIdService != null && userIdService.equals(userId)) { + Status status = b.getParcelable("data"); + if (federatedFragment != null) { + federatedFragment.refresh(status); + } + } + } + }; + receive_local_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + userIdService = b.getString("userIdService", null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if( userIdService != null && userIdService.equals(userId)) { + Status status = b.getParcelable("data"); + if (localFragment != null) { + localFragment.refresh(status); + } + } + } + }; + receive_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + StreamingService.EventStreaming eventStreaming = (StreamingService.EventStreaming) intent.getSerializableExtra("eventStreaming"); + userIdService = b.getString("userIdService", null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if( userIdService != null && userIdService.equals(userId)) { + if (eventStreaming == StreamingService.EventStreaming.NOTIFICATION) { + Notification notification = b.getParcelable("data"); + if (notificationsFragment != null) { + notificationsFragment.refresh(notification); + } + } else if (eventStreaming == StreamingService.EventStreaming.UPDATE) { + Status status = b.getParcelable("data"); + if (homeFragment != null) { + homeFragment.refresh(status); + } + } else if (eventStreaming == StreamingService.EventStreaming.DELETE) { + String id = b.getString("id"); + if (notificationsFragment != null) { + if (notificationsFragment.getUserVisibleHint()) { + } else { + + } + } + } + updateNotifCounter(); + updateHomeCounter(); + } + } + }; + streamingIntent = new Intent(this, StreamingService.class); + startService(streamingIntent); + LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA)); + LocalBroadcastManager.getInstance(this).registerReceiver(receive_federated_data, new IntentFilter(Helper.RECEIVE_FEDERATED_DATA)); + LocalBroadcastManager.getInstance(this).registerReceiver(receive_local_data, new IntentFilter(Helper.RECEIVE_LOCAL_DATA)); + } + + @Override + public void onStop(){ + super.onStop(); + if( streamingIntent != null) { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, false); + stopService(streamingIntent); + editor.apply(); + } + if( receive_data != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data); + if( receive_federated_data != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_federated_data); + if( receive_local_data != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_local_data); + } @Override protected void onPause() { @@ -910,10 +964,6 @@ public class MainActivity extends AppCompatActivity @Override public void onDestroy(){ super.onDestroy(); - if( streamingIntent != null) - stopService(streamingIntent); - LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data); - broadCastRegistred = false; } @SuppressWarnings("StatementWithEmptyBody") @@ -1119,6 +1169,16 @@ public class MainActivity extends AppCompatActivity case 1: notificationsFragment = (DisplayNotificationsFragment) createdFragment; break; + case 2: + if ( !display_local && display_global) + federatedFragment = (DisplayStatusFragment) createdFragment; + if( display_local) + localFragment = (DisplayStatusFragment) createdFragment; + break; + case 3: + if( display_local && display_global) + federatedFragment = (DisplayStatusFragment) createdFragment; + break; } return createdFragment; } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bd131506c..30e6ab865 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -43,6 +43,24 @@ + + + + + + + + + + + + s.toString().length()) return; Matcher m; @@ -566,7 +568,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc } new RetrieveSearchAccountsAsyncTask(getApplicationContext(),search,TootActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }else{toot_content.dismissDropDown();} - int totalChar = toot_cw_content.length() + toot_content.length(); + totalChar = toot_cw_content.length() + toot_content.length(); toot_space_left.setText(String.valueOf(totalChar)); } }); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java index 210d66d88..5787a5148 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java @@ -16,11 +16,8 @@ package fr.gouv.etalab.mastodon.asynctasks; import android.content.Context; import android.os.AsyncTask; -import android.util.Log; - import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.APIResponse; -import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface; @@ -40,7 +37,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { private String tag; private boolean showMediaOnly = false; private boolean showPinned = false; - private boolean refreshData; public enum Type{ HOME, @@ -59,7 +55,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { this.action = action; this.max_id = max_id; this.listener = onRetrieveFeedsInterface; - this.refreshData = true; } public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, boolean showPinned, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ @@ -69,7 +64,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { this.listener = onRetrieveFeedsInterface; this.targetedID = targetedID; this.showMediaOnly = showMediaOnly; - this.refreshData = true; this.showPinned = showPinned; } public RetrieveFeedsAsyncTask(Context context, Type action, String tag, String targetedID, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ @@ -79,7 +73,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { this.listener = onRetrieveFeedsInterface; this.targetedID = targetedID; this.tag = tag; - this.refreshData = true; } @@ -121,6 +114,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { @Override protected void onPostExecute(Void result) { - listener.onRetrieveFeeds(apiResponse, refreshData); + listener.onRetrieveFeeds(apiResponse); } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveMissingFeedsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveMissingFeedsAsyncTask.java new file mode 100644 index 000000000..c6773404c --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveMissingFeedsAsyncTask.java @@ -0,0 +1,72 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.asynctasks; + +import android.content.Context; +import android.os.AsyncTask; +import java.util.ArrayList; +import java.util.List; +import fr.gouv.etalab.mastodon.activities.MainActivity; +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.APIResponse; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMissingFeedsInterface; + + +/** + * Created by Thomas on 27/09/2017. + * Retrieves missing toots since last pause + */ + +public class RetrieveMissingFeedsAsyncTask extends AsyncTask { + + private Context context; + private String since_id; + private OnRetrieveMissingFeedsInterface listener; + private List statuses = new ArrayList<>(); + + public RetrieveMissingFeedsAsyncTask(Context context, String since_id, OnRetrieveMissingFeedsInterface onRetrieveMissingFeedsInterface){ + this.context = context; + this.since_id = since_id; + this.listener = onRetrieveMissingFeedsInterface; + } + + + @Override + protected Void doInBackground(Void... params) { + int loopInc = 0; + API api = new API(context); + List tempStatus; + while (loopInc < 10){ + APIResponse apiResponse = api.getHomeTimelineSinceId(since_id, 80); + String max_id = apiResponse.getMax_id(); + since_id = apiResponse.getSince_id(); + tempStatus = apiResponse.getStatuses(); + if( statuses != null && tempStatus != null) + statuses.addAll(0, tempStatus); + loopInc++; + if( max_id == null || max_id.equals(since_id)) + break; + } + if( statuses != null && statuses.size() > 0) { + MainActivity.lastHomeId = statuses.get(0).getId(); + } + return null; + } + + @Override + protected void onPostExecute(Void result) { + listener.onRetrieveMissingFeeds(statuses); + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveMissingNotificationsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveMissingNotificationsAsyncTask.java new file mode 100644 index 000000000..694d625c3 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveMissingNotificationsAsyncTask.java @@ -0,0 +1,77 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.asynctasks; + +import android.content.Context; +import android.os.AsyncTask; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import fr.gouv.etalab.mastodon.activities.MainActivity; +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.APIResponse; +import fr.gouv.etalab.mastodon.client.Entities.Notification; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMissingNotificationsInterface; + + +/** + * Created by Thomas on 27/09/2017. + * Retrieves missing notifications since last pause + */ + +public class RetrieveMissingNotificationsAsyncTask extends AsyncTask { + + private Context context; + private String since_id; + private OnRetrieveMissingNotificationsInterface listener; + private List notifications = new ArrayList<>(); + + public RetrieveMissingNotificationsAsyncTask(Context context, String since_id, OnRetrieveMissingNotificationsInterface onRetrieveMissingNotifications){ + this.context = context; + this.since_id = since_id; + this.listener = onRetrieveMissingNotifications; + } + + + @Override + protected Void doInBackground(Void... params) { + int loopInc = 0; + API api = new API(context); + List tempNotifications; + while (loopInc < 10){ + APIResponse apiResponse = api.getNotificationsSince(since_id, 40); + String max_id = apiResponse.getMax_id(); + since_id = apiResponse.getSince_id(); + tempNotifications = apiResponse.getNotifications(); + if( notifications != null && tempNotifications != null) + notifications.addAll(0, tempNotifications); + loopInc++; + if( max_id == null || max_id.equals(since_id)) + break; + } + if( notifications != null && notifications.size() > 0) { + MainActivity.lastNotificationId = notifications.get(0).getId(); + } + return null; + } + + @Override + protected void onPostExecute(Void result) { + listener.onRetrieveMissingNotifications(notifications); + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index b420e93bf..15bacf9a1 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -271,6 +271,9 @@ public class API { return relationship; } + + + /** * Returns a relationship between the authenticated account and an account * @param accounts ArrayList accounts fetched @@ -468,6 +471,14 @@ public class API { return getHomeTimeline(max_id, null, tootPerPage); } + /** + * Retrieves home timeline for the account *synchronously* + * @return APIResponse + */ + public APIResponse getHomeTimeline( String max_id, int tootPerPage) { + return getHomeTimeline(max_id, null, tootPerPage); + } + /** * Retrieves home timeline for the account since an Id value *synchronously* * @return APIResponse @@ -476,6 +487,14 @@ public class API { return getHomeTimeline(null, since_id, tootPerPage); } + /** + * Retrieves home timeline for the account since an Id value *synchronously* + * @return APIResponse + */ + public APIResponse getHomeTimelineSinceId(String since_id, int tootPerPage) { + return getHomeTimeline(null, since_id, tootPerPage); + } + /** * Retrieves home timeline for the account *synchronously* * @param max_id String id max @@ -490,8 +509,8 @@ public class API { params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); - if (0 > limit || limit > 40) - limit = 40; + if (0 > limit || limit > 80) + limit = 80; params.put("limit",String.valueOf(limit)); statuses = new ArrayList<>(); get("/timelines/home", params, new JsonHttpResponseHandler() { @@ -1070,6 +1089,15 @@ public class API { return getNotifications(null, since_id, notificationPerPage); } + /** + * Retrieves notifications for the authenticated account since an id*synchronously* + * @param since_id String since max + * @return APIResponse + */ + public APIResponse getNotificationsSince(String since_id, int notificationPerPage){ + return getNotifications(null, since_id, notificationPerPage); + } + /** * Retrieves notifications for the authenticated account *synchronously* * @param max_id String id max @@ -1095,6 +1123,21 @@ public class API { if( 0 > limit || limit > 40) limit = 40; params.put("limit",String.valueOf(limit)); + + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); + boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); + boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); + boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); + if( !notif_follow ) + params.add("exclude_types[]", "follow"); + if( !notif_add ) + params.add("exclude_types[]", "favourite"); + if( !notif_share ) + params.add("exclude_types[]", "reblog"); + if( !notif_mention ) + params.add("exclude_types[]", "mention"); + notifications = new ArrayList<>(); get("/notifications", params, new JsonHttpResponseHandler() { @@ -1347,8 +1390,16 @@ public class API { status.setContent(resobj.get("content").toString()); status.setFavourites_count(Integer.valueOf(resobj.get("favourites_count").toString())); status.setReblogs_count(Integer.valueOf(resobj.get("reblogs_count").toString())); - status.setReblogged(Boolean.valueOf(resobj.get("reblogged").toString())); - status.setFavourited(Boolean.valueOf(resobj.get("favourited").toString())); + try { + status.setReblogged(Boolean.valueOf(resobj.get("reblogged").toString())); + }catch (Exception e){ + status.setReblogged(false); + } + try { + status.setFavourited(Boolean.valueOf(resobj.get("favourited").toString())); + }catch (Exception e){ + status.setReblogged(false); + } try { status.setPinned(Boolean.valueOf(resobj.get("pinned").toString())); }catch (JSONException e){ diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java index 4bc402d09..803597b06 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java @@ -29,12 +29,14 @@ import android.os.Build; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v7.widget.CardView; +import android.support.v7.widget.PopupMenu; import android.text.Html; import android.text.SpannableString; import android.text.method.LinkMovementMethod; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -509,10 +511,166 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio holder.notification_account_username.setText( String.format("@%s",notification.getAccount().getUsername())); final View finalConvertView = convertView; + final String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + final View attached = holder.status_more; holder.status_more.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - moreOptionDialog(status, finalConvertView); + + holder.status_more.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PopupMenu popup = new PopupMenu(context, attached); + final boolean isOwner = status.getAccount().getId().equals(userId); + popup.getMenuInflater() + .inflate(R.menu.option_toot, popup.getMenu()); + if( status.getVisibility().equals("private") || status.getVisibility().equals("direct")){ + popup.getMenu().findItem(R.id.action_mention).setVisible(false); + } + final String[] stringArrayConf; + if( isOwner) { + popup.getMenu().findItem(R.id.action_block).setVisible(false); + popup.getMenu().findItem(R.id.action_mute).setVisible(false); + popup.getMenu().findItem(R.id.action_report).setVisible(false); + stringArrayConf = context.getResources().getStringArray(R.array.more_action_owner_confirm); + }else { + popup.getMenu().findItem(R.id.action_remove).setVisible(false); + stringArrayConf = context.getResources().getStringArray(R.array.more_action_confirm); + } + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + AlertDialog.Builder builderInner; + final API.StatusAction doAction; + switch (item.getItemId()) { + case R.id.action_remove: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[0]); + doAction = API.StatusAction.UNSTATUS; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); + else + //noinspection deprecation + builderInner.setMessage(Html.fromHtml(status.getContent())); + break; + case R.id.action_mute: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[0]); + doAction = API.StatusAction.MUTE; + break; + case R.id.action_block: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[1]); + doAction = API.StatusAction.BLOCK; + break; + case R.id.action_report: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[2]); + doAction = API.StatusAction.REPORT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); + else + //noinspection deprecation + builderInner.setMessage(Html.fromHtml(status.getContent())); + break; + case R.id.action_copy: + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + String content; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + content = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); + else + //noinspection deprecation + content = Html.fromHtml(status.getContent()).toString(); + ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content); + clipboard.setPrimaryClip(clip); + Toast.makeText(context,R.string.clipboard,Toast.LENGTH_LONG).show(); + return true; + case R.id.action_share: + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); + sendIntent.putExtra(Intent.EXTRA_TEXT, status.getUrl()); + sendIntent.setType("text/plain"); + context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); + return true; + case R.id.action_mention: + status.setTakingScreenShot(true); + notificationsListAdapter.notifyDataSetChanged(); + Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + + @Override + public void run() { + Bitmap bitmap = Helper.convertTootIntoBitmap(context, finalConvertView); + status.setTakingScreenShot(false); + notificationsListAdapter.notifyDataSetChanged(); + Intent intent = new Intent(context, TootActivity.class); + Bundle b = new Bundle(); + String fname = "tootmention_" + status.getId() +".jpg"; + File file = new File (context.getCacheDir() + "/", fname); + if (file.exists ()) //noinspection ResultOfMethodCallIgnored + file.delete (); + try { + FileOutputStream out = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); + out.flush(); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + b.putString("fileMention", fname); + b.putString("tootMention", (status.getReblog() != null)?status.getReblog().getAccount().getAcct():status.getAccount().getAcct()); + b.putString("urlMention", (status.getReblog() != null)?status.getReblog().getUrl():status.getUrl()); + intent.putExtras(b); + context.startActivity(intent); + } + + }, 1000); + return true; + default: + return true; + } + + //Text for report + EditText input = null; + if( doAction == API.StatusAction.REPORT){ + input = new EditText(context); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + input.setLayoutParams(lp); + builderInner.setView(input); + } + builderInner.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog,int which) { + dialog.dismiss(); + } + }); + final EditText finalInput = input; + builderInner.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog,int which) { + if(doAction == API.StatusAction.UNSTATUS ){ + String targetedId = status.getId(); + new PostActionAsyncTask(context, doAction, targetedId, NotificationsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else if(doAction == API.StatusAction.REPORT ){ + String comment = null; + if( finalInput.getText() != null) + comment = finalInput.getText().toString(); + new PostActionAsyncTask(context, doAction, status.getId(), status, comment, NotificationsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + String targetedId = status.getAccount().getId(); + new PostActionAsyncTask(context, doAction, targetedId, NotificationsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + dialog.dismiss(); + } + }); + builderInner.show(); + return true; + } + }); + popup.show(); + } + }); } }); @@ -830,244 +988,4 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio ImageView status_privacy; } - - - /** - * More option for status (report / remove status / Mute / Block) - * @param status Status current status - */ - private void moreOptionDialog(final Status status, final View view){ - - SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - final boolean isOwner = status.getAccount().getId().equals(userId); - AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); - //builderSingle.setTitle(R.string.make_a_choice); - final String[] stringArray, stringArrayConf; - final API.StatusAction[] doAction; - if( isOwner) { - if( status.getVisibility().equals("private") || status.getVisibility().equals("direct")){ - String[] stringArraytmp = context.getResources().getStringArray(R.array.more_action_owner); - List list = new ArrayList<>(Arrays.asList(stringArraytmp)); - list.remove(3); - stringArray = list.toArray(new String[0]); - String[] stringArrayConftmp = context.getResources().getStringArray(R.array.more_action_owner_confirm); - list = new ArrayList<>(Arrays.asList(stringArrayConftmp)); - list.remove(3); - stringArrayConf = list.toArray(new String[0]); - doAction = new API.StatusAction[]{API.StatusAction.UNSTATUS}; - }else { - stringArray = context.getResources().getStringArray(R.array.more_action_owner); - stringArrayConf = context.getResources().getStringArray(R.array.more_action_owner_confirm); - doAction = new API.StatusAction[]{API.StatusAction.UNSTATUS}; - } - }else { - if( status.getVisibility().equals("private") || status.getVisibility().equals("direct")){ - String[] stringArraytmp = context.getResources().getStringArray(R.array.more_action); - List list = new ArrayList<>(Arrays.asList(stringArraytmp)); - list.remove(5); - stringArray = list.toArray(new String[0]); - String[] stringArrayConftmp = context.getResources().getStringArray(R.array.more_action_confirm); - list = new ArrayList<>(Arrays.asList(stringArrayConftmp)); - list.remove(5); - stringArrayConf = list.toArray(new String[0]); - doAction = new API.StatusAction[]{API.StatusAction.MUTE, API.StatusAction.BLOCK, API.StatusAction.REPORT}; - }else { - stringArray = context.getResources().getStringArray(R.array.more_action); - stringArrayConf = context.getResources().getStringArray(R.array.more_action_confirm); - doAction = new API.StatusAction[]{API.StatusAction.MUTE, API.StatusAction.BLOCK, API.StatusAction.REPORT}; - } - } - final ArrayAdapter arrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, stringArray); - builderSingle.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - - builderSingle.setAdapter(arrayAdapter, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - AlertDialog.Builder builderInner = new AlertDialog.Builder(context); - builderInner.setTitle(stringArrayConf[which]); - if( isOwner) { - if( which == 0) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); - else - //noinspection deprecation - builderInner.setMessage(Html.fromHtml(status.getContent())); - }else if( which == 1){ - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - String content; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - content = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); - else - //noinspection deprecation - content = Html.fromHtml(status.getContent()).toString(); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content); - clipboard.setPrimaryClip(clip); - Toast.makeText(context,R.string.clipboard,Toast.LENGTH_LONG).show(); - dialog.dismiss(); - return; - }else if( which == 2) { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, status.getUrl()); - sendIntent.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); - return; - }else if (which == 3){ - status.setTakingScreenShot(true); - notificationsListAdapter.notifyDataSetChanged(); - - - Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - - @Override - public void run() { - Bitmap bitmap = Helper.convertTootIntoBitmap(context, view); - status.setTakingScreenShot(false); - notificationsListAdapter.notifyDataSetChanged(); - Intent intent = new Intent(context, TootActivity.class); - Bundle b = new Bundle(); - String fname = "tootmention_" + status.getId() +".jpg"; - File file = new File (context.getCacheDir() + "/", fname); - if (file.exists ()) //noinspection ResultOfMethodCallIgnored - file.delete (); - try { - FileOutputStream out = new FileOutputStream(file); - bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); - out.flush(); - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - b.putString("fileMention", fname); - b.putString("tootMention", (status.getReblog() != null)?status.getReblog().getAccount().getAcct():status.getAccount().getAcct()); - b.putString("urlMention", (status.getReblog() != null)?status.getReblog().getUrl():status.getUrl()); - intent.putExtras(b); - context.startActivity(intent); - } - - }, 1000); - return; - } - }else { - if( which < 2 ){ - builderInner.setMessage(status.getAccount().getAcct()); - }else if( which == 2) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); - else - //noinspection deprecation - builderInner.setMessage(Html.fromHtml(status.getContent())); - }else if( which == 3 ){ - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - String content; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - content = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); - else - //noinspection deprecation - content = Html.fromHtml(status.getContent()).toString(); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content); - clipboard.setPrimaryClip(clip); - Toast.makeText(context,R.string.clipboard,Toast.LENGTH_LONG).show(); - dialog.dismiss(); - return; - }else if (which == 4){ - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, status.getUrl()); - sendIntent.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); - return; - }else if (which == 5){ - status.setTakingScreenShot(true); - notificationsListAdapter.notifyDataSetChanged(); - Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - - @Override - public void run() { - Bitmap bitmap = Helper.convertTootIntoBitmap(context, view); - status.setTakingScreenShot(false); - notificationsListAdapter.notifyDataSetChanged(); - Intent intent = new Intent(context, TootActivity.class); - Bundle b = new Bundle(); - String fname = "tootmention_" + status.getId() +".jpg"; - File file = new File (context.getCacheDir() + "/", fname); - if (file.exists ()) //noinspection ResultOfMethodCallIgnored - file.delete (); - try { - FileOutputStream out = new FileOutputStream(file); - bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); - out.flush(); - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - b.putString("fileMention", fname); - b.putString("tootMention", (status.getReblog() != null)?status.getReblog().getAccount().getAcct():status.getAccount().getAcct()); - b.putString("urlMention", (status.getReblog() != null)?status.getReblog().getUrl():status.getUrl()); - intent.putExtras(b); - context.startActivity(intent); - } - - }, 1000); - return; - } - } - //Text for report - EditText input = null; - final int position = which; - if( doAction[which] == API.StatusAction.REPORT){ - input = new EditText(context); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT); - input.setLayoutParams(lp); - builderInner.setView(input); - } - builderInner.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog,int which) { - dialog.dismiss(); - } - }); - final EditText finalInput = input; - builderInner.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog,int which) { - API.StatusAction statusAction = doAction[position]; - if(statusAction == API.StatusAction.REPORT || statusAction == API.StatusAction.CREATESTATUS){ - String comment = null; - if( finalInput != null && finalInput.getText() != null) - comment = finalInput.getText().toString(); - new PostActionAsyncTask(context, statusAction, status.getId(), status, comment, NotificationsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - }else{ - String targetedId; - if( doAction[position] == API.StatusAction.FAVOURITE || - doAction[position] == API.StatusAction.UNFAVOURITE || - doAction[position] == API.StatusAction.REBLOG || - doAction[position] == API.StatusAction.UNREBLOG || - doAction[position] == API.StatusAction.UNSTATUS - ) - targetedId = status.getId(); - else - targetedId = status.getAccount().getId(); - new PostActionAsyncTask(context, statusAction, targetedId, NotificationsListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - dialog.dismiss(); - } - }); - builderInner.show(); - } - }); - builderSingle.create().requestWindowFeature(Window.FEATURE_NO_TITLE); - builderSingle.show(); - } - } \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index 8f65e5883..cede1ca07 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -33,6 +33,7 @@ import android.os.Bundle; import android.os.CountDownTimer; import android.support.v4.content.ContextCompat; import android.support.v7.widget.CardView; +import android.support.v7.widget.PopupMenu; import android.text.Html; import android.text.SpannableString; import android.text.method.LinkMovementMethod; @@ -40,6 +41,7 @@ import android.util.Log; import android.util.Patterns; import android.util.TypedValue; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -76,6 +78,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; + +import fr.gouv.etalab.mastodon.activities.LoginActivity; +import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.activities.MediaActivity; import fr.gouv.etalab.mastodon.activities.ShowAccountActivity; import fr.gouv.etalab.mastodon.activities.ShowConversationActivity; @@ -235,7 +240,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + final String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); //Display a preview for accounts that have replied *if enabled and only for home timeline* if( type == RetrieveFeedsAsyncTask.Type.HOME ) { @@ -856,10 +861,159 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf final View finalConvertView = convertView; + final View attached = holder.status_more; holder.status_more.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - moreOptionDialog(status, finalConvertView); + PopupMenu popup = new PopupMenu(context, attached); + final boolean isOwner = status.getAccount().getId().equals(userId); + popup.getMenuInflater() + .inflate(R.menu.option_toot, popup.getMenu()); + if( status.getVisibility().equals("private") || status.getVisibility().equals("direct")){ + popup.getMenu().findItem(R.id.action_mention).setVisible(false); + } + final String[] stringArrayConf; + if( isOwner) { + popup.getMenu().findItem(R.id.action_block).setVisible(false); + popup.getMenu().findItem(R.id.action_mute).setVisible(false); + popup.getMenu().findItem(R.id.action_report).setVisible(false); + stringArrayConf = context.getResources().getStringArray(R.array.more_action_owner_confirm); + }else { + popup.getMenu().findItem(R.id.action_remove).setVisible(false); + stringArrayConf = context.getResources().getStringArray(R.array.more_action_confirm); + } + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + AlertDialog.Builder builderInner; + final API.StatusAction doAction; + switch (item.getItemId()) { + case R.id.action_remove: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[0]); + doAction = API.StatusAction.UNSTATUS; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); + else + //noinspection deprecation + builderInner.setMessage(Html.fromHtml(status.getContent())); + break; + case R.id.action_mute: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[0]); + doAction = API.StatusAction.MUTE; + break; + case R.id.action_block: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[1]); + doAction = API.StatusAction.BLOCK; + break; + case R.id.action_report: + builderInner = new AlertDialog.Builder(context); + builderInner.setTitle(stringArrayConf[2]); + doAction = API.StatusAction.REPORT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); + else + //noinspection deprecation + builderInner.setMessage(Html.fromHtml(status.getContent())); + break; + case R.id.action_copy: + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + String content; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + content = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); + else + //noinspection deprecation + content = Html.fromHtml(status.getContent()).toString(); + ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content); + clipboard.setPrimaryClip(clip); + Toast.makeText(context,R.string.clipboard,Toast.LENGTH_LONG).show(); + return true; + case R.id.action_share: + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); + sendIntent.putExtra(Intent.EXTRA_TEXT, status.getUrl()); + sendIntent.setType("text/plain"); + context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); + return true; + case R.id.action_mention: + status.setTakingScreenShot(true); + statusListAdapter.notifyDataSetChanged(); + Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + + @Override + public void run() { + Bitmap bitmap = Helper.convertTootIntoBitmap(context, finalConvertView); + status.setTakingScreenShot(false); + statusListAdapter.notifyDataSetChanged(); + Intent intent = new Intent(context, TootActivity.class); + Bundle b = new Bundle(); + String fname = "tootmention_" + status.getId() +".jpg"; + File file = new File (context.getCacheDir() + "/", fname); + if (file.exists ()) //noinspection ResultOfMethodCallIgnored + file.delete (); + try { + FileOutputStream out = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); + out.flush(); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + b.putString("fileMention", fname); + b.putString("tootMention", (status.getReblog() != null)?status.getReblog().getAccount().getAcct():status.getAccount().getAcct()); + b.putString("urlMention", (status.getReblog() != null)?status.getReblog().getUrl():status.getUrl()); + intent.putExtras(b); + context.startActivity(intent); + } + + }, 1000); + return true; + default: + return true; + } + + //Text for report + EditText input = null; + if( doAction == API.StatusAction.REPORT){ + input = new EditText(context); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + input.setLayoutParams(lp); + builderInner.setView(input); + } + builderInner.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog,int which) { + dialog.dismiss(); + } + }); + final EditText finalInput = input; + builderInner.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog,int which) { + if(doAction == API.StatusAction.UNSTATUS ){ + String targetedId = status.getId(); + new PostActionAsyncTask(context, doAction, targetedId, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else if(doAction == API.StatusAction.REPORT ){ + String comment = null; + if( finalInput.getText() != null) + comment = finalInput.getText().toString(); + new PostActionAsyncTask(context, doAction, status.getId(), status, comment, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ + String targetedId = status.getAccount().getId(); + new PostActionAsyncTask(context, doAction, targetedId, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + dialog.dismiss(); + } + }); + builderInner.show(); + return true; + } + }); + popup.show(); } }); @@ -1027,7 +1181,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf @Override - public void onRetrieveFeeds(APIResponse apiResponse, boolean refreshData) { + public void onRetrieveFeeds(APIResponse apiResponse) { if( apiResponse.getError() != null){ final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true); @@ -1330,245 +1484,4 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf }) .show(); } - - /** - * More option for status (report / remove status / Mute / Block) - * @param status Status current status - */ - private void moreOptionDialog(final Status status, final View view){ - - - SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - final boolean isOwner = status.getAccount().getId().equals(userId); - AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); - final String[] stringArray, stringArrayConf; - final API.StatusAction[] doAction; - if( isOwner) { - if( status.getVisibility().equals("private") || status.getVisibility().equals("direct")){ - String[] stringArraytmp = context.getResources().getStringArray(R.array.more_action_owner); - List list = new ArrayList<>(Arrays.asList(stringArraytmp)); - list.remove(3); - stringArray = list.toArray(new String[0]); - String[] stringArrayConftmp = context.getResources().getStringArray(R.array.more_action_owner_confirm); - list = new ArrayList<>(Arrays.asList(stringArrayConftmp)); - list.remove(3); - stringArrayConf = list.toArray(new String[0]); - doAction = new API.StatusAction[]{API.StatusAction.UNSTATUS}; - }else { - stringArray = context.getResources().getStringArray(R.array.more_action_owner); - stringArrayConf = context.getResources().getStringArray(R.array.more_action_owner_confirm); - doAction = new API.StatusAction[]{API.StatusAction.UNSTATUS}; - } - - }else { - if( status.getVisibility().equals("private") || status.getVisibility().equals("direct")){ - String[] stringArraytmp = context.getResources().getStringArray(R.array.more_action); - List list = new ArrayList<>(Arrays.asList(stringArraytmp)); - list.remove(5); - stringArray = list.toArray(new String[0]); - String[] stringArrayConftmp = context.getResources().getStringArray(R.array.more_action_confirm); - list = new ArrayList<>(Arrays.asList(stringArrayConftmp)); - list.remove(5); - stringArrayConf = list.toArray(new String[0]); - doAction = new API.StatusAction[]{API.StatusAction.MUTE, API.StatusAction.BLOCK, API.StatusAction.REPORT}; - }else { - stringArray = context.getResources().getStringArray(R.array.more_action); - stringArrayConf = context.getResources().getStringArray(R.array.more_action_confirm); - doAction = new API.StatusAction[]{API.StatusAction.MUTE, API.StatusAction.BLOCK, API.StatusAction.REPORT}; - } - } - final ArrayAdapter arrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, stringArray); - builderSingle.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - - builderSingle.setAdapter(arrayAdapter, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - AlertDialog.Builder builderInner = new AlertDialog.Builder(context); - builderInner.setTitle(stringArrayConf[which]); - if( isOwner) { - if( which == 0) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); - else - //noinspection deprecation - builderInner.setMessage(Html.fromHtml(status.getContent())); - }else if( which == 1){ - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - String content; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - content = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); - else - //noinspection deprecation - content = Html.fromHtml(status.getContent()).toString(); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content); - clipboard.setPrimaryClip(clip); - Toast.makeText(context,R.string.clipboard,Toast.LENGTH_LONG).show(); - dialog.dismiss(); - return; - }else if( which == 2) { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, status.getUrl()); - sendIntent.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); - return; - }else if( which == 3) { - status.setTakingScreenShot(true); - statusListAdapter.notifyDataSetChanged(); - - - Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - - @Override - public void run() { - Bitmap bitmap = Helper.convertTootIntoBitmap(context, view); - status.setTakingScreenShot(false); - statusListAdapter.notifyDataSetChanged(); - Intent intent = new Intent(context, TootActivity.class); - Bundle b = new Bundle(); - String fname = "tootmention_" + status.getId() +".jpg"; - File file = new File (context.getCacheDir() + "/", fname); - if (file.exists ()) //noinspection ResultOfMethodCallIgnored - file.delete (); - try { - FileOutputStream out = new FileOutputStream(file); - bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); - out.flush(); - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - b.putString("fileMention", fname); - b.putString("tootMention", (status.getReblog() != null)?status.getReblog().getAccount().getAcct():status.getAccount().getAcct()); - b.putString("urlMention", (status.getReblog() != null)?status.getReblog().getUrl():status.getUrl()); - intent.putExtras(b); - context.startActivity(intent); - } - - }, 1000); - return; - } - }else { - if( which < 2 ){ - builderInner.setMessage(status.getAccount().getAcct()); - }else if( which == 2) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - builderInner.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); - else - //noinspection deprecation - builderInner.setMessage(Html.fromHtml(status.getContent())); - }else if( which == 3 ){ - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - String content; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - content = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); - else - //noinspection deprecation - content = Html.fromHtml(status.getContent()).toString(); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, content); - clipboard.setPrimaryClip(clip); - Toast.makeText(context,R.string.clipboard,Toast.LENGTH_LONG).show(); - dialog.dismiss(); - return; - }else if( which == 4 ){ - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, status.getUrl()); - sendIntent.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with))); - return; - }else if( which == 5 ){ - status.setTakingScreenShot(true); - statusListAdapter.notifyDataSetChanged(); - - - Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - - @Override - public void run() { - Bitmap bitmap = Helper.convertTootIntoBitmap(context, view); - status.setTakingScreenShot(false); - statusListAdapter.notifyDataSetChanged(); - Intent intent = new Intent(context, TootActivity.class); - Bundle b = new Bundle(); - String fname = "tootmention_" + status.getId() +".jpg"; - File file = new File (context.getCacheDir() + "/", fname); - if (file.exists ()) //noinspection ResultOfMethodCallIgnored - file.delete (); - try { - FileOutputStream out = new FileOutputStream(file); - bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); - out.flush(); - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - b.putString("fileMention", fname); - b.putString("tootMention", (status.getReblog() != null)?status.getReblog().getAccount().getAcct():status.getAccount().getAcct()); - b.putString("urlMention", (status.getReblog() != null)?status.getReblog().getUrl():status.getUrl()); - intent.putExtras(b); - context.startActivity(intent); - } - - }, 1000); - return; - } - } - //Text for report - EditText input = null; - final int position = which; - if( doAction[which] == API.StatusAction.REPORT){ - input = new EditText(context); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT); - input.setLayoutParams(lp); - builderInner.setView(input); - } - builderInner.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog,int which) { - dialog.dismiss(); - } - }); - final EditText finalInput = input; - builderInner.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog,int which) { - API.StatusAction statusAction = doAction[position]; - if(statusAction == API.StatusAction.REPORT || statusAction == API.StatusAction.CREATESTATUS){ - String comment = null; - if( finalInput != null && finalInput.getText() != null) - comment = finalInput.getText().toString(); - new PostActionAsyncTask(context, statusAction, status.getId(), status, comment, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - }else{ - String targetedId; - if( doAction[position] == API.StatusAction.FAVOURITE || - doAction[position] == API.StatusAction.UNFAVOURITE || - doAction[position] == API.StatusAction.REBLOG || - doAction[position] == API.StatusAction.UNREBLOG || - doAction[position] == API.StatusAction.UNSTATUS - ) - targetedId = status.getId(); - else - targetedId = status.getAccount().getId(); - new PostActionAsyncTask(context, statusAction, targetedId, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - dialog.dismiss(); - } - }); - builderInner.show(); - } - }); - builderSingle.create().requestWindowFeature(Window.FEATURE_NO_TITLE); - builderSingle.show(); - } } \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayNotificationsFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayNotificationsFragment.java index c77db26f3..3245b1d53 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayNotificationsFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayNotificationsFragment.java @@ -19,6 +19,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -30,11 +31,11 @@ import java.util.ArrayList; import java.util.List; import fr.gouv.etalab.mastodon.activities.MainActivity; -import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveMissingNotificationsAsyncTask; import fr.gouv.etalab.mastodon.client.APIResponse; -import fr.gouv.etalab.mastodon.client.Entities.Status; import fr.gouv.etalab.mastodon.drawers.NotificationsListAdapter; import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMissingNotificationsInterface; import mastodon.etalab.gouv.fr.mastodon.R; import fr.gouv.etalab.mastodon.asynctasks.RetrieveNotificationsAsyncTask; import fr.gouv.etalab.mastodon.client.Entities.Notification; @@ -45,7 +46,7 @@ import fr.gouv.etalab.mastodon.interfaces.OnRetrieveNotificationsInterface; * Created by Thomas on 28/04/2017. * Fragment to display notifications related to accounts */ -public class DisplayNotificationsFragment extends Fragment implements OnRetrieveNotificationsInterface { +public class DisplayNotificationsFragment extends Fragment implements OnRetrieveNotificationsInterface, OnRetrieveMissingNotificationsInterface { @@ -62,7 +63,6 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve private ListView lv_notifications; private String lastReadNotifications; private String userId; - public static ArrayList tempNotifications = new ArrayList<>(); public DisplayNotificationsFragment(){ } @@ -155,31 +155,6 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve asyncTask.cancel(true); } - - @Override - public void onResume() { - super.onResume(); - ArrayList knownId = new ArrayList<>(); - for(Notification nt: notifications){ - knownId.add(nt.getId()); - } - for(Notification notification: tempNotifications){ - if( !knownId.contains(notification.getId())) { - int index = lv_notifications.getFirstVisiblePosition() + 1; - View v = lv_notifications.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); - notifications.add(0, notification); - notificationsListAdapter.notifyDataSetChanged(); - lv_notifications.setSelectionFromTop(index, top); - if (textviewNoAction.getVisibility() == View.VISIBLE) - textviewNoAction.setVisibility(View.GONE); - } - } - ((MainActivity)context).updateNotifCounter(); - tempNotifications.clear(); - tempNotifications = new ArrayList<>(); - } - @Override public void onRetrieveNotifications(APIResponse apiResponse, String acct, String userId, boolean refreshData) { final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); @@ -208,13 +183,18 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve lv_notifications.setAdapter(notificationsListAdapter); swiped = false; } + if( notifications != null && notifications.size() > 0) { for(Notification tmpNotification: notifications){ - if( lastReadNotifications != null && Long.parseLong(tmpNotification.getId()) > Long.parseLong(lastReadNotifications)) + if( lastReadNotifications != null && Long.parseLong(tmpNotification.getId()) > Long.parseLong(lastReadNotifications)) { MainActivity.countNewNotifications++; + } this.notifications.add(tmpNotification); } if( firstLoad) { + //Update the id of the last notification retrieved + + MainActivity.lastNotificationId = notifications.get(0).getId(); SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + this.userId, notifications.get(0).getId()); editor.apply(); @@ -230,6 +210,14 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve flag_loading = (max_id == null ); } + /** + * Called from main activity in onResume to retrieve missing notifications + * @param sinceId String + */ + public void retrieveMissingNotifications(String sinceId){ + asyncTask = new RetrieveMissingNotificationsAsyncTask(context, sinceId, DisplayNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + @Override public void setMenuVisibility(final boolean visible) { super.setMenuVisibility(visible); @@ -264,6 +252,8 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve if( context == null) return; if( notification != null){ + //Update the id of the last notification retrieved + MainActivity.lastNotificationId = notification.getId(); int index = lv_notifications.getFirstVisiblePosition() + 1; View v = lv_notifications.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); @@ -275,4 +265,24 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve textviewNoAction.setVisibility(View.GONE); } } + + @Override + public void onRetrieveMissingNotifications(List notifications) { + if( notifications != null && notifications.size() > 0) { + ArrayList knownId = new ArrayList<>(); + for (Notification nt : this.notifications) { + knownId.add(nt.getId()); + } + for (int i = notifications.size()-1 ; i >= 0 ; i--) { + if (!knownId.contains(notifications.get(i).getId())) { + MainActivity.countNewNotifications++; + this.notifications.add(0, notifications.get(i)); + } + } + notificationsListAdapter.notifyDataSetChanged(); + try { + ((MainActivity) context).updateNotifCounter(); + }catch (Exception ignored){} + } + } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java index 1bf472139..b6adb8571 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java @@ -19,6 +19,7 @@ import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v4.content.LocalBroadcastManager; @@ -33,14 +34,21 @@ import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Toast; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; import java.util.List; +import java.util.concurrent.TimeUnit; import fr.gouv.etalab.mastodon.activities.MainActivity; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveMissingFeedsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveRepliesAsyncTask; import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.drawers.StatusListAdapter; import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMissingFeedsInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRepliesInterface; +import fr.gouv.etalab.mastodon.services.StreamingFederatedTimelineService; +import fr.gouv.etalab.mastodon.services.StreamingLocalTimelineService; import mastodon.etalab.gouv.fr.mastodon.R; import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; import fr.gouv.etalab.mastodon.client.Entities.Status; @@ -51,7 +59,7 @@ import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface; * Created by Thomas on 24/04/2017. * Fragment to display content related to status */ -public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsInterface, OnRetrieveRepliesInterface { +public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsInterface, OnRetrieveRepliesInterface, OnRetrieveMissingFeedsInterface { private boolean flag_loading; @@ -75,9 +83,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn private boolean hideHeader; private String instanceValue; private String lastReadStatus; - private String userId; - public static ArrayList tempStatuses = new ArrayList<>(); - private int lastTotalItemCount = 0; + private Intent streamingFederatedIntent, streamingLocalIntent; + private Date lastRefreshPublic, lastRefreshLocal; public DisplayStatusFragment(){ } @@ -119,7 +126,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn positionSpinnerTrans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_YANDEX); swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipeContainer); behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); - userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); if( type == RetrieveFeedsAsyncTask.Type.HOME) lastReadStatus = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null); lv_status = (ListView) rootView.findViewById(R.id.lv_status); @@ -164,6 +171,10 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } if(firstVisibleItem + visibleItemCount == totalItemCount ) { if(!flag_loading ) { + if( type == RetrieveFeedsAsyncTask.Type.PUBLIC) + lastRefreshPublic = new Date(); + if( type == RetrieveFeedsAsyncTask.Type.LOCAL) + lastRefreshLocal = new Date(); flag_loading = true; if( type == RetrieveFeedsAsyncTask.Type.USER) asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -190,6 +201,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn flag_loading = true; swiped = true; MainActivity.countNewStatus = 0; + if( type == RetrieveFeedsAsyncTask.Type.PUBLIC) + lastRefreshPublic = new Date(); if( type == RetrieveFeedsAsyncTask.Type.USER) asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); else if( type == RetrieveFeedsAsyncTask.Type.TAG) @@ -201,13 +214,17 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4, R.color.mastodonC2, R.color.mastodonC3); - + if( type == RetrieveFeedsAsyncTask.Type.PUBLIC) + lastRefreshPublic = new Date(); + if( type == RetrieveFeedsAsyncTask.Type.LOCAL) + lastRefreshLocal = new Date(); if( type == RetrieveFeedsAsyncTask.Type.USER) asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); else if( type == RetrieveFeedsAsyncTask.Type.TAG) asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else + else { asyncTask = new RetrieveFeedsAsyncTask(context, type, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } }else { statusListAdapter.notifyDataSetChanged(); mainLoader.setVisibility(View.GONE); @@ -228,37 +245,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn - @Override - public void onResume() { - super.onResume(); - if( type == RetrieveFeedsAsyncTask.Type.HOME && tempStatuses != null && tempStatuses.size() > 0 ){ - ArrayList knownId = new ArrayList<>(); - for(Status st: statuses){ - knownId.add(st.getId()); - } - for(Status status: tempStatuses){ - if( !knownId.contains(status.getId())){ - int index = lv_status.getFirstVisiblePosition() + 1; - View v = lv_status.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); - status.setReplies(new ArrayList()); - statuses.add(0,status); - statusListAdapter.notifyDataSetChanged(); - lv_status.setSelectionFromTop(index, top); - if (textviewNoAction.getVisibility() == View.VISIBLE) - textviewNoAction.setVisibility(View.GONE); - MainActivity.countNewStatus++; - } - } - if( getActivity() != null && getActivity().getClass().isInstance(MainActivity.class)) - ((MainActivity)context).updateHomeCounter(); - //Resets value for the counter but doesn't update it - MainActivity.countNewStatus = 0; - tempStatuses.clear(); - tempStatuses = new ArrayList<>(); - } - } - @Override public void onAttach(Context context) { super.onAttach(context); @@ -275,7 +261,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn @Override - public void onRetrieveFeeds(APIResponse apiResponse, boolean refreshData) { + public void onRetrieveFeeds(APIResponse apiResponse) { mainLoader.setVisibility(View.GONE); nextElementLoader.setVisibility(View.GONE); //Discards 404 - error which can often happen due to toots which have been deleted @@ -321,6 +307,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } if( firstLoad && type == RetrieveFeedsAsyncTask.Type.HOME) { + //Update the id of the last toot retrieved + MainActivity.lastHomeId = statuses.get(0).getId(); SharedPreferences.Editor editor = sharedpreferences.edit(); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, statuses.get(0).getId()); @@ -347,12 +335,18 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } } + /** + * Deals with new status coming from the streaming api + * @param status Status + */ public void refresh(Status status){ //New data are available - if( type == RetrieveFeedsAsyncTask.Type.HOME ) { + if( type == RetrieveFeedsAsyncTask.Type.HOME) { if (context == null) return; if (status != null) { + //Update the id of the last toot retrieved + MainActivity.lastHomeId = status.getId(); int index = lv_status.getFirstVisiblePosition() + 1; View v = lv_status.getChildAt(0); int top = (v == null) ? 0 : v.getTop(); @@ -367,15 +361,97 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn if (textviewNoAction.getVisibility() == View.VISIBLE) textviewNoAction.setVisibility(View.GONE); } + }else if(type == RetrieveFeedsAsyncTask.Type.PUBLIC || type == RetrieveFeedsAsyncTask.Type.LOCAL){ + if (context == null) + return; + //Avoids the array to be too big... + if (status != null) { + if (lv_status.getFirstVisiblePosition() == 0) { + status.setReplies(new ArrayList()); + status.setNew(false); + statuses.add(0, status); + statusListAdapter.notifyDataSetChanged(); + } else { + status.setReplies(new ArrayList()); + statuses.add(0, status); + } + if (textviewNoAction.getVisibility() == View.VISIBLE) + textviewNoAction.setVisibility(View.GONE); + } } } + @Override + public void onResume(){ + super.onResume(); + if( type == RetrieveFeedsAsyncTask.Type.PUBLIC){ + + if( getUserVisibleHint() ){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, true); + editor.apply(); + streamingFederatedIntent = new Intent(context, StreamingFederatedTimelineService.class); + context.startService(streamingFederatedIntent); + } + Calendar date = Calendar.getInstance(); + long t = date.getTimeInMillis(); + Date newDate = new Date(t - TimeUnit.SECONDS.toMillis(20)); + if( lastRefreshPublic.before(newDate)){ + lastRefreshPublic = new Date(); + max_id = null; + statuses = new ArrayList<>(); + firstLoad = true; + flag_loading = true; + swiped = true; + asyncTask = new RetrieveFeedsAsyncTask(context, type, null, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + }else if (type == RetrieveFeedsAsyncTask.Type.LOCAL){ + + if( getUserVisibleHint() ){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL+userId, true); + editor.apply(); + streamingLocalIntent = new Intent(context, StreamingLocalTimelineService.class); + context.startService(streamingLocalIntent); + } + Calendar date = Calendar.getInstance(); + long t = date.getTimeInMillis(); + Date newDate = new Date(t - TimeUnit.SECONDS.toMillis(20)); + if( lastRefreshLocal.before(newDate)){ + lastRefreshLocal = new Date(); + max_id = null; + statuses = new ArrayList<>(); + firstLoad = true; + flag_loading = true; + swiped = true; + asyncTask = new RetrieveFeedsAsyncTask(context, type, null, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + } + } + + /** + * Called from main activity in onResume to retrieve missing toots (home timeline) + * @param sinceId String + */ + public void retrieveMissingToots(String sinceId){ + asyncTask = new RetrieveMissingFeedsAsyncTask(context, sinceId, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + /** + * When tab comes visible, first displayed toot is defined as read + * @param visible boolean + */ @Override public void setMenuVisibility(final boolean visible) { super.setMenuVisibility(visible); if( context == null) return; - //Store last toot id for home timeline to avoid to notify for those that have been already seen if (type == RetrieveFeedsAsyncTask.Type.HOME && visible && statuses != null && statuses.size() > 0) { SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); @@ -385,6 +461,65 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn lastReadStatus = statuses.get(0).getId(); editor.apply(); } + if( type == RetrieveFeedsAsyncTask.Type.PUBLIC ){ + if (visible) { + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, true); + editor.apply(); + streamingFederatedIntent = new Intent(context, StreamingFederatedTimelineService.class); + context.startService(streamingFederatedIntent); + }else { + if( streamingFederatedIntent != null){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, false); + editor.apply(); + context.stopService(streamingFederatedIntent); + } + } + }else if (type == RetrieveFeedsAsyncTask.Type.LOCAL){ + if (visible) { + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL+userId, true); + editor.apply(); + streamingLocalIntent = new Intent(context, StreamingLocalTimelineService.class); + context.startService(streamingLocalIntent); + }else { + if( streamingLocalIntent != null){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL+userId, false); + editor.apply(); + context.stopService(streamingLocalIntent); + } + } + } + } + + @Override + public void onStop(){ + super.onStop(); + if( type == RetrieveFeedsAsyncTask.Type.PUBLIC && streamingFederatedIntent != null){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, false); + editor.apply(); + context.stopService(streamingFederatedIntent); + }else if(type == RetrieveFeedsAsyncTask.Type.LOCAL && streamingLocalIntent != null){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL+userId, false); + editor.apply(); + context.stopService(streamingLocalIntent); + } } public void scrollToTop(){ @@ -419,4 +554,25 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } statusListAdapter.notifyDataSetChanged(); } + + @Override + public void onRetrieveMissingFeeds(List statuses) { + if( statuses != null && statuses.size() > 0) { + ArrayList knownId = new ArrayList<>(); + for (Status st : this.statuses) { + knownId.add(st.getId()); + } + for (int i = statuses.size()-1 ; i >= 0 ; i--) { + if (!knownId.contains(statuses.get(i).getId())) { + statuses.get(i).setNew(true); + MainActivity.countNewStatus++; + this.statuses.add(0, statuses.get(i)); + } + } + statusListAdapter.notifyDataSetChanged(); + try { + ((MainActivity) context).updateHomeCounter(); + }catch (Exception ignored){} + } + } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index b76eac29e..aafda0942 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -181,6 +181,10 @@ public class Helper { public static final String SHOW_BATTERY_SAVER_MESSAGE = "show_battery_saver_message"; public static final String LAST_NOTIFICATION_MAX_ID = "last_notification_max_id"; public static final String LAST_HOMETIMELINE_MAX_ID = "last_hometimeline_max_id"; + public static final String SHOULD_CONTINUE_STREAMING = "should_continue_streaming"; + public static final String SHOULD_CONTINUE_STREAMING_FEDERATED = "should_continue_streaming_federated"; + public static final String SHOULD_CONTINUE_STREAMING_LOCAL = "should_continue_streaming_local"; + public static final String CLIP_BOARD = "clipboard"; //Notifications public static final int NOTIFICATION_INTENT = 1; @@ -250,9 +254,10 @@ public class Helper { public static final String INTENT_ACTION = "intent_action"; //Receiver - public static final String SEARCH_VALIDATE_ACCOUNT = "search_validate_account"; public static final String HEADER_ACCOUNT = "header_account"; public static final String RECEIVE_DATA = "receive_data"; + public static final String RECEIVE_FEDERATED_DATA = "receive_federated_data"; + public static final String RECEIVE_LOCAL_DATA = "receive_local_data"; public static final String RECEIVE_PICTURE = "receive_picture"; //User agent public static final String USER_AGENT = "Mastalab/"+ BuildConfig.VERSION_NAME + " Android/"+ Build.VERSION.RELEASE; @@ -923,6 +928,8 @@ public class Helper { final NavigationView navigationView = (NavigationView) activity.findViewById(R.id.nav_view); navigationView.getMenu().clear(); + MainActivity.lastNotificationId = null; + MainActivity.lastHomeId = null; navigationView.inflateMenu(R.menu.activity_main_drawer); SQLiteDatabase db = Sqlite.getInstance(activity, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); Account account = new AccountDAO(activity,db).getAccountByID(userID); @@ -937,17 +944,6 @@ public class Helper { } SharedPreferences sharedpreferences = activity.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); String oldUserId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - //User wont' be the same, temp values are cleared - if( oldUserId != null && !oldUserId.equals(userID)){ - if( DisplayStatusFragment.tempStatuses != null) { - DisplayStatusFragment.tempStatuses.clear(); - DisplayStatusFragment.tempStatuses = new ArrayList<>(); - } - if( DisplayNotificationsFragment.tempNotifications != null) { - DisplayNotificationsFragment.tempNotifications.clear(); - DisplayNotificationsFragment.tempNotifications = new ArrayList<>(); - } - } SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, account.getToken()); editor.putString(Helper.PREF_KEY_ID, account.getId()); @@ -967,9 +963,8 @@ public class Helper { final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); - final float roundPx = roundPixelSize; paint.setAntiAlias(true); - canvas.drawRoundRect(rectF,roundPx,roundPx, paint); + canvas.drawRoundRect(rectF, (float) roundPixelSize, (float) roundPixelSize, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveFeedsInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveFeedsInterface.java index d7e656c78..8ca4df95c 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveFeedsInterface.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveFeedsInterface.java @@ -21,5 +21,5 @@ import fr.gouv.etalab.mastodon.client.APIResponse; * Interface when status have been retrieved */ public interface OnRetrieveFeedsInterface { - void onRetrieveFeeds(APIResponse apiResponse, boolean refreshData); + void onRetrieveFeeds(APIResponse apiResponse); } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveMissingFeedsInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveMissingFeedsInterface.java new file mode 100644 index 000000000..9a1147c43 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveMissingFeedsInterface.java @@ -0,0 +1,26 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.interfaces; + +import java.util.List; +import fr.gouv.etalab.mastodon.client.Entities.Status; + +/** + * Created by Thomas on 27/09/2017. + * Interface when missing status have been retrieved + */ +public interface OnRetrieveMissingFeedsInterface { + void onRetrieveMissingFeeds(List statuses); +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveMissingNotificationsInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveMissingNotificationsInterface.java new file mode 100644 index 000000000..4899bb727 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveMissingNotificationsInterface.java @@ -0,0 +1,27 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.interfaces; + +import java.util.List; + +import fr.gouv.etalab.mastodon.client.Entities.Notification; + +/** + * Created by Thomas on 27/09/2017. + * Interface when missing notifications have been retrieved + */ +public interface OnRetrieveMissingNotificationsInterface { + void onRetrieveMissingNotifications(List notifications); +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/RestartFederatedServiceReceiver.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/RestartFederatedServiceReceiver.java new file mode 100644 index 000000000..bf03f9440 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/RestartFederatedServiceReceiver.java @@ -0,0 +1,33 @@ +package fr.gouv.etalab.mastodon.services; +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * Created by Thomas on 26/09/2017. + * BroadcastReceiver for restarting the service for listening federated timeline + */ + +public class RestartFederatedServiceReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Intent streamingServiceIntent = new Intent(context.getApplicationContext(), StreamingFederatedTimelineService.class); + context.startService(streamingServiceIntent); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/RestartLocalServiceReceiver.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/RestartLocalServiceReceiver.java new file mode 100644 index 000000000..5c0809c86 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/RestartLocalServiceReceiver.java @@ -0,0 +1,33 @@ +package fr.gouv.etalab.mastodon.services; +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * Created by Thomas on 29/09/2017. + * BroadcastReceiver for restarting the service for listening local timeline + */ + +public class RestartLocalServiceReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Intent streamingServiceIntent = new Intent(context.getApplicationContext(), StreamingLocalTimelineService.class); + context.startService(streamingServiceIntent); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingFederatedTimelineService.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingFederatedTimelineService.java new file mode 100644 index 000000000..d6423f3d2 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingFederatedTimelineService.java @@ -0,0 +1,172 @@ +package fr.gouv.etalab.mastodon.services; +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.os.SystemClock; +import android.support.annotation.Nullable; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; + +import javax.net.ssl.HttpsURLConnection; + +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.Entities.Account; +import fr.gouv.etalab.mastodon.client.Entities.Notification; +import fr.gouv.etalab.mastodon.client.Entities.Status; +import fr.gouv.etalab.mastodon.client.TLSSocketFactory; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.sqlite.AccountDAO; +import fr.gouv.etalab.mastodon.sqlite.Sqlite; + + +/** + * Created by Thomas on 26/09/2017. + * Manage service for streaming api for federated timeline + */ + +public class StreamingFederatedTimelineService extends IntentService { + + + /** + * Creates an IntentService. Invoked by your subclass's constructor. + * + * @param name Used to name the worker thread, important only for debugging. + */ + public StreamingFederatedTimelineService(String name) { + super(name); + } + public StreamingFederatedTimelineService() { + super("StreamingFederatedTimelineService"); + } + + private static HttpsURLConnection httpsURLConnection; + protected Account account; + + public void onCreate() { + super.onCreate(); + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean display_global = sharedpreferences.getBoolean(Helper.SET_DISPLAY_GLOBAL, true); + if( !display_global){ + stopSelf(); + } + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, true); + editor.apply(); + } + + + @Override + protected void onHandleIntent(@Nullable Intent intent) { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + InputStream inputStream; + BufferedReader reader = null; + Account accountStream = null; + if( httpsURLConnection != null) + httpsURLConnection.disconnect(); + if( userId != null) { + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + accountStream = new AccountDAO(getApplicationContext(), db).getAccountByID(userId); + } + if( accountStream != null){ + try { + + URL url = new URL("https://" + accountStream.getInstance() + "/api/v1/streaming/public"); + httpsURLConnection = (HttpsURLConnection) url.openConnection(); + httpsURLConnection.setRequestProperty("Content-Type", "application/json"); + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + accountStream.getToken()); + httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); + httpsURLConnection.setRequestProperty("Keep-Alive", "header"); + httpsURLConnection.setRequestProperty("Connection", "close"); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + httpsURLConnection.setRequestMethod("GET"); + httpsURLConnection.setConnectTimeout(70000); + httpsURLConnection.setReadTimeout(70000); + inputStream = new BufferedInputStream(httpsURLConnection.getInputStream()); + reader = new BufferedReader(new InputStreamReader(inputStream)); + String event; + while((event = reader.readLine()) != null) { + if (!event.startsWith("data: ")) { + continue; + } + + if (!sharedpreferences.getBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED + accountStream.getId(), true)) { + stopSelf(); + return; + } + event = event.substring(6); + if( event.matches("^[0-9]{1,}$")) + continue; + try { + JSONObject eventJson = new JSONObject(event); + onRetrieveStreaming(accountStream, eventJson); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } catch (Exception e) { + e.printStackTrace(); + }finally { + if(reader != null){ + try{ + reader.close(); + }catch (IOException e){ + e.printStackTrace(); + } + } + if( sharedpreferences.getBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED + accountStream.getId(), true)) { + SystemClock.sleep(1000); + sendBroadcast(new Intent("RestartStreamingFederatedService")); + } + } + } + } + + public void onRetrieveStreaming(Account account, JSONObject response) { + if( response == null ) + return; + Status status ; + Bundle b = new Bundle(); + status = API.parseStatuses(getApplicationContext(), response); + status.setReplies(new ArrayList()); + status.setNew(true); + b.putParcelable("data", status); + if( account != null) + b.putString("userIdService",account.getId()); + Intent intentBC = new Intent(Helper.RECEIVE_FEDERATED_DATA); + intentBC.putExtras(b); + LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentBC); + } + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingLocalTimelineService.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingLocalTimelineService.java new file mode 100644 index 000000000..e4ad29d3a --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingLocalTimelineService.java @@ -0,0 +1,169 @@ +package fr.gouv.etalab.mastodon.services; +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.os.SystemClock; +import android.support.annotation.Nullable; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; + +import javax.net.ssl.HttpsURLConnection; + +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.Entities.Account; +import fr.gouv.etalab.mastodon.client.Entities.Status; +import fr.gouv.etalab.mastodon.client.TLSSocketFactory; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.sqlite.AccountDAO; +import fr.gouv.etalab.mastodon.sqlite.Sqlite; + + +/** + * Created by Thomas on 29/09/2017. + * Manage service for streaming api for local timeline + */ + +public class StreamingLocalTimelineService extends IntentService { + + + /** + * Creates an IntentService. Invoked by your subclass's constructor. + * + * @param name Used to name the worker thread, important only for debugging. + */ + public StreamingLocalTimelineService(String name) { + super(name); + } + public StreamingLocalTimelineService() { + super("StreamingLocalTimelineService"); + } + + private static HttpsURLConnection httpsURLConnection; + protected Account account; + + public void onCreate() { + super.onCreate(); + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean display_local = sharedpreferences.getBoolean(Helper.SET_DISPLAY_LOCAL, true); + if( !display_local){ + stopSelf(); + } + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL+userId, true); + editor.apply(); + } + + + @Override + protected void onHandleIntent(@Nullable Intent intent) { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + InputStream inputStream; + BufferedReader reader = null; + Account accountStream = null; + if( httpsURLConnection != null) + httpsURLConnection.disconnect(); + if( userId != null) { + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + accountStream = new AccountDAO(getApplicationContext(), db).getAccountByID(userId); + } + if( accountStream != null){ + try { + + URL url = new URL("https://" + accountStream.getInstance() + "/api/v1/streaming/public/local"); + httpsURLConnection = (HttpsURLConnection) url.openConnection(); + httpsURLConnection.setRequestProperty("Content-Type", "application/json"); + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + accountStream.getToken()); + httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); + httpsURLConnection.setRequestProperty("Keep-Alive", "header"); + httpsURLConnection.setRequestProperty("Connection", "close"); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + httpsURLConnection.setRequestMethod("GET"); + httpsURLConnection.setConnectTimeout(70000); + httpsURLConnection.setReadTimeout(70000); + inputStream = new BufferedInputStream(httpsURLConnection.getInputStream()); + reader = new BufferedReader(new InputStreamReader(inputStream)); + String event; + while((event = reader.readLine()) != null) { + if (!event.startsWith("data: ")) { + continue; + } + if (!sharedpreferences.getBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL + accountStream.getId(), true)) { + stopSelf(); + return; + } + event = event.substring(6); + if( event.matches("^[0-9]{1,}$")) + continue; + try { + JSONObject eventJson = new JSONObject(event); + onRetrieveStreaming(accountStream, eventJson); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } catch (Exception e) { + e.printStackTrace(); + }finally { + if(reader != null){ + try{ + reader.close(); + }catch (IOException e){ + e.printStackTrace(); + } + } + if( sharedpreferences.getBoolean(Helper.SHOULD_CONTINUE_STREAMING_LOCAL + accountStream.getId(), true)) { + SystemClock.sleep(1000); + sendBroadcast(new Intent("RestartStreamingLocalService")); + } + } + } + } + + public void onRetrieveStreaming(Account account, JSONObject response) { + if( response == null ) + return; + Status status ; + Bundle b = new Bundle(); + status = API.parseStatuses(getApplicationContext(), response); + status.setReplies(new ArrayList()); + status.setNew(true); + b.putParcelable("data", status); + if( account != null) + b.putString("userIdService",account.getId()); + Intent intentBC = new Intent(Helper.RECEIVE_LOCAL_DATA); + intentBC.putExtras(b); + LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentBC); + } + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingService.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingService.java index c7bfd8278..e2fede163 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingService.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingService.java @@ -22,6 +22,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; import org.json.JSONException; @@ -55,7 +56,6 @@ public class StreamingService extends IntentService { private EventStreaming lastEvent; - /** * Creates an IntentService. Invoked by your subclass's constructor. * @@ -79,6 +79,11 @@ public class StreamingService extends IntentService { public void onCreate() { super.onCreate(); + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING+userId, true); + editor.apply(); } @@ -114,6 +119,8 @@ public class StreamingService extends IntentService { String event; EventStreaming eventStreaming; while((event = reader.readLine()) != null) { + if( !sharedpreferences.getBoolean(Helper.SHOULD_CONTINUE_STREAMING + accountStream.getId(), true) ) + stopSelf(); if ((lastEvent == EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) { switch (event.trim()) { case "event: update": diff --git a/app/src/main/res/menu/option_toot.xml b/app/src/main/res/menu/option_toot.xml new file mode 100644 index 000000000..eb8ccd95d --- /dev/null +++ b/app/src/main/res/menu/option_toot.xml @@ -0,0 +1,32 @@ + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9badd4ae4..8083a0d37 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -98,28 +98,23 @@ Toot nicht mehr teilen? Diesen toot anheften? Diesen toot nicht mehr anheften? - - Stummschalten - Blockieren - Melden - Kopieren - Teilen - Erwähnen - - - Entfernen - Kopieren - Teilen - Erwähnen - + + + + + Stummschalten + Blockieren + Melden + Entfernen + Kopieren + Teilen + Erwähnen + Nutzer stummschalten? Diesen Nutzer blockieren? Diesen toot melden? - null - null - null @@ -130,9 +125,6 @@ Entferne diesen toot? - null - null - null diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c71843bf8..25bec6926 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -96,28 +96,23 @@ Supprimer ce pouet des favoris ? Partager ce pouet ? Supprimer ce pouet des partages ? - - Masquer - Bloquer - Signaler - Copier - Partager - Mentionner - - - Supprimer - Copier - Partager - Mentionner - + + + + Masquer + Bloquer + Signaler + Supprimer + Copier + Partager + Mentionner + + Masquer ce compte ? Bloquer ce compte ? Signaler ce pouet ? - null - null - null @@ -128,9 +123,6 @@ Supprimer ce pouet ? - null - null - null diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f9e324227..438166a5f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,33 +107,25 @@ Share Mention - - Remove - Copy - Share - Mention - + + + Mute + Block + Report + Remove + Copy + Share + Mention Mute this account? Block this account? Report this toot? - null - null - null - - Unmute this account? - Unblock this account? - - Remove this toot? - null - null - null diff --git a/app/src/safetynet/java/fr.gouv.etalab.mastodon/activities/MainActivity.java b/app/src/safetynet/java/fr.gouv.etalab.mastodon/activities/MainActivity.java index 6a273039b..6fde91392 100644 --- a/app/src/safetynet/java/fr.gouv.etalab.mastodon/activities/MainActivity.java +++ b/app/src/safetynet/java/fr.gouv.etalab.mastodon/activities/MainActivity.java @@ -101,8 +101,6 @@ import fr.gouv.etalab.mastodon.fragments.TabLayoutSettingsFragment; import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import mastodon.etalab.gouv.fr.mastodon.R; -import static fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment.tempNotifications; -import static fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment.tempStatuses; import static fr.gouv.etalab.mastodon.helper.Helper.CHANGE_THEME_INTENT; import static fr.gouv.etalab.mastodon.helper.Helper.CHANGE_USER_INTENT; import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT; @@ -134,16 +132,16 @@ public class MainActivity extends AppCompatActivity private RelativeLayout main_app_container; private Stack stackBack = new Stack<>(); - private DisplayStatusFragment homeFragment; + private DisplayStatusFragment homeFragment, federatedFragment, localFragment; private DisplayNotificationsFragment notificationsFragment; private static final int ERROR_DIALOG_REQUEST_CODE = 97; - private BroadcastReceiver receive_data; + private BroadcastReceiver receive_data, receive_federated_data, receive_local_data; private boolean display_local, display_global; public static int countNewStatus = 0; public static int countNewNotifications = 0; private String userIdService; private Intent streamingIntent; - public static boolean broadCastRegistred = false; + public static String lastHomeId = null, lastNotificationId = null; public MainActivity() { } @@ -154,53 +152,9 @@ public class MainActivity extends AppCompatActivity final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - receive_data = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Bundle b = intent.getExtras(); - StreamingService.EventStreaming eventStreaming = (StreamingService.EventStreaming) intent.getSerializableExtra("eventStreaming"); - userIdService = b.getString("userIdService", null); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - if( userIdService != null && userIdService.equals(userId)) { - if (eventStreaming == StreamingService.EventStreaming.NOTIFICATION) { - Notification notification = b.getParcelable("data"); - if (notificationsFragment != null) { - notificationsFragment.refresh(notification); - } else { - tempNotifications.add(notification); - } - } else if (eventStreaming == StreamingService.EventStreaming.UPDATE) { - Status status = b.getParcelable("data"); - if (homeFragment != null) { - homeFragment.refresh(status); - } else { - tempStatuses.add(status); - } - } else if (eventStreaming == StreamingService.EventStreaming.DELETE) { - String id = b.getString("id"); - if (notificationsFragment != null) { - if (notificationsFragment.getUserVisibleHint()) { - } else { - - } - } - } - updateNotifCounter(); - updateHomeCounter(); - } - } - }; - streamingIntent = new Intent(this, StreamingService.class); - startService(streamingIntent); - - if( !broadCastRegistred) { - LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA)); - broadCastRegistred = true; - } ProviderInstaller.installIfNeededAsync(this, this); - final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); if( theme == Helper.THEME_LIGHT){ setTheme(R.style.AppTheme_NoActionBar); @@ -756,6 +710,12 @@ public class MainActivity extends AppCompatActivity matchingIntent = true; }else if( extras.getInt(INTENT_ACTION) == CHANGE_USER_INTENT){ unCheckAllMenuItems(navigationView); + if( tabLayout.getTabAt(0) != null) + //noinspection ConstantConditions + tabLayout.getTabAt(0).select(); + if( !toolbar_search.isIconified() ) { + toolbar_search.setIconified(true); + } matchingIntent = true; } }else if( Intent.ACTION_SEND.equals(action) && type != null ) { @@ -898,10 +858,105 @@ public class MainActivity extends AppCompatActivity //Proceeds to update of the authenticated account if(Helper.isLoggedIn(getApplicationContext())) new UpdateAccountInfoByIDAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if( lastHomeId != null && homeFragment != null){ + homeFragment.retrieveMissingToots(lastHomeId); + } + if( lastNotificationId != null && notificationsFragment != null){ + notificationsFragment.retrieveMissingNotifications(lastNotificationId); + } } + @Override + public void onStart(){ + super.onStart(); + final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + receive_federated_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + userIdService = b.getString("userIdService", null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if( userIdService != null && userIdService.equals(userId)) { + Status status = b.getParcelable("data"); + if (federatedFragment != null) { + federatedFragment.refresh(status); + } + } + } + }; + receive_local_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + userIdService = b.getString("userIdService", null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if( userIdService != null && userIdService.equals(userId)) { + Status status = b.getParcelable("data"); + if (localFragment != null) { + localFragment.refresh(status); + } + } + } + }; + receive_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + StreamingService.EventStreaming eventStreaming = (StreamingService.EventStreaming) intent.getSerializableExtra("eventStreaming"); + userIdService = b.getString("userIdService", null); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if( userIdService != null && userIdService.equals(userId)) { + if (eventStreaming == StreamingService.EventStreaming.NOTIFICATION) { + Notification notification = b.getParcelable("data"); + if (notificationsFragment != null) { + notificationsFragment.refresh(notification); + } + } else if (eventStreaming == StreamingService.EventStreaming.UPDATE) { + Status status = b.getParcelable("data"); + if (homeFragment != null) { + homeFragment.refresh(status); + } + } else if (eventStreaming == StreamingService.EventStreaming.DELETE) { + String id = b.getString("id"); + if (notificationsFragment != null) { + if (notificationsFragment.getUserVisibleHint()) { + } else { + + } + } + } + updateNotifCounter(); + updateHomeCounter(); + } + } + }; + streamingIntent = new Intent(this, StreamingService.class); + startService(streamingIntent); + LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA)); + LocalBroadcastManager.getInstance(this).registerReceiver(receive_federated_data, new IntentFilter(Helper.RECEIVE_FEDERATED_DATA)); + LocalBroadcastManager.getInstance(this).registerReceiver(receive_local_data, new IntentFilter(Helper.RECEIVE_LOCAL_DATA)); + } + + @Override + public void onStop(){ + super.onStop(); + if( streamingIntent != null) { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_FEDERATED+userId, false); + stopService(streamingIntent); + editor.apply(); + } + if( receive_data != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data); + if( receive_federated_data != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_federated_data); + if( receive_local_data != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_local_data); + } @Override protected void onPause() { @@ -912,10 +967,6 @@ public class MainActivity extends AppCompatActivity @Override public void onDestroy(){ super.onDestroy(); - if( streamingIntent != null) - stopService(streamingIntent); - LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data); - broadCastRegistred = false; } @SuppressWarnings("StatementWithEmptyBody") @@ -1168,6 +1219,16 @@ public class MainActivity extends AppCompatActivity case 1: notificationsFragment = (DisplayNotificationsFragment) createdFragment; break; + case 2: + if ( !display_local && display_global) + federatedFragment = (DisplayStatusFragment) createdFragment; + if( display_local) + localFragment = (DisplayStatusFragment) createdFragment; + break; + case 3: + if( display_local && display_global) + federatedFragment = (DisplayStatusFragment) createdFragment; + break; } return createdFragment; }