Merged in web_socket (pull request #94)

Web socket
This commit is contained in:
tom79 2017-08-28 17:26:02 +00:00
commit 84f4357ce0
22 changed files with 878 additions and 910 deletions

View File

@ -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;
}

View File

@ -34,6 +34,9 @@
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppThemeDark">
<service
android:name="fr.gouv.etalab.mastodon.services.StreamingService"
android:exported="false"/>
<activity
android:name="fr.gouv.etalab.mastodon.activities.MainActivity"
android:label="@string/app_name"

View File

@ -17,8 +17,7 @@ import android.app.Application;
import android.os.StrictMode;
import com.evernote.android.job.JobManager;
import fr.gouv.etalab.mastodon.jobs.ApplicationJob;
import fr.gouv.etalab.mastodon.jobs.HomeTimelineSyncJob;
import fr.gouv.etalab.mastodon.jobs.NotificationsSyncJob;
import fr.gouv.etalab.mastodon.jobs.StreamingSyncJob;
/**
* Created by Thomas on 29/04/2017.
@ -33,8 +32,7 @@ public class MainApplication extends Application{
super.onCreate();
JobManager.create(this).addJobCreator(new ApplicationJob());
JobManager.instance().getConfig().setVerbose(false);
NotificationsSyncJob.schedule(false);
HomeTimelineSyncJob.schedule(false);
StreamingSyncJob.schedule(true);
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}

View File

@ -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.OnRetrieveFeedsInterface;
@ -61,8 +56,6 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
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<Void, Void, Void> {
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<Void, Void, Void> {
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<Void, Void, Void> {
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();
}
}
}

View File

@ -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<Void, Void, Void>
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<Void, Void, Void>
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();
}
}

View File

@ -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 <http://www.gnu.org/licenses>. */
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<String, HttpURLConnection> 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;
}
}

View File

@ -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++;
}

View File

@ -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<Notification> CREATOR = new Creator<Notification>() {
@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);
}
}

View File

@ -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<Notification> 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<Notification> 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<>();
}
}

View File

@ -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<Status> 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<Status> 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();
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses>. */
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);
}

View File

@ -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:

View File

@ -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 <http://www.gnu.org/licenses>. */
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<JobRequest> 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<Account> 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<Status> 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);
}});
}
}
}
}

View File

@ -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 <http://www.gnu.org/licenses>. */
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<JobRequest> 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<Account> 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<Notification> 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);
}});
}
}
}
}

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses>. */
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<JobRequest> 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();
}
}

View File

@ -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 <http://www.gnu.org/licenses>. */
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<Account> 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);
}});
}
}
}
}

View File

@ -58,11 +58,6 @@
android:text="@string/set_auto_store_toot"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_bubble_counter"
android:layout_width="wrap_content"
android:text="@string/set_bubble_counter"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_preview_reply"

View File

@ -58,11 +58,6 @@
android:text="@string/set_auto_store_toot"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_bubble_counter"
android:layout_width="wrap_content"
android:text="@string/set_bubble_counter"
android:layout_height="wrap_content" />
<CheckBox
android:id="@+id/set_preview_reply"

View File

@ -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;
@ -71,8 +74,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;
@ -80,6 +86,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;
@ -124,6 +131,8 @@ public class MainActivity extends AppCompatActivity
private DisplayStatusFragment homeFragment;
private DisplayNotificationsFragment notificationsFragment;
private static final int ERROR_DIALOG_REQUEST_CODE = 97;
private BroadcastReceiver receive_data;
private int newNotif, newHome;
public MainActivity() {
}
@ -131,6 +140,46 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
newNotif = 0;
newHome = 0;
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));
ProviderInstaller.installIfNeededAsync(this, this);
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
@ -150,7 +199,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);
@ -208,7 +257,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) {
@ -231,16 +279,18 @@ 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";
@ -448,6 +498,8 @@ public class MainActivity extends AppCompatActivity
navigationView.getMenu().findItem(R.id.nav_follow_request).setVisible(false);
}
LinearLayout owner_container = (LinearLayout) headerLayout.findViewById(R.id.owner_container);
owner_container.setOnClickListener(new View.OnClickListener() {
@Override
@ -810,23 +862,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
@ -1060,40 +1112,8 @@ public class MainActivity extends AppCompatActivity
}
}
private void refreshData(){
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, 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
@ -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;
}