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 da5a9ae3e..a31d8b211 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 @@ -15,9 +15,11 @@ package fr.gouv.etalab.mastodon.activities; import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.graphics.PorterDuff; @@ -31,6 +33,7 @@ import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; +import android.support.v4.content.LocalBroadcastManager; import android.support.v4.view.ViewPager; import android.support.v7.app.AlertDialog; import android.support.v7.widget.SearchView; @@ -67,8 +70,11 @@ import java.util.Locale; import java.util.Stack; import java.util.concurrent.TimeUnit; +import fr.gouv.etalab.mastodon.asynctasks.StreamingUserAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoByIDAsyncTask; 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.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.fragments.DisplayAccountsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayFollowRequestSentFragment; @@ -76,6 +82,7 @@ import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayScheduledTootsFragment; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnUpdateAccountInfoInterface; +import fr.gouv.etalab.mastodon.services.StreamingService; import fr.gouv.etalab.mastodon.sqlite.Sqlite; import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; @@ -119,14 +126,53 @@ public class MainActivity extends AppCompatActivity private DisplayStatusFragment homeFragment; private DisplayNotificationsFragment notificationsFragment; - - + private BroadcastReceiver receive_data; + private int newNotif, newHome; public MainActivity() { } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + receive_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + StreamingUserAsyncTask.EventStreaming eventStreaming = (StreamingUserAsyncTask.EventStreaming) intent.getSerializableExtra("eventStreaming"); + + if( eventStreaming == StreamingUserAsyncTask.EventStreaming.NOTIFICATION){ + Notification notification = b.getParcelable("data"); + if(notificationsFragment != null && notificationsFragment.getUserVisibleHint()){ + notificationsFragment.updateData(notification); + }else{ + newNotif++; + updateNotifCounter(); + notificationsFragment.updateData(notification); + } + }else if(eventStreaming == StreamingUserAsyncTask.EventStreaming.UPDATE){ + Status status = b.getParcelable("data"); + if(homeFragment != null && homeFragment.getUserVisibleHint()){ + homeFragment.updateData(status); + }else{ + newHome++; + updateHomeCounter(); + homeFragment.updateData(status); + } + }else if(eventStreaming == StreamingUserAsyncTask.EventStreaming.DELETE){ + String id = b.getString("id"); + if(notificationsFragment != null && notificationsFragment.getUserVisibleHint()){ + + }else{ + + } + } + } + }; + LocalBroadcastManager.getInstance(this).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA)); + + newNotif = 0; + newHome = 0; + final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); @@ -145,7 +191,7 @@ public class MainActivity extends AppCompatActivity finish(); return; } - + startService(new Intent(getApplicationContext(), StreamingService.class)); Helper.fillMapEmoji(getApplicationContext()); //Here, the user is authenticated Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); @@ -203,7 +249,6 @@ public class MainActivity extends AppCompatActivity (getSupportFragmentManager(), tabLayout.getTabCount()); viewPager.setAdapter(adapter); viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); - final boolean bubbles = sharedpreferences.getBoolean(Helper.SET_BUBBLE_COUNTER, true); tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { @@ -226,16 +271,19 @@ public class MainActivity extends AppCompatActivity case 0: item = navigationView.getMenu().findItem(R.id.nav_home); fragmentTag = "HOME_TIMELINE"; - if( bubbles && homeFragment != null) - homeFragment.refreshData(); - updateHomeCounter(0); + newHome = 0; + if( homeFragment != null) + homeFragment.refresh(); + updateHomeCounter(); break; case 1: fragmentTag = "NOTIFICATIONS"; item = navigationView.getMenu().findItem(R.id.nav_notification); - updateNotifCounter(0); - if( bubbles && notificationsFragment != null) - notificationsFragment.refreshData(); + newNotif = 0; + + if( notificationsFragment != null) + notificationsFragment.refresh(); + updateNotifCounter(); break; case 2: fragmentTag = "LOCAL_TIMELINE"; @@ -805,22 +853,23 @@ public class MainActivity extends AppCompatActivity @Override public void onResume(){ super.onResume(); - SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - boolean bubbles = sharedpreferences.getBoolean(Helper.SET_BUBBLE_COUNTER, true); - if( bubbles){ - Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() {refreshData();} - }, 1000); - } + MainActivity.activityResumed(); //Proceeds to update of the authenticated account if(Helper.isLoggedIn(getApplicationContext())) new UpdateAccountInfoByIDAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + @Override + protected void onPause() { + super.onPause(); + MainActivity.activityPaused(); + } - + @Override + public void onDestroy(){ + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(receive_data); + } @SuppressWarnings("StatementWithEmptyBody") @Override @@ -1008,40 +1057,8 @@ public class MainActivity extends AppCompatActivity } } - private void refreshData(){ - final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - String prefKeyOauthTokenT = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); - SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - Account account = new AccountDAO(getApplicationContext(), db).getAccountByToken(prefKeyOauthTokenT); - if( account != null){ - String last_refresh = sharedpreferences.getString(Helper.LAST_BUBBLE_REFRESH_NOTIF + account.getId(), null); - Date last_refresh_date = Helper.stringToDate(getApplicationContext(), last_refresh); - if (last_refresh_date == null || (new Date().getTime() - last_refresh_date.getTime()) >= TimeUnit.SECONDS.toMillis(60)) { - - if( notificationsFragment != null ){ - notificationsFragment.update(); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ account.getId(),Helper.dateToString(getApplicationContext(), new Date())); - editor.apply(); - } - } - - last_refresh = sharedpreferences.getString(Helper.LAST_BUBBLE_REFRESH_HOME + account.getId(), null); - last_refresh_date = Helper.stringToDate(getApplicationContext(), last_refresh); - - if (last_refresh_date == null || (new Date().getTime() - last_refresh_date.getTime()) >= TimeUnit.SECONDS.toMillis(60)) { - if( homeFragment != null ){ - homeFragment.update(); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_BUBBLE_REFRESH_HOME+ account.getId(),Helper.dateToString(getApplicationContext(), new Date())); - editor.apply(); - } - } - } - } - - public void updateHomeCounter(int newHomeCount){ + public void updateHomeCounter(){ if( tabLayout.getTabAt(0) == null ) return; //noinspection ConstantConditions @@ -1049,8 +1066,8 @@ public class MainActivity extends AppCompatActivity if( tabHome == null) return; TextView tabCounterHome = (TextView) tabHome.findViewById(R.id.tab_counter); - tabCounterHome.setText(String.valueOf(newHomeCount)); - if( newHomeCount > 0){ + tabCounterHome.setText(String.valueOf(newHome)); + if( newHome > 0){ //New data are available //The fragment is not displayed, so the counter is displayed if( tabLayout.getSelectedTabPosition() != 0) @@ -1062,7 +1079,7 @@ public class MainActivity extends AppCompatActivity } } - public void updateNotifCounter(int newNotifCount){ + public void updateNotifCounter(){ if(tabLayout.getTabAt(1) == null) return; //noinspection ConstantConditions @@ -1070,8 +1087,8 @@ public class MainActivity extends AppCompatActivity if( tabNotif == null) return; TextView tabCounterNotif = (TextView) tabNotif.findViewById(R.id.tab_counter); - tabCounterNotif.setText(String.valueOf(newNotifCount)); - if( newNotifCount > 0){ + tabCounterNotif.setText(String.valueOf(newNotif)); + if( newNotif > 0){ if( tabLayout.getSelectedTabPosition() != 1) tabCounterNotif.setVisibility(View.VISIBLE); else @@ -1081,4 +1098,18 @@ public class MainActivity extends AppCompatActivity } } + public static boolean isActivityVisible() { + return activityVisible; + } + + private static void activityResumed() { + activityVisible = true; + } + + private static void activityPaused() { + activityVisible = false; + } + + private static boolean activityVisible; + } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 72d3b2012..5c0910447 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,9 @@ android:roundIcon="@mipmap/ic_launcher" android:supportsRtl="true" android:theme="@style/AppThemeDark"> + { this.max_id = max_id; this.listener = onRetrieveFeedsInterface; this.refreshData = true; - updateTimeRefresh(); - } public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ @@ -73,7 +66,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { this.targetedID = targetedID; this.showMediaOnly = showMediaOnly; this.refreshData = true; - updateTimeRefresh(); } public RetrieveFeedsAsyncTask(Context context, Type action, String tag, String targetedID, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ this.context = context; @@ -83,17 +75,8 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { this.targetedID = targetedID; this.tag = tag; this.refreshData = true; - updateTimeRefresh(); } - public RetrieveFeedsAsyncTask(Context context, Type action, String max_id, boolean refreshData, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ - this.context = context; - this.action = action; - this.max_id = max_id; - this.listener = onRetrieveFeedsInterface; - this.refreshData = refreshData; - updateTimeRefresh(); - } @Override protected Void doInBackground(Void... params) { @@ -134,14 +117,4 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { protected void onPostExecute(Void result) { listener.onRetrieveFeeds(apiResponse, refreshData); } - - private void updateTimeRefresh(){ - if( action == Type.HOME) { - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - editor.putString(Helper.LAST_BUBBLE_REFRESH_HOME + userId, Helper.dateToString(context, new Date())); - editor.apply(); - } - } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveNotificationsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveNotificationsAsyncTask.java index e59bb8417..6b7a8b7c6 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveNotificationsAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveNotificationsAsyncTask.java @@ -15,14 +15,9 @@ package fr.gouv.etalab.mastodon.asynctasks; import android.content.Context; -import android.content.SharedPreferences; import android.os.AsyncTask; - -import java.util.Date; - 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.OnRetrieveNotificationsInterface; @@ -51,20 +46,8 @@ public class RetrieveNotificationsAsyncTask extends AsyncTask this.userId = userId; this.token = token; this.refreshData = true; - updateTimeRefresh(); } - public RetrieveNotificationsAsyncTask(Context context, String instance, String token, String max_id, String acct, String userId, boolean refreshData, OnRetrieveNotificationsInterface onRetrieveNotificationsInterface){ - this.context = context; - this.max_id = max_id; - this.listener = onRetrieveNotificationsInterface; - this.acct = acct; - this.instance = instance; - this.userId = userId; - this.token = token; - this.refreshData = refreshData; - updateTimeRefresh(); - } @Override protected Void doInBackground(Void... params) { @@ -82,10 +65,4 @@ public class RetrieveNotificationsAsyncTask extends AsyncTask listener.onRetrieveNotifications(apiResponse, acct, userId, refreshData); } - private void updateTimeRefresh(){ - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ userId,Helper.dateToString(context, new Date())); - editor.apply(); - } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/StreamingUserAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/StreamingUserAsyncTask.java new file mode 100644 index 000000000..333ca8a8a --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/StreamingUserAsyncTask.java @@ -0,0 +1,153 @@ +/* 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.os.AsyncTask; +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.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; + +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveStreamingInterface; + + +/** + * Created by Thomas on 28/08/2017. + * Calls user streaming api + */ + +public class StreamingUserAsyncTask extends AsyncTask { + + private String instance, token, acct, userId; + private OnRetrieveStreamingInterface listener; + private static HashMap connectionHashMap; + private EventStreaming lastEvent; + + + public StreamingUserAsyncTask(String instance, String token, String acct, String userId, OnRetrieveStreamingInterface onRetrieveStreamingInterface){ + this.instance = instance; + this.token = token; + this.acct = acct; + this.userId = userId; + this.listener = onRetrieveStreamingInterface; + } + public enum EventStreaming{ + UPDATE, + NOTIFICATION, + DELETE, + NONE + } + + + @Override + protected Object doInBackground(Object[] params){ + if( connectionHashMap == null) + connectionHashMap = new HashMap<>(); + + boolean connectionAlive = false; + if( connectionHashMap.get(acct+userId) != null) { + try { + connectionAlive = (connectionHashMap.get(acct + userId).getResponseCode() == 200); + } catch (IOException e) { + connectionAlive = false; + } + } + + if( !connectionAlive) { + try { + URL url = new URL("https://" + this.instance + "/api/v1/streaming/user"); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setRequestProperty("Content-Type", "application/json"); + urlConnection.setRequestProperty("Authorization", "Bearer " + this.token); + urlConnection.setRequestProperty("Connection", "Keep-Alive"); + urlConnection.setRequestProperty("Keep-Alive", "header"); + connectionHashMap.put(acct+userId, urlConnection); + + InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream()); + readStream(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + private String readStream(InputStream inputStream) { + BufferedReader reader = null; + try{ + reader = new BufferedReader(new InputStreamReader(inputStream)); + String event; + EventStreaming eventStreaming = null; + while((event = reader.readLine()) != null){ + if( lastEvent == EventStreaming.NONE || lastEvent == null) { + switch (event.trim()) { + case "event: update": + lastEvent = EventStreaming.UPDATE; + break; + case "event: notification": + lastEvent = EventStreaming.NOTIFICATION; + break; + case "event: delete": + lastEvent = EventStreaming.DELETE; + break; + default: + lastEvent = EventStreaming.NONE; + } + }else{ + event = event.replace("data: ",""); + if(lastEvent == EventStreaming.UPDATE) { + eventStreaming = EventStreaming.UPDATE; + }else if(lastEvent == EventStreaming.NOTIFICATION) { + eventStreaming = EventStreaming.NOTIFICATION; + }else if( lastEvent == EventStreaming.DELETE) { + eventStreaming = EventStreaming.DELETE; + event = "{id:" + event + "}"; + } + lastEvent = EventStreaming.NONE; + try { + JSONObject eventJson = new JSONObject(event); + listener.onRetrieveStreaming(eventStreaming, eventJson, acct, userId); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + } + }catch (Exception e){ + e.printStackTrace(); + }finally { + if(reader != null){ + try{ + reader.close(); + }catch (IOException e){ + e.printStackTrace(); + } + } + } + return null; + } + +} 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 baa7b2d60..312c42e4b 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 @@ -188,12 +188,12 @@ public class API { get("/accounts/verify_credentials", null, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - account = parseAccountResponse(response); + account = parseAccountResponse(context, response); } @Override public void onSuccess(int statusCode, Header[] headers, JSONArray response) { try { - account = parseAccountResponse(response.getJSONObject(0)); + account = parseAccountResponse(context, response.getJSONObject(0)); } catch (JSONException e) { e.printStackTrace(); } @@ -217,12 +217,12 @@ public class API { get(String.format("/accounts/%s",accountId), null, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - account = parseAccountResponse(response); + account = parseAccountResponse(context, response); } @Override public void onSuccess(int statusCode, Header[] headers, JSONArray response) { try { - account = parseAccountResponse(response.getJSONObject(0)); + account = parseAccountResponse(context, response.getJSONObject(0)); } catch (JSONException e) { e.printStackTrace(); } @@ -330,7 +330,7 @@ public class API { get(String.format("/accounts/%s/statuses", accountId), params, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Status status = parseStatuses(response); + Status status = parseStatuses(context, response); statuses.add(status); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -365,7 +365,7 @@ public class API { public void onSuccess(int statusCode, Header[] headers, JSONObject response) { apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); - Status status = parseStatuses(response); + Status status = parseStatuses(context, response); statuses.add(status); } @Override @@ -445,7 +445,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Status status = parseStatuses(response); + Status status = parseStatuses(context, response); statuses.add(status); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -500,7 +500,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Status status = parseStatuses(response); + Status status = parseStatuses(context, response); statuses.add(status); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -557,7 +557,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Status status = parseStatuses(response); + Status status = parseStatuses(context, response); statuses.add(status); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -641,7 +641,7 @@ public class API { public void onSuccess(int statusCode, Header[] headers, JSONObject response) { apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); - Account account = parseAccountResponse(response); + Account account = parseAccountResponse(context, response); accounts.add(account); } @Override @@ -692,7 +692,7 @@ public class API { public void onSuccess(int statusCode, Header[] headers, JSONObject response) { apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); - Account account = parseAccountResponse(response); + Account account = parseAccountResponse(context, response); accounts.add(account); } @Override @@ -741,7 +741,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Status status = parseStatuses(response); + Status status = parseStatuses(context, response); statuses.add(status); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -945,7 +945,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Status statusreturned = parseStatuses(response); + Status statusreturned = parseStatuses(context, response); statuses.add(statusreturned); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -1041,7 +1041,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Notification notification = parseNotificationResponse(response); + Notification notification = parseNotificationResponse(context, response); notifications.add(notification); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -1130,7 +1130,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { accounts = new ArrayList<>(); - account = parseAccountResponse(response); + account = parseAccountResponse(context, response); accounts.add(account); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -1170,7 +1170,7 @@ public class API { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { accounts = new ArrayList<>(); - account = parseAccountResponse(response); + account = parseAccountResponse(context, response); accounts.add(account); apiResponse.setSince_id(findSinceId(headers)); apiResponse.setMax_id(findMaxId(headers)); @@ -1236,7 +1236,7 @@ public class API { while (i < jsonArray.length() ){ JSONObject resobj = jsonArray.getJSONObject(i); - Status status = parseStatuses(resobj); + Status status = parseStatuses(context, resobj); i++; statuses.add(status); } @@ -1253,7 +1253,7 @@ public class API { * @return Status */ @SuppressWarnings("InfiniteRecursion") - private Status parseStatuses(JSONObject resobj){ + public static Status parseStatuses(Context context, JSONObject resobj){ Status status = new Status(); try { status.setId(resobj.get("id").toString()); @@ -1315,14 +1315,14 @@ public class API { } status.setTags(tags); - status.setAccount(parseAccountResponse(resobj.getJSONObject("account"))); + status.setAccount(parseAccountResponse(context, resobj.getJSONObject("account"))); 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.setReblog(parseStatuses(resobj.getJSONObject("reblog"))); + status.setReblog(parseStatuses(context, resobj.getJSONObject("reblog"))); }catch (Exception ignored){} } catch (JSONException e) { e.printStackTrace(); @@ -1355,7 +1355,7 @@ public class API { * @param resobj JSONObject * @return Account */ - private Account parseAccountResponse(JSONObject resobj){ + private static Account parseAccountResponse(Context context, JSONObject resobj){ Account account = new Account(); try { @@ -1392,7 +1392,7 @@ public class API { int i = 0; while (i < jsonArray.length() ) { JSONObject resobj = jsonArray.getJSONObject(i); - Account account = parseAccountResponse(resobj); + Account account = parseAccountResponse(context, resobj); accounts.add(account); i++; } @@ -1416,7 +1416,7 @@ public class API { Account account = null; while (i < jsonArray.length() ) { JSONObject resobj = jsonArray.getJSONObject(i); - account = parseAccountResponse(resobj); + account = parseAccountResponse(context, resobj); if( account.getAcct().contains(Helper.DEVELOPER_INSTANCE)) accounts.add(account); i++; @@ -1500,16 +1500,16 @@ public class API { * @param resobj JSONObject * @return Account */ - private Notification parseNotificationResponse(JSONObject resobj){ + public static Notification parseNotificationResponse(Context context, JSONObject resobj){ Notification notification = new Notification(); try { notification.setId(resobj.get("id").toString()); notification.setType(resobj.get("type").toString()); notification.setCreated_at(Helper.mstStringToDate(context, resobj.get("created_at").toString())); - notification.setAccount(parseAccountResponse(resobj.getJSONObject("account"))); + notification.setAccount(parseAccountResponse(context, resobj.getJSONObject("account"))); try{ - notification.setStatus(parseStatuses(resobj.getJSONObject("status"))); + notification.setStatus(parseStatuses(context, resobj.getJSONObject("status"))); }catch (Exception ignored){} notification.setCreated_at(Helper.mstStringToDate(context, resobj.get("created_at").toString())); } catch (JSONException e) { @@ -1531,7 +1531,7 @@ public class API { while (i < jsonArray.length() ) { JSONObject resobj = jsonArray.getJSONObject(i); - Notification notification = parseNotificationResponse(resobj); + Notification notification = parseNotificationResponse(context, resobj); notifications.add(notification); i++; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Notification.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Notification.java index a8cc8f74d..c415088dc 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Notification.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Notification.java @@ -15,13 +15,16 @@ package fr.gouv.etalab.mastodon.client.Entities; +import android.os.Parcel; +import android.os.Parcelable; + import java.util.Date; /** * Created by Thomas on 23/04/2017. */ -public class Notification { +public class Notification implements Parcelable { private String id; private String type; @@ -29,6 +32,27 @@ public class Notification { private Account account; private Status status; + protected Notification(Parcel in) { + id = in.readString(); + type = in.readString(); + account = in.readParcelable(Account.class.getClassLoader()); + status = in.readParcelable(Status.class.getClassLoader()); + } + + public Notification(){}; + + public static final Creator CREATOR = new Creator() { + @Override + public Notification createFromParcel(Parcel in) { + return new Notification(in); + } + + @Override + public Notification[] newArray(int size) { + return new Notification[size]; + } + }; + public String getId() { return id; } @@ -68,4 +92,17 @@ public class Notification { public void setStatus(Status status) { this.status = status; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(id); + dest.writeString(type); + dest.writeParcelable(account, flags); + dest.writeParcelable(status, flags); + } } 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 6823f340b..45b374f46 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 @@ -37,6 +37,7 @@ import java.util.List; import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.Entities.Account; +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.sqlite.AccountDAO; @@ -145,13 +146,6 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve for(Notification notification: notificationsTmp){ notifications.add(notification); } - //The user clicked on the banner to refresh values so, the pointer is changed - if( notificationsTmp.size() > 0 ) { - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - editor.putString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, notificationsTmp.get(0).getId()); - editor.apply(); - } notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications); lv_notifications.setAdapter(notificationsListAdapter); if( notificationsTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE) @@ -205,64 +199,11 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve return; } SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ userId,Helper.dateToString(context, new Date())); - editor.apply(); - String bubble_max_id = sharedpreferences.getString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, null); List notifications = apiResponse.getNotifications(); since_id = apiResponse.getSince_id(); max_id = apiResponse.getMax_id(); //The initial call comes from a classic tab refresh - if( refreshData ) { - manageNotifications(notifications, max_id, since_id); - //The current tab is displayed, so user is supposed to have seen the notifications - if( since_id != null && displayNotificationsFragment.getUserVisibleHint() && firstLoad) { - editor.putString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, since_id); - editor.apply(); - }else if(!displayNotificationsFragment.getUserVisibleHint()){ - //The refresh was done automatically, but the fragment was not displayed in viewpager - //So the bubble counter will be displayed - int countData = 0; - //Retrieves new notification count - if( bubble_max_id != null) { - for (Notification nt : notifications) { - if (nt.getId().trim().equals(bubble_max_id.trim())) - break; - countData++; - } - } - ((MainActivity)context).updateNotifCounter(countData); - } - }else { //Here, new values have been retrieved on the onResume call (forced mode) - int countData = 0; - if( bubble_max_id != null) { - for (Notification nt : notifications) { - if (nt.getId().trim().equals(bubble_max_id.trim())) - break; - countData++; - } - } - if( notifications != null && notifications.size() > 0 && countData > 0) { - max_id = null; - firstLoad = true; - notificationsTmp = new ArrayList<>(); - for (Notification tmpNotification : notifications) { - this.notificationsTmp.add(tmpNotification); - } - //New notifications will be counted - //The fragment is not displayed, so the bubble counter should be shown - if (!displayNotificationsFragment.getUserVisibleHint()) { - ((MainActivity) context).updateNotifCounter(countData); - } else { //The current fragment is visible, but for avoiding to populate with new values - // a message will be displayed at the bottom requiring a click to display these new values - new_data.setVisibility(View.VISIBLE); - } - } - } - } - - private void manageNotifications(List notifications, String max_id, String since_id){ flag_loading = (max_id == null ); - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); if( !swiped && firstLoad && (notifications == null || notifications.size() == 0)) textviewNoAction.setVisibility(View.VISIBLE); else @@ -284,11 +225,10 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve //Store last notification id to avoid to notify for those that have been already seen if( notifications != null && notifications.size() > 0) { //acct is null as userId when used in Fragment, data need to be retrieved via shared preferences and db - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); Account currentAccount = new AccountDAO(context, db).getAccountByID(userId); if( currentAccount != null && firstLoad && since_id != null){ - SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + currentAccount.getId(), since_id); editor.apply(); } @@ -296,40 +236,40 @@ public class DisplayNotificationsFragment extends Fragment implements OnRetrieve firstLoad = false; } + public void scrollToTop(){ if( lv_notifications != null) lv_notifications.setAdapter(notificationsListAdapter); } - public void update(){ - if( context != null){ - asyncTask = new RetrieveNotificationsAsyncTask(context, null, null, null, null, null, false, DisplayNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + public void updateData(Notification notification){ + if( notificationsTmp != null && notificationsTmp.size() > 0){ + notificationsTmp.add(0,notification); + }else { + notificationsTmp = new ArrayList<>(); + for(Notification notificationTmp: this.notifications){ + notificationsTmp.add(notificationTmp); + } + notificationsTmp.add(0,notification); } - } - - public void refreshData(){ - - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - - if(context != null && this.notificationsTmp != null && this.notificationsTmp.size() > 0){ - boolean isOnWifi = Helper.isOnWIFI(context); - int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); - notifications = new ArrayList<>(); - for(Notification notification: this.notificationsTmp){ - notifications.add(notification); - } - if( textviewNoAction.getVisibility() == View.VISIBLE) - textviewNoAction.setVisibility(View.GONE); - notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications); - lv_notifications.setAdapter(notificationsListAdapter); - this.notificationsTmp = new ArrayList<>(); - } - if( since_id != null){ - //The user clicked on the tab to refresh values so, the pointer is changed - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - editor.putString(Helper.LAST_MAX_ID_BUBBLE_NOTIF + userId, since_id); - editor.apply(); - } - } + new_data.setVisibility(View.VISIBLE); + } + public void refresh(){ + if( notificationsTmp != null){ + boolean isOnWifi = Helper.isOnWIFI(context); + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); + notifications = new ArrayList<>(); + for(Notification notification: notificationsTmp){ + notifications.add(notification); + } + notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments, notifications); + lv_notifications.setAdapter(notificationsListAdapter); + if( notificationsTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE) + textviewNoAction.setVisibility(View.GONE); + } + new_data.setVisibility(View.GONE); + notificationsTmp = new ArrayList<>(); + } } 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 3aa2e1e6b..400df36f5 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 @@ -229,13 +229,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn for(Status status: statusesTmp){ statuses.add(status); } - //The user clicked on the banner to refresh values so, the pointer is changed - if( statusesTmp.size() > 0 ) { - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, statusesTmp.get(0).getId()); - editor.apply(); - } if( statusesTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE) textviewNoAction.setVisibility(View.GONE); statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses); @@ -271,11 +264,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn for(Status status: statusesTmp){ statuses.add(status); } - //The user clicked on the tab to refresh values so, the pointer is changed - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, statusesTmp.get(0).getId()); - editor.apply(); statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses); lv_status.setAdapter(statusListAdapter); statusesTmp = new ArrayList<>(); @@ -315,72 +303,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn List statuses = apiResponse.getStatuses(); since_id = apiResponse.getSince_id(); max_id = apiResponse.getMax_id(); - //Special case for home timeline - if( type == RetrieveFeedsAsyncTask.Type.HOME){ - //Retrieves some values - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - String bubble_max_id = sharedpreferences.getString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, null); - //The initial call comes from a classic tab refresh - if( refreshData ) { - - manageStatus(statuses, max_id, since_id); - //The current tab is displayed, so user is supposed to have seen status - if( since_id != null && displayStatusFragment.getUserVisibleHint() && firstLoad) { - editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, since_id); - editor.apply(); - }else if(!displayStatusFragment.getUserVisibleHint()){ - //Current fragment was loaded but not displayed to the user. - //So the bubble counter will be displayed - int countData = 0; - //Retrieves new status count - if( bubble_max_id != null) { - for (Status st : statuses) { - if (st.getId().trim().equals(bubble_max_id.trim())) - break; - countData++; - } - } - ((MainActivity)context).updateHomeCounter(countData); - } - }else { //Here, new values have been retrieved on the onResume call (forced mode) - int countData = 0; - if( bubble_max_id != null) { - for (Status st : statuses) { - if (st.getId().trim().equals(bubble_max_id.trim())) - break; - countData++; - } - } - - if( statuses != null && statuses.size() > 0 && countData > 0) { - max_id = null; - firstLoad = true; - statusesTmp = new ArrayList<>(); - for (Status tmpStatus : statuses) { - this.statusesTmp.add(tmpStatus); - } - //New status will be counted - //The fragment is not displayed, so the bubble counter should be shown - if (!displayStatusFragment.getUserVisibleHint()) { - ((MainActivity) context).updateHomeCounter(countData); - } else { - //The current fragment is visible, but for avoiding to populate with new values - //Values are put in temp and the banned is displayed - new_data.setVisibility(View.VISIBLE); - } - } - } - }else { - manageStatus(statuses, max_id, since_id); - } - - - - } - - private void manageStatus(List statuses, String max_id, String since_id){ flag_loading = (max_id == null ); if( !swiped && firstLoad && (statuses == null || statuses.size() == 0)) textviewNoAction.setVisibility(View.VISIBLE); @@ -401,7 +324,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn //Store last toot id for home timeline to avoid to notify for those that have been already seen if(statuses != null && statuses.size() > 0 && type == RetrieveFeedsAsyncTask.Type.HOME ){ - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); //acct is null when used in Fragment, data need to be retrieved via shared preferences and db String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); @@ -416,7 +338,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn //Retrieves replies if(statuses != null && statuses.size() > 0 && type == RetrieveFeedsAsyncTask.Type.HOME ) { - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); boolean showPreview = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, true); //Retrieves attached replies to a toot if (showPreview) { @@ -425,6 +346,37 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } } + public void updateData(Status status){ + if( statusesTmp != null && statusesTmp.size() > 0){ + statusesTmp.add(0,status); + }else { + statusesTmp = new ArrayList<>(); + for(Status statusTmp: this.statuses){ + statusesTmp.add(statusTmp); + } + statusesTmp.add(0,status); + } + new_data.setVisibility(View.VISIBLE); + } + + public void refresh(){ + if( statusesTmp != null){ + boolean isOnWifi = Helper.isOnWIFI(context); + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); + statuses = new ArrayList<>(); + for(Status status: statusesTmp){ + statuses.add(status); + } + if( statusesTmp.size() > 0 && textviewNoAction.getVisibility() == View.VISIBLE) + textviewNoAction.setVisibility(View.GONE); + statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses); + lv_status.setAdapter(statusListAdapter); + statusesTmp = new ArrayList<>(); + } + new_data.setVisibility(View.GONE); + } + public void scrollToTop(){ if( lv_status != null) lv_status.setAdapter(statusListAdapter); @@ -444,36 +396,4 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } statusListAdapter.notifyDataSetChanged(); } - public void update() { - if( context != null) { - asyncTask = new RetrieveFeedsAsyncTask(context, type, null, false, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - - public void refreshData(){ - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - if(context != null && this.statusesTmp != null && this.statusesTmp.size() > 0){ - - boolean isOnWifi = Helper.isOnWIFI(context); - int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); - int positionSpinnerTrans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_YANDEX); - - statuses = new ArrayList<>(); - for(Status status: statusesTmp){ - statuses.add(status); - } - if( textviewNoAction.getVisibility() == View.VISIBLE) - textviewNoAction.setVisibility(View.GONE); - statusListAdapter = new StatusListAdapter(context, type, targetedId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, statuses); - lv_status.setAdapter(statusListAdapter); - statusesTmp = new ArrayList<>(); - } - if( since_id != null){ - //The user clicked on the tab to refresh values so, the pointer is changed - SharedPreferences.Editor editor = sharedpreferences.edit(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - editor.putString(Helper.LAST_MAX_ID_BUBBLE_HOME + userId, since_id); - editor.apply(); - } - } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java index 2783602f9..5907cb623 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java @@ -94,19 +94,6 @@ public class SettingsFragment extends Fragment { } }); - boolean bubble_counter = sharedpreferences.getBoolean(Helper.SET_BUBBLE_COUNTER, true); - - final CheckBox set_bubble_counter = (CheckBox) rootView.findViewById(R.id.set_bubble_counter); - set_bubble_counter.setChecked(bubble_counter); - set_bubble_counter.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putBoolean(Helper.SET_BUBBLE_COUNTER, set_bubble_counter.isChecked()); - editor.apply(); - } - }); - boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true); final CheckBox set_show_error_messages = (CheckBox) rootView.findViewById(R.id.set_show_error_messages); set_show_error_messages.setChecked(show_error_messages); 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 97d89f078..a703e0db7 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 @@ -178,10 +178,6 @@ 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 LAST_BUBBLE_REFRESH_NOTIF = "last_bubble_refresh_notif"; - public static final String LAST_BUBBLE_REFRESH_HOME = "last_bubble_refresh_home"; - public static final String LAST_MAX_ID_BUBBLE_NOTIF = "last_max_id_bubble_notif"; - public static final String LAST_MAX_ID_BUBBLE_HOME = "last_max_id_bubble_home"; public static final String CLIP_BOARD = "clipboard"; //Notifications public static final int NOTIFICATION_INTENT = 1; @@ -205,7 +201,6 @@ public class Helper { public static final String SET_ICON_SIZE = "set_icon_size"; public static final String SET_PREVIEW_REPLIES = "set_preview_replies"; public static final String SET_PREVIEW_REPLIES_PP = "set_preview_replies_pp"; - public static final String SET_BUBBLE_COUNTER = "set_bubble_counter"; public static final String SET_TRANSLATOR = "set_translator"; public static final int ATTACHMENT_ALWAYS = 1; @@ -242,8 +237,7 @@ public class Helper { //Refresh job - public static final int MINUTES_BETWEEN_NOTIFICATIONS_REFRESH = 15; - public static final int MINUTES_BETWEEN_HOME_TIMELINE = 30; + public static final int MINUTES_BETWEEN_STREAMING_CHECK_ALIVE = 15; //Intent public static final String INTENT_ACTION = "intent_action"; @@ -251,6 +245,7 @@ public class Helper { //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"; //User agent public static final String USER_AGENT = "Mastalab/"+ BuildConfig.VERSION_NAME + " Android/"+ Build.VERSION.RELEASE; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveStreamingInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveStreamingInterface.java new file mode 100644 index 000000000..43d5dd8cc --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveStreamingInterface.java @@ -0,0 +1,28 @@ +/* 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 org.json.JSONObject; + +import fr.gouv.etalab.mastodon.asynctasks.StreamingUserAsyncTask; + + +/** + * Created by Thomas on 28/08/2017. + * Interface when event from streaming api has been retrieved + */ +public interface OnRetrieveStreamingInterface { + void onRetrieveStreaming(StreamingUserAsyncTask.EventStreaming event, JSONObject response, String acct, String userId); +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java index c087b520f..61b7159bf 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java @@ -26,10 +26,8 @@ public class ApplicationJob implements JobCreator { @Override public Job create(String tag) { switch (tag) { - case NotificationsSyncJob.NOTIFICATION_REFRESH: - return new NotificationsSyncJob(); - case HomeTimelineSyncJob.HOME_TIMELINE: - return new HomeTimelineSyncJob(); + case StreamingSyncJob.STREAMING: + return new StreamingSyncJob(); case ScheduledTootsSyncJob.SCHEDULED_TOOT: return new ScheduledTootsSyncJob(); default: diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java deleted file mode 100644 index 19cd2d843..000000000 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java +++ /dev/null @@ -1,204 +0,0 @@ -package fr.gouv.etalab.mastodon.jobs; -/* 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.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.support.annotation.NonNull; -import android.view.View; - -import com.evernote.android.job.Job; -import com.evernote.android.job.JobManager; -import com.evernote.android.job.JobRequest; -import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; -import com.nostra13.universalimageloader.core.DisplayImageOptions; -import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; -import com.nostra13.universalimageloader.core.assist.FailReason; -import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; -import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; - -import java.io.File; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import fr.gouv.etalab.mastodon.activities.MainActivity; -import fr.gouv.etalab.mastodon.asynctasks.RetrieveHomeTimelineServiceAsyncTask; -import fr.gouv.etalab.mastodon.client.APIResponse; -import fr.gouv.etalab.mastodon.client.Entities.Account; -import fr.gouv.etalab.mastodon.client.Entities.Status; -import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; -import fr.gouv.etalab.mastodon.helper.Helper; -import fr.gouv.etalab.mastodon.interfaces.OnRetrieveHomeTimelineServiceInterface; -import fr.gouv.etalab.mastodon.sqlite.AccountDAO; -import fr.gouv.etalab.mastodon.sqlite.Sqlite; -import mastodon.etalab.gouv.fr.mastodon.R; - -import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT; -import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION; -import static fr.gouv.etalab.mastodon.helper.Helper.PREF_KEY_ID; -import static fr.gouv.etalab.mastodon.helper.Helper.canNotify; -import static fr.gouv.etalab.mastodon.helper.Helper.notify_user; - - -/** - * Created by Thomas on 20/05/2017. - * Notifications for home timeline job - */ - -public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineServiceInterface{ - - static final String HOME_TIMELINE = "home_timeline"; - - @NonNull - @Override - protected Result onRunJob(Params params) { - callAsynchronousTask(); - return Result.SUCCESS; - } - - - public static int schedule(boolean updateCurrent){ - - Set jobRequests = JobManager.instance().getAllJobRequestsForTag(HOME_TIMELINE); - if (!jobRequests.isEmpty() && !updateCurrent) { - return jobRequests.iterator().next().getJobId(); - } - return new JobRequest.Builder(HomeTimelineSyncJob.HOME_TIMELINE) - .setPeriodic(TimeUnit.MINUTES.toMillis(Helper.MINUTES_BETWEEN_HOME_TIMELINE), TimeUnit.MINUTES.toMillis(5)) - .setPersisted(true) - .setUpdateCurrent(updateCurrent) - .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) - .setRequirementsEnforced(false) - .build() - .schedule(); - } - - - /** - * Task in background starts here. - */ - private void callAsynchronousTask() { - - if( !canNotify(getContext())) - return; - final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true); - //User disagree with home timeline refresh - if( !notif_hometimeline) - return; //Nothing is done - //No account connected, the service is stopped - if(!Helper.isLoggedIn(getContext())) - return; - SQLiteDatabase db = Sqlite.getInstance(getContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - //If an Internet connection and user agrees with notification refresh - //If WIFI only and on WIFI OR user defined any connections to use the service. - if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getContext())) { - List accounts = new AccountDAO(getContext(),db).getAllAccount(); - //It means there is no user in DB. - if( accounts == null ) - return; - //Retrieve users in db that owner has. - for (Account account: accounts) { - String since_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + account.getId(), null); - new RetrieveHomeTimelineServiceAsyncTask(getContext(), account.getInstance(), account.getToken(), since_id, account.getAcct(), account.getId(), HomeTimelineSyncJob.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - - } - } - } - - - @Override - public void onRetrieveHomeTimelineService(APIResponse apiResponse, String acct, String userId) { - List statuses = apiResponse.getStatuses(); - if( apiResponse.getError() != null || statuses == null || statuses.size() == 0) - return; - final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - - final String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null); - if( max_id == null){ - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, apiResponse.getSince_id()); - editor.apply(); - return; - } - //No previous notifications in cache, so no notification will be sent - String message; - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, apiResponse.getSince_id()); - editor.apply(); - for(Status status: statuses){ - //The notification associated to max_id is discarded as it is supposed to have already been sent - //Also, if the toot comes from the owner, we will avoid to warn him/her... - if( (status.getId().equals(max_id)) || (acct != null && status.getAccount().getAcct().trim().equals(acct.trim()) )) - continue; - String notificationUrl = status.getAccount().getAvatar(); - - if(statuses.size() > 0 ) - message = getContext().getResources().getQuantityString(R.plurals.other_notif_hometimeline, statuses.size(), statuses.size()); - else - message = ""; - final Intent intent = new Intent(getContext(), MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); - intent.putExtra(INTENT_ACTION, HOME_TIMELINE_INTENT); - intent.putExtra(PREF_KEY_ID, userId); - long notif_id = Long.parseLong(userId); - final int notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2); - - if( notificationUrl != null){ - ImageLoader imageLoaderNoty = ImageLoader.getInstance(); - File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name)); - ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext()) - .imageDownloader(new PatchBaseImageDownloader(getContext())) - .threadPoolSize(5) - .threadPriority(Thread.MIN_PRIORITY + 3) - .denyCacheImageMultipleSizesInMemory() - .diskCache(new UnlimitedDiskCache(cacheDir)) - .build(); - imageLoaderNoty.init(config); - DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false) - .cacheOnDisk(true).resetViewBeforeLoading(true).build(); - final String finalMessage = message; - String title; - if( status.getAccount().getDisplay_name() != null && status.getAccount().getDisplay_name().length() > 0 ) - title = getContext().getResources().getString(R.string.notif_pouet, Helper.shortnameToUnicode(status.getAccount().getDisplay_name(), true)); - else - title = getContext().getResources().getString(R.string.notif_pouet, status.getAccount().getUsername()); - final String finalTitle = title; - - imageLoaderNoty.loadImage(notificationUrl, options, new SimpleImageLoadingListener(){ - @Override - public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { - super.onLoadingComplete(imageUri, view, loadedImage); - notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, finalMessage); - } - @Override - public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){ - notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(), - R.drawable.mastodonlogo), finalTitle, finalMessage); - }}); - - } - } - - } - -} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java deleted file mode 100644 index 49603c1c1..000000000 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java +++ /dev/null @@ -1,271 +0,0 @@ -package fr.gouv.etalab.mastodon.jobs; -/* 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.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.support.annotation.NonNull; -import android.view.View; - -import com.evernote.android.job.Job; -import com.evernote.android.job.JobManager; -import com.evernote.android.job.JobRequest; -import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; -import com.nostra13.universalimageloader.core.DisplayImageOptions; -import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; -import com.nostra13.universalimageloader.core.assist.FailReason; -import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; -import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; - -import java.io.File; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import fr.gouv.etalab.mastodon.activities.MainActivity; -import fr.gouv.etalab.mastodon.client.APIResponse; -import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; -import fr.gouv.etalab.mastodon.helper.Helper; -import mastodon.etalab.gouv.fr.mastodon.R; -import fr.gouv.etalab.mastodon.asynctasks.RetrieveNotificationsAsyncTask; -import fr.gouv.etalab.mastodon.client.Entities.Account; -import fr.gouv.etalab.mastodon.client.Entities.Notification; -import fr.gouv.etalab.mastodon.interfaces.OnRetrieveNotificationsInterface; -import fr.gouv.etalab.mastodon.sqlite.AccountDAO; -import fr.gouv.etalab.mastodon.sqlite.Sqlite; - -import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION; -import static fr.gouv.etalab.mastodon.helper.Helper.NOTIFICATION_INTENT; -import static fr.gouv.etalab.mastodon.helper.Helper.PREF_KEY_ID; -import static fr.gouv.etalab.mastodon.helper.Helper.canNotify; -import static fr.gouv.etalab.mastodon.helper.Helper.notify_user; - - -/** - * Created by Thomas on 29/04/2017. - * Notifications refresh job - */ - -public class NotificationsSyncJob extends Job implements OnRetrieveNotificationsInterface{ - - static final String NOTIFICATION_REFRESH = "job_notification"; - - @NonNull - @Override - protected Result onRunJob(Params params) { - //Code refresh here - callAsynchronousTask(); - return Result.SUCCESS; - } - - - public static int schedule(boolean updateCurrent){ - - Set jobRequests = JobManager.instance().getAllJobRequestsForTag(NOTIFICATION_REFRESH); - if (!jobRequests.isEmpty() && !updateCurrent) { - return jobRequests.iterator().next().getJobId(); - } - - return new JobRequest.Builder(NotificationsSyncJob.NOTIFICATION_REFRESH) - .setPeriodic(TimeUnit.MINUTES.toMillis(Helper.MINUTES_BETWEEN_NOTIFICATIONS_REFRESH), TimeUnit.MINUTES.toMillis(5)) - .setPersisted(true) - .setUpdateCurrent(updateCurrent) - .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) - .setRequirementsEnforced(false) - .build() - .schedule(); - } - - - - /** - * Task in background starts here. - */ - private void callAsynchronousTask() { - if( !canNotify(getContext())) - return; - SQLiteDatabase db = Sqlite.getInstance(getContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - //If an Internet connection and user agrees with notification refresh - final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - //Check which notifications the user wants to see - boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); - boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); - boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true); - boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); - boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); - //User disagree with all notifications - if( !notif_follow && !notif_add && !notif_ask && !notif_mention && !notif_share) - return; //Nothing is done - //No account connected, the service is stopped - if(!Helper.isLoggedIn(getContext())) - return; - //If WIFI only and on WIFI OR user defined any connections to use the service. - if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getContext())) { - List accounts = new AccountDAO(getContext(),db).getAllAccount(); - //It means there is no user in DB. - if( accounts == null ) - return; - //Retrieve users in db that owner has. - for (Account account: accounts) { - String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId(), null); - new RetrieveNotificationsAsyncTask(getContext(), account.getInstance(), account.getToken(), max_id, account.getAcct(), account.getId(), NotificationsSyncJob.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - } - - - - @Override - public void onRetrieveNotifications(APIResponse apiResponse, String acct, String userId, boolean refreshData) { - List notifications = apiResponse.getNotifications(); - if( apiResponse.getError() != null || notifications == null || notifications.size() == 0) - return; - Bitmap icon_notification = null; - final SharedPreferences sharedpreferences = getContext().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); - final String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId, null); - if( max_id == null){ - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, apiResponse.getSince_id()); - editor.apply(); - return; - } - - //No previous notifications in cache, so no notification will be sent - int newFollows = 0; - int newAdds = 0; - int newAsks = 0; - int newMentions = 0; - int newShare = 0; - String notificationUrl = null; - String title = null; - final String message; - for(Notification notification: notifications){ - //The notification associated to max_id is discarded as it is supposed to have already been sent - if( max_id != null && notification.getId().equals(max_id)) - continue; - switch (notification.getType()){ - case "mention": - if(notif_mention){ - newMentions++; - if( notificationUrl == null){ - notificationUrl = notification.getAccount().getAvatar(); - if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) - title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getContext().getString(R.string.notif_mention)); - else - title = String.format("@%s %s", notification.getAccount().getUsername(),getContext().getString(R.string.notif_mention)); - } - } - break; - case "reblog": - if(notif_share){ - newShare++; - if( notificationUrl == null){ - notificationUrl = notification.getAccount().getAvatar(); - if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) - title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getContext().getString(R.string.notif_reblog)); - else - title = String.format("@%s %s", notification.getAccount().getUsername(),getContext().getString(R.string.notif_reblog)); - - } - } - break; - case "favourite": - if(notif_add){ - newAdds++; - if( notificationUrl == null){ - notificationUrl = notification.getAccount().getAvatar(); - if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) - title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getContext().getString(R.string.notif_favourite)); - else - title = String.format("@%s %s", notification.getAccount().getUsername(),getContext().getString(R.string.notif_favourite)); - } - } - break; - case "follow": - if(notif_follow){ - newFollows++; - if( notificationUrl == null){ - notificationUrl = notification.getAccount().getAvatar(); - if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) - title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getContext().getString(R.string.notif_follow)); - else - title = String.format("@%s %s", notification.getAccount().getUsername(),getContext().getString(R.string.notif_follow)); - } - } - break; - default: - } - } - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, apiResponse.getSince_id()); - editor.apply(); - int allNotifCount = newFollows + newAdds + newAsks + newMentions + newShare; - if( allNotifCount > 0){ - //Some others notification - int other = allNotifCount -1; - if(other > 0 ) - message = getContext().getResources().getQuantityString(R.plurals.other_notifications, other, other); - else - message = ""; - final Intent intent = new Intent(getContext(), MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); - intent.putExtra(INTENT_ACTION, NOTIFICATION_INTENT); - intent.putExtra(PREF_KEY_ID, userId); - long notif_id = Long.parseLong(userId); - final int notificationId = ((notif_id + 1) > 2147483647) ? (int) (2147483647 - notif_id - 1) : (int) (notif_id + 1); - - if( notificationUrl != null && icon_notification == null){ - ImageLoader imageLoaderNoty = ImageLoader.getInstance(); - File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name)); - ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext()) - .imageDownloader(new PatchBaseImageDownloader(getContext())) - .threadPoolSize(5) - .threadPriority(Thread.MIN_PRIORITY + 3) - .denyCacheImageMultipleSizesInMemory() - .diskCache(new UnlimitedDiskCache(cacheDir)) - .build(); - imageLoaderNoty.init(config); - DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false) - .cacheOnDisk(true).resetViewBeforeLoading(true).build(); - - final String finalTitle = title; - imageLoaderNoty.loadImage(notificationUrl, options, new SimpleImageLoadingListener(){ - @Override - public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { - super.onLoadingComplete(imageUri, view, loadedImage); - if( max_id != null) - notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, message); - } - @Override - public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){ - if( max_id != null) - notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(), - R.drawable.mastodonlogo), finalTitle, message); - }}); - } - - } - } - -} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ScheduledTootsSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ScheduledTootsSyncJob.java index 5bc7eb5bf..a995d5b1e 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ScheduledTootsSyncJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ScheduledTootsSyncJob.java @@ -17,7 +17,6 @@ package fr.gouv.etalab.mastodon.jobs; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.support.annotation.NonNull; -import android.util.Log; import com.evernote.android.job.Job; import com.evernote.android.job.JobRequest; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/StreamingSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/StreamingSyncJob.java new file mode 100644 index 000000000..b1b093de3 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/StreamingSyncJob.java @@ -0,0 +1,63 @@ +package fr.gouv.etalab.mastodon.jobs; +/* 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.Intent; +import android.support.annotation.NonNull; +import com.evernote.android.job.Job; +import com.evernote.android.job.JobManager; +import com.evernote.android.job.JobRequest; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.services.StreamingService; + + +/** + * Created by Thomas on 29/04/2017. + * Notifications refresh job + */ + +public class StreamingSyncJob extends Job { + + static final String STREAMING = "job_streaming"; + + + @NonNull + @Override + protected Result onRunJob(Params params) { + //Code refresh here + getContext().startService(new Intent(getContext(), StreamingService.class)); + return Result.SUCCESS; + } + + + public static int schedule(boolean updateCurrent){ + + Set jobRequests = JobManager.instance().getAllJobRequestsForTag(STREAMING); + if (!jobRequests.isEmpty() && !updateCurrent) { + return jobRequests.iterator().next().getJobId(); + } + return new JobRequest.Builder(StreamingSyncJob.STREAMING) + .setPeriodic(TimeUnit.MINUTES.toMillis(Helper.MINUTES_BETWEEN_STREAMING_CHECK_ALIVE), TimeUnit.MINUTES.toMillis(5)) + .setPersisted(true) + .setUpdateCurrent(updateCurrent) + .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) + .setRequirementsEnforced(false) + .build() + .schedule(); + } + +} 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 new file mode 100644 index 000000000..7144da304 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/StreamingService.java @@ -0,0 +1,314 @@ +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.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.Nullable; +import android.support.v4.content.LocalBroadcastManager; +import android.text.Html; +import android.view.View; + +import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.util.List; + +import fr.gouv.etalab.mastodon.activities.MainActivity; +import fr.gouv.etalab.mastodon.asynctasks.StreamingUserAsyncTask; +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.PatchBaseImageDownloader; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveStreamingInterface; +import fr.gouv.etalab.mastodon.jobs.StreamingSyncJob; +import fr.gouv.etalab.mastodon.sqlite.AccountDAO; +import fr.gouv.etalab.mastodon.sqlite.Sqlite; +import mastodon.etalab.gouv.fr.mastodon.R; + +import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT; +import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION; +import static fr.gouv.etalab.mastodon.helper.Helper.NOTIFICATION_INTENT; +import static fr.gouv.etalab.mastodon.helper.Helper.PREF_KEY_ID; +import static fr.gouv.etalab.mastodon.helper.Helper.notify_user; + +/** + * Created by Thomas on 28/08/2017. + */ + +public class StreamingService extends Service implements OnRetrieveStreamingInterface { + + private String message; + private int notificationId; + private Intent intent; + + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + callAsynchronousTask(); + return START_NOT_STICKY; + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + + /** + * Task in background starts here. + */ + private void callAsynchronousTask() { + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + //If an Internet connection and user agrees with notification refresh + final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + //Check which notifications the user wants to see + boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); + boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); + boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true); + boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); + boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); + //User disagree with all notifications + if( !notif_follow && !notif_add && !notif_ask && !notif_mention && !notif_share) + return; //Nothing is done + //No account connected, the service is stopped + if(!Helper.isLoggedIn(getApplicationContext())) + return; + //If WIFI only and on WIFI OR user defined any connections to use the service. + if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getApplicationContext())) { + List accounts = new AccountDAO(getApplicationContext(),db).getAllAccount(); + //It means there is no user in DB. + if( accounts == null ) + return; + //Retrieve users in db that owner has. + for (Account account: accounts) { + new StreamingUserAsyncTask(account.getInstance(), account.getToken(), account.getAcct(), account.getId(), StreamingService.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + } + + + @Override + public void onRetrieveStreaming(StreamingUserAsyncTask.EventStreaming event, JSONObject response, String acct, String userId) { + if( response == null ) + return; + String max_id = null; + final SharedPreferences sharedpreferences = 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); + + //No previous notifications in cache, so no notification will be sent + boolean notify = false; + + String notificationUrl = null; + String title = null; + Status status = null; + Notification notification = null; + String dataId = null; + if( event == StreamingUserAsyncTask.EventStreaming.NOTIFICATION){ + notification = API.parseNotificationResponse(getApplicationContext(), response); + max_id = notification.getId(); + switch (notification.getType()){ + case "mention": + if(notif_mention){ + notify = true; + notificationUrl = notification.getAccount().getAvatar(); + if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) + title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_mention)); + else + title = String.format("@%s %s", notification.getAccount().getUsername(),getString(R.string.notif_mention)); + } + break; + case "reblog": + if(notif_share){ + notify = true; + notificationUrl = notification.getAccount().getAvatar(); + if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) + title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_reblog)); + else + title = String.format("@%s %s", notification.getAccount().getUsername(),getString(R.string.notif_reblog)); + } + break; + case "favourite": + if(notif_add){ + notify = true; + notificationUrl = notification.getAccount().getAvatar(); + if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) + title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_favourite)); + else + title = String.format("@%s %s", notification.getAccount().getUsername(),getString(R.string.notif_favourite)); + } + break; + case "follow": + if(notif_follow){ + notify = true; + notificationUrl = notification.getAccount().getAvatar(); + if( notification.getAccount().getDisplay_name() != null && notification.getAccount().getDisplay_name().length() > 0 ) + title = String.format("@%s %s", Helper.shortnameToUnicode(notification.getAccount().getDisplay_name(), true),getString(R.string.notif_follow)); + else + title = String.format("@%s %s", notification.getAccount().getUsername(),getString(R.string.notif_follow)); + } + break; + default: + break; + } + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, notification.getId()); + editor.apply(); + if( notification.getStatus().getContent()!= null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + message = Html.fromHtml(notification.getStatus().getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); + else + //noinspection deprecation + message = Html.fromHtml(notification.getStatus().getContent()).toString(); + message = message.substring(0, message.length()>49?49:message.length()); + message = message + "…"; + }else{ + message = ""; + } + }else if ( event == StreamingUserAsyncTask.EventStreaming.UPDATE){ + status = API.parseStatuses(getApplicationContext(), response); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, status.getId()); + editor.apply(); + if( status.getContent() != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + message = Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString(); + else + //noinspection deprecation + message = Html.fromHtml(status.getContent()).toString(); + message = message.substring(0, message.length()>49?49:message.length()); + message = message + "…"; + }else{ + message = ""; + } + title = getString(R.string.notif_pouet, status.getAccount().getUsername()); + notificationUrl = status.getAccount().getAvatar(); + }else if( event == StreamingUserAsyncTask.EventStreaming.DELETE){ + try { + dataId = response.getString("id"); + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + if( max_id != null){ + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId, max_id); + editor.apply(); + return; + } + + //Check which user is connected and if activity is to front + boolean activityVisible = false; + try{ + activityVisible = MainActivity.isActivityVisible(); + }catch (Exception ignored){} + String userconnected = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(userconnected); + //User receiving the notification is connected and application is to front, notification won't be pushed + //Instead, the interaction is done in the activity + if( activityVisible && account != null && !account.getAcct().trim().equals(acct.trim()) && !account.getId().trim().equals(userId.trim())){ + notify = false; + Intent intentBC = new Intent(Helper.RECEIVE_DATA); + intentBC.putExtra("eventStreaming", event); + Bundle b = new Bundle(); + if( event == StreamingUserAsyncTask.EventStreaming.UPDATE) + b.putParcelable("data", status); + else if(event == StreamingUserAsyncTask.EventStreaming.NOTIFICATION) + b.putParcelable("data", notification); + else if(event == StreamingUserAsyncTask.EventStreaming.DELETE) + b.putString("id", dataId); + intentBC.putExtras(b); + LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentBC); + }else if(event == StreamingUserAsyncTask.EventStreaming.NOTIFICATION ){ + notify = true; + intent = new Intent(getApplicationContext(), MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); + intent.putExtra(INTENT_ACTION, NOTIFICATION_INTENT); + intent.putExtra(PREF_KEY_ID, userId); + long notif_id = Long.parseLong(userId); + notificationId = ((notif_id + 1) > 2147483647) ? (int) (2147483647 - notif_id - 1) : (int) (notif_id + 1); + + + }else if(event == StreamingUserAsyncTask.EventStreaming.UPDATE ){ + if(account.getAcct().trim().equals(acct.trim()) && account.getId().trim().equals(userId.trim())){ + notify = false; + }else { + notify = true; + intent = new Intent(getApplicationContext(), MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(INTENT_ACTION, HOME_TIMELINE_INTENT); + intent.putExtra(PREF_KEY_ID, userId); + long notif_id = Long.parseLong(userId); + notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2); + } + } + if( notify){ + if( notificationUrl != null){ + ImageLoader imageLoaderNoty = ImageLoader.getInstance(); + File cacheDir = new File(getApplicationContext().getCacheDir(), getString(R.string.app_name)); + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()) + .imageDownloader(new PatchBaseImageDownloader(getApplicationContext())) + .threadPoolSize(5) + .threadPriority(Thread.MIN_PRIORITY + 3) + .denyCacheImageMultipleSizesInMemory() + .diskCache(new UnlimitedDiskCache(cacheDir)) + .build(); + imageLoaderNoty.init(config); + DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false) + .cacheOnDisk(true).resetViewBeforeLoading(true).build(); + + final String finalTitle = title; + imageLoaderNoty.loadImage(notificationUrl, options, new SimpleImageLoadingListener(){ + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + super.onLoadingComplete(imageUri, view, loadedImage); + notify_user(getApplicationContext(), intent, notificationId, loadedImage, finalTitle, message); + + } + @Override + public void onLoadingFailed(String imageUri, View view, FailReason failReason){ + notify_user(getApplicationContext(), intent, notificationId, BitmapFactory.decodeResource(getApplicationContext().getResources(), + R.drawable.mastodonlogo), finalTitle, message); + }}); + } + } + } +} diff --git a/app/src/main/res/layout-sw600dp/fragment_settings.xml b/app/src/main/res/layout-sw600dp/fragment_settings.xml index 73c3fd3d0..9e104537d 100644 --- a/app/src/main/res/layout-sw600dp/fragment_settings.xml +++ b/app/src/main/res/layout-sw600dp/fragment_settings.xml @@ -58,11 +58,6 @@ android:text="@string/set_auto_store_toot" android:layout_height="wrap_content" /> - - = TimeUnit.SECONDS.toMillis(60)) { - - if( notificationsFragment != null ){ - notificationsFragment.update(); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_BUBBLE_REFRESH_NOTIF+ account.getId(),Helper.dateToString(getApplicationContext(), new Date())); - editor.apply(); - } - } - - last_refresh = sharedpreferences.getString(Helper.LAST_BUBBLE_REFRESH_HOME + account.getId(), null); - last_refresh_date = Helper.stringToDate(getApplicationContext(), last_refresh); - - if (last_refresh_date == null || (new Date().getTime() - last_refresh_date.getTime()) >= TimeUnit.SECONDS.toMillis(60)) { - if( homeFragment != null ){ - homeFragment.update(); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_BUBBLE_REFRESH_HOME+ account.getId(),Helper.dateToString(getApplicationContext(), new Date())); - editor.apply(); - } - } - } - } - - public void updateHomeCounter(int newHomeCount){ + public void updateHomeCounter(){ if( tabLayout.getTabAt(0) == null ) return; //noinspection ConstantConditions @@ -1101,8 +1121,8 @@ public class MainActivity extends AppCompatActivity if( tabHome == null) return; TextView tabCounterHome = (TextView) tabHome.findViewById(R.id.tab_counter); - tabCounterHome.setText(String.valueOf(newHomeCount)); - if( newHomeCount > 0){ + tabCounterHome.setText(String.valueOf(newHome)); + if( newHome > 0){ //New data are available //The fragment is not displayed, so the counter is displayed if( tabLayout.getSelectedTabPosition() != 0) @@ -1114,7 +1134,7 @@ public class MainActivity extends AppCompatActivity } } - public void updateNotifCounter(int newNotifCount){ + public void updateNotifCounter(){ if(tabLayout.getTabAt(1) == null) return; //noinspection ConstantConditions @@ -1122,8 +1142,8 @@ public class MainActivity extends AppCompatActivity if( tabNotif == null) return; TextView tabCounterNotif = (TextView) tabNotif.findViewById(R.id.tab_counter); - tabCounterNotif.setText(String.valueOf(newNotifCount)); - if( newNotifCount > 0){ + tabCounterNotif.setText(String.valueOf(newNotif)); + if( newNotif > 0){ if( tabLayout.getSelectedTabPosition() != 1) tabCounterNotif.setVisibility(View.VISIBLE); else @@ -1133,4 +1153,21 @@ public class MainActivity extends AppCompatActivity } } + + + + + public static boolean isActivityVisible() { + return activityVisible; + } + + private static void activityResumed() { + activityVisible = true; + } + + private static void activityPaused() { + activityVisible = false; + } + + private static boolean activityVisible; }