From 13181f0bf03de5966dbf22be3f0b9310803cf9b8 Mon Sep 17 00:00:00 2001 From: stom79 Date: Wed, 19 Dec 2018 15:12:46 +0100 Subject: [PATCH] Improvements --- .../mastodon/activities/BaseMainActivity.java | 14 +- .../mastodon/activities/MainApplication.java | 2 - .../mastodon/drawers/StatusListAdapter.java | 20 +- .../fragments/DisplayStatusFragment.java | 146 ++++++------ .../gouv/etalab/mastodon/helper/Helper.java | 1 + .../etalab/mastodon/jobs/ApplicationJob.java | 2 - .../mastodon/jobs/HomeTimelineSyncJob.java | 221 ------------------ 7 files changed, 90 insertions(+), 316 deletions(-) delete mode 100644 app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java index 3e900c0d3..5187d41be 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java @@ -195,7 +195,6 @@ public abstract class BaseMainActivity extends BaseActivity boolean notif_follow, notif_add, notif_mention, notif_share, show_boosts, show_replies , show_nsfw; String show_filtered; private AppBarLayout appBar; - private String bookmark; private String userId; private String instance; public int countPage; @@ -1222,10 +1221,7 @@ public abstract class BaseMainActivity extends BaseActivity userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); instance = sharedpreferences.getString(Helper.PREF_INSTANCE, Helper.getLiveInstance(getApplicationContext())); - //Get the previous bookmark value - //If null try to use the LAST_HOMETIMELINE_MAX_ID - String lastHomeTimeline = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId + instance, null); - bookmark = sharedpreferences.getString(Helper.BOOKMARK_ID + userId + instance, lastHomeTimeline); + Account account = new AccountDAO(getApplicationContext(), db).getAccountByID(userId); if( account == null){ Helper.logout(getApplicationContext()); @@ -2331,14 +2327,6 @@ public abstract class BaseMainActivity extends BaseActivity Helper.canPin = (currentVersion.compareTo(minVersion) == 1 || currentVersion.equals(minVersion)); } - public String getBookmark() { - return bookmark; - } - - public void setBookmark(@SuppressWarnings("SameParameterValue") String bookmark) { - this.bookmark = bookmark; - } - @Override public void onRetrieveRemoteAccount(Results results) { if (results == null) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java index 24b2da91d..691a48852 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java @@ -30,7 +30,6 @@ import java.util.Locale; import es.dmoral.toasty.Toasty; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.jobs.ApplicationJob; -import fr.gouv.etalab.mastodon.jobs.HomeTimelineSyncJob; import fr.gouv.etalab.mastodon.jobs.NotificationsSyncJob; /** @@ -47,7 +46,6 @@ public class MainApplication extends MultiDexApplication { super.onCreate(); JobManager.create(this).addJobCreator(new ApplicationJob()); NotificationsSyncJob.schedule(false); - HomeTimelineSyncJob.schedule(false); StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); try { diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index 6fd3c5d62..90771eb8d 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -997,22 +997,22 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct if( status.isFetchMore()) { holder.fetch_more.setVisibility(View.VISIBLE); holder.fetch_more.setEnabled(true); - }else { - holder.fetch_more.setVisibility(View.GONE); - - } - - holder.fetch_more.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { + holder.fetch_more.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { status.setFetchMore(false); holder.fetch_more.setEnabled(false); holder.fetch_more.setVisibility(View.GONE); DisplayStatusFragment homeFragment = ((BaseMainActivity) context).getHomeFragment(); if( homeFragment != null) homeFragment.fetchMore(status.getId()); - } - }); + } + }); + }else { + holder.fetch_more.setVisibility(View.GONE); + + } + holder.status_mention_spoiler.setText(Helper.makeMentionsClick(context,status.getMentions()), TextView.BufferType.SPANNABLE); holder.status_mention_spoiler.setMovementMethod(LinkMovementMethod.getInstance()); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java index 51d20b122..31b90f4fa 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java @@ -105,6 +105,9 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn private boolean fetchMoreButtonDisplayed; private TagTimeline tagTimeline; + private String updatedBookMark; + private String lastReadToot; + public DisplayStatusFragment(){ } @@ -117,7 +120,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn Bundle bundle = this.getArguments(); showMediaOnly = false; //Will allow to load first toots if bookmark != null - firstTootsLoaded = true; + firstTootsLoaded = false; fetchMoreButtonDisplayed = false; showPinned = false; showReply = false; @@ -144,6 +147,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn max_id = null; flag_loading = true; firstLoad = true; + initialBookMark = null; + assert context != null; sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); boolean isOnWifi = Helper.isOnWIFI(context); @@ -156,9 +161,15 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn nextElementLoader.setVisibility(View.GONE); userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + instance = sharedpreferences.getString(Helper.PREF_INSTANCE, context!=null?Helper.getLiveInstance(context):null); Account account = new AccountDAO(context, db).getAccountByID(userId); mutedAccount = new TempMuteDAO(context, db).getAllTimeMuted(account); + //For Home timeline, fetch stored values for bookmark and last read toot + if( type == RetrieveFeedsAsyncTask.Type.HOME) { + initialBookMark = sharedpreferences.getString(Helper.BOOKMARK_ID + userId + instance, null); + lastReadToot = sharedpreferences.getString(Helper.LAST_READ_TOOT_ID + userId + instance, null); + } if( type == RetrieveFeedsAsyncTask.Type.TAG && tag != null) { BaseMainActivity.displayPeertube = null; List tagTimelines = new SearchDAO(context, db).getTimelineInfo(tag); @@ -180,7 +191,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn lv_status.setLayoutManager(mLayoutManager); - instance = sharedpreferences.getString(Helper.PREF_INSTANCE, context!=null?Helper.getLiveInstance(context):null); if( type == RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE && search_peertube != null) ((Activity)context).setTitle(remoteInstance + " - " + search_peertube); @@ -228,13 +238,12 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn nextElementLoader.setVisibility(View.GONE); } } - if(type == RetrieveFeedsAsyncTask.Type.HOME && statuses != null && statuses.size() > firstVisibleItem && firstVisibleItem >= 0) - if( context instanceof BaseMainActivity){ - SharedPreferences.Editor editor = sharedpreferences.edit(); - Long bookmarkL = Long.parseLong(statuses.get(firstVisibleItem).getId()) + 1; - editor.putString(Helper.BOOKMARK_ID + userId + instance, String.valueOf(bookmarkL)); - editor.apply(); - } + if(type == RetrieveFeedsAsyncTask.Type.HOME && statuses != null && statuses.size() > firstVisibleItem && firstVisibleItem >= 0) { + Long bookmarkL = Long.parseLong(statuses.get(firstVisibleItem).getId()) + 1; + updatedBookMark = String.valueOf(bookmarkL); + if( lastReadToot == null || bookmarkL > Long.parseLong(lastReadToot)) //Last read toot, only incremented if the id of the toot is greater than the recorded one + lastReadToot = String.valueOf(bookmarkL); + } } }); @@ -306,9 +315,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn asyncTask = new RetrievePeertubeSearchAsyncTask(context, remoteInstance, search_peertube, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }else { if( type == RetrieveFeedsAsyncTask.Type.HOME ){ - firstTootsLoaded = false; if( context instanceof BaseMainActivity){ - initialBookMark = ((BaseMainActivity) context).getBookmark(); asyncTask = new RetrieveFeedsAsyncTask(context, type, initialBookMark, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }else { @@ -335,9 +342,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn asyncTask = new RetrievePeertubeSearchAsyncTask(context, remoteInstance, search_peertube, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }else { if( type == RetrieveFeedsAsyncTask.Type.HOME ){ - firstTootsLoaded = false; if( context instanceof BaseMainActivity){ - initialBookMark = ((BaseMainActivity) context).getBookmark(); asyncTask = new RetrieveFeedsAsyncTask(context, type, initialBookMark,DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }else { @@ -352,6 +357,21 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn return rootView; } + @Override + public void onPause(){ + super.onPause(); + //Store bookmark on pause + if (context instanceof BaseMainActivity && type == RetrieveFeedsAsyncTask.Type.HOME) { + SharedPreferences.Editor editor = sharedpreferences.edit(); + if(updatedBookMark != null) + editor.putString(Helper.BOOKMARK_ID + userId + instance, updatedBookMark); + if( lastReadToot != null) + editor.putString(Helper.LAST_READ_TOOT_ID + userId + instance, lastReadToot); + if( lastReadToot != null || updatedBookMark != null) + editor.apply(); + } + } + @Override public void onCreate(Bundle saveInstance) @@ -378,9 +398,10 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn @Override public void onRetrieveFeeds(APIResponse apiResponse) { + //hide loaders mainLoader.setVisibility(View.GONE); nextElementLoader.setVisibility(View.GONE); - //Discards 404 - error which can often happen due to toots which have been deleted + //handle other API error but discards 404 - error which can often happen due to toots which have been deleted if( apiResponse == null || (apiResponse.getError() != null && apiResponse.getError().getStatusCode() != 404) ){ if( apiResponse == null) Toasty.error(context, context.getString(R.string.toast_error),Toast.LENGTH_LONG).show(); @@ -390,25 +411,30 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn flag_loading = false; return; } - + //For remote Peertube remote instances if( type == RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE && peertubeAdapater != null){ int previousPosition = this.peertubes.size(); if( max_id == null) max_id = "0"; + //max_id needs to work like an offset max_id = String.valueOf(Integer.valueOf(max_id) + 50); this.peertubes.addAll(apiResponse.getPeertubes()); + //If no item were inserted previously the adapter is created if( previousPosition == 0) { peertubeAdapater = new PeertubeAdapter(context, remoteInstance, this.peertubes); lv_status.setAdapter(peertubeAdapater); }else peertubeAdapater.notifyItemRangeInserted(previousPosition, apiResponse.getPeertubes().size()); + //remove handlers swipeRefreshLayout.setRefreshing(false); firstLoad = false; flag_loading = false; }else { - //Add conversation in status - if( type == RetrieveFeedsAsyncTask.Type.CONVERSATION ){ + //When Mastodon statuses have been fetched. + if( type == RetrieveFeedsAsyncTask.Type.CONVERSATION ){ //Conversation timeline + //this timeline is dealt differently because it is embedded in Conversation entity and not directly in statuses List conversations = apiResponse.getConversations(); + //Statuses from conversation entity are retrieved List statusesConversations = new ArrayList<>(); if( conversations != null) { for (Conversation conversation : conversations) { @@ -427,48 +453,55 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } int previousPosition = this.statuses.size(); List statuses = apiResponse.getStatuses(); - if( type == RetrieveFeedsAsyncTask.Type.HOME) { - if (max_id == null || (apiResponse.getMax_id() != null && Long.parseLong(max_id) > Long.parseLong(apiResponse.getMax_id()))) - max_id = apiResponse.getMax_id(); - }else { - max_id = apiResponse.getMax_id(); - } + //At this point all statuses are in "List statuses" + max_id = apiResponse.getMax_id(); + //while max_id is different from null, there are some more toots to load when scrolling flag_loading = (max_id == null ); - if( firstLoad && (statuses == null || statuses.size() == 0)) + //If it's the first load and the reply doesn't contain any toots, a message is displayed. + if( firstLoad && (statuses == null || statuses.size() == 0)) { textviewNoAction.setVisibility(View.VISIBLE); - else + lv_status.setVisibility(View.GONE); + }else { + lv_status.setVisibility(View.VISIBLE); textviewNoAction.setVisibility(View.GONE); + } //First toot are loaded as soon as the bookmark has been retrieved + //Only for the Home timeline if( type == RetrieveFeedsAsyncTask.Type.HOME && !firstTootsLoaded){ asyncTask = new RetrieveFeedsAsyncTask(context, type, null, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); firstTootsLoaded = true; } + + //Let's deal with statuses if( statuses != null && statuses.size() > 0) { if (type == RetrieveFeedsAsyncTask.Type.HOME) { - //Toots are older than the bookmark -> no special treatment with them + //Toots are older than the bookmark: + //Bookmark is null or greater id of returned status is lower than the bookmark id (+1 to exclude the bookmarked status). + //The initialBookMark will be only set once for Home timeline when the fragment is created if( initialBookMark == null || Long.parseLong(statuses.get(0).getId()) + 1 < Long.parseLong(initialBookMark)){ this.statuses.addAll(statuses); statusListAdapter.notifyItemRangeInserted(previousPosition, statuses.size()); }else { //Toots are younger than the bookmark - String currentMaxId = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId + instance, null); + //Find the position of toots between those already present int position = 0; while (position < this.statuses.size() && Long.parseLong(statuses.get(0).getId()) < Long.parseLong(this.statuses.get(position).getId())) { position++; } ArrayList tmpStatuses = new ArrayList<>(); for (Status tmpStatus : statuses) { - //Mark status at new ones when their id is greater than the bookmark id / Also increments counter - if (currentMaxId != null && Long.parseLong(tmpStatus.getId()) > Long.parseLong(currentMaxId)) { - tmpStatus.setNew(true); - MainActivity.countNewStatus++; - } //Put the toot at its place in the list (id desc) - if( !this.statuses.contains(tmpStatus) ) { //Element not already addeds + if( !this.statuses.contains(tmpStatus) ) { //Element not already added + //Mark status at new ones when their id is greater than the last read toot id + if (lastReadToot != null && Long.parseLong(tmpStatus.getId()) > Long.parseLong(lastReadToot)) { + tmpStatus.setNew(true); + MainActivity.countNewStatus++; + } tmpStatuses.add(tmpStatus); } } int tootPerPage = sharedpreferences.getInt(Helper.SET_TOOTS_PER_PAGE, 40); + //Display the fetch more toot button if( tmpStatuses.size() >= tootPerPage) { if (!fetchMoreButtonDisplayed && tmpStatuses.size() > 0 && Long.parseLong(tmpStatuses.get(tmpStatuses.size() - 1).getId()) > Long.parseLong(initialBookMark)) { tmpStatuses.get(tmpStatuses.size() - 1).setFetchMore(true); @@ -484,6 +517,14 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn } } + //Update the id of the last toot retrieved + if( MainActivity.lastHomeId == null || Long.parseLong(statuses.get(0).getId()) > Long.parseLong(MainActivity.lastHomeId)) + MainActivity.lastHomeId = statuses.get(0).getId(); + //Display new value in counter + try { + ((MainActivity) context).updateHomeCounter(); + }catch (Exception ignored){} + }else if ( statusListAdapter != null){ if( tagTimeline == null || !tagTimeline.isART() || (tagTimeline.isART() && tagTimeline.isNSFW())) { this.statuses.addAll(statuses); @@ -499,18 +540,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn statusListAdapter.notifyItemRangeInserted(previousPosition, safeStatuses.size()); } } - if( type == RetrieveFeedsAsyncTask.Type.HOME ) { - //Update the id of the last toot retrieved - if( MainActivity.lastHomeId == null || Long.parseLong(statuses.get(0).getId()) > Long.parseLong(MainActivity.lastHomeId)) - MainActivity.lastHomeId = statuses.get(0).getId(); - if( firstLoad ) - updateStatusLastId(statuses.get(0).getId()); - } - if( type == RetrieveFeedsAsyncTask.Type.HOME) - //Display new value in counter - try { - ((MainActivity) context).updateHomeCounter(); - }catch (Exception ignored){} + } swipeRefreshLayout.setRefreshing(false); firstLoad = false; @@ -541,12 +571,14 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn statuses.add(0, status); if (!status.getAccount().getId().equals(userId)) MainActivity.countNewStatus++; + try { + ((MainActivity) context).updateHomeCounter(); + }catch (Exception ignored){} statusListAdapter.notifyItemInserted(0); if (textviewNoAction.getVisibility() == View.VISIBLE) textviewNoAction.setVisibility(View.GONE); } - } else if (type == RetrieveFeedsAsyncTask.Type.PUBLIC || type == RetrieveFeedsAsyncTask.Type.LOCAL|| type == RetrieveFeedsAsyncTask.Type.DIRECT) { status.setNew(false); @@ -664,8 +696,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 (type == RetrieveFeedsAsyncTask.Type.HOME ) { - if(visible && statuses != null && statuses.size() > 0) - updateStatusLastId(statuses.get(0).getId()); if (visible) { SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putBoolean(Helper.SHOULD_CONTINUE_STREAMING_HOME + userId + instance, true); @@ -755,10 +785,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn public void scrollToTop(){ if( lv_status != null) { lv_status.setAdapter(statusListAdapter); - //Store last toot id for home timeline to avoid to notify for those that have been already seen - if (type == RetrieveFeedsAsyncTask.Type.HOME && statuses != null && statuses.size() > 0) { - updateStatusLastId(statuses.get(0).getId()); - } } } @@ -832,20 +858,4 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn fetchMoreButtonDisplayed = false; asyncTask = new RetrieveFeedsAsyncTask(context, type, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - - - /** - * Records the id of the status only if its greater than the previous one. - * @param statusId String current status id to check - */ - private void updateStatusLastId(String statusId){ - - String lastNotif = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId + instance, null); - if( lastNotif == null || Long.parseLong(statusId) > Long.parseLong(lastNotif)){ - MainActivity.countNewStatus = 0; - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId + instance, statusId); - editor.apply(); - } - } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index 650863a98..e7eaaaf47 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -222,6 +222,7 @@ public class Helper { 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 BOOKMARK_ID = "bookmark_id"; + public static final String LAST_READ_TOOT_ID = "last_read_toot_id"; public static final String LAST_HOMETIMELINE_NOTIFICATION_MAX_ID = "last_hometimeline_notification_max_id"; public static final String SHOULD_CONTINUE_STREAMING = "should_continue_streaming"; public static final String SHOULD_CONTINUE_STREAMING_HOME = "should_continue_streaming_home"; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java index 1cfc5a48b..f70d8fe25 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java @@ -30,8 +30,6 @@ public class ApplicationJob implements JobCreator { switch (tag) { case NotificationsSyncJob.NOTIFICATION_REFRESH: return new NotificationsSyncJob(); - case HomeTimelineSyncJob.HOME_TIMELINE: - return new HomeTimelineSyncJob(); case ScheduledTootsSyncJob.SCHEDULED_TOOT: return new ScheduledTootsSyncJob(); case ScheduledBoostsSyncJob.SCHEDULED_BOOST: diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java deleted file mode 100644 index 275e099fd..000000000 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java +++ /dev/null @@ -1,221 +0,0 @@ -package fr.gouv.etalab.mastodon.jobs; -/* Copyright 2017 Thomas Schneider - * - * This file is a part of Mastalab - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with Mastalab; if not, - * see . */ - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.DataSource; -import com.bumptech.glide.load.engine.GlideException; -import com.bumptech.glide.request.RequestListener; -import com.bumptech.glide.request.target.SimpleTarget; -import com.bumptech.glide.request.target.Target; -import com.bumptech.glide.request.transition.Transition; -import com.evernote.android.job.Job; -import com.evernote.android.job.JobManager; -import com.evernote.android.job.JobRequest; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import fr.gouv.etalab.mastodon.R; -import fr.gouv.etalab.mastodon.activities.MainActivity; -import fr.gouv.etalab.mastodon.client.API; -import fr.gouv.etalab.mastodon.client.APIResponse; -import fr.gouv.etalab.mastodon.client.Entities.Account; -import fr.gouv.etalab.mastodon.client.Entities.Status; -import fr.gouv.etalab.mastodon.helper.Helper; -import fr.gouv.etalab.mastodon.sqlite.AccountDAO; -import fr.gouv.etalab.mastodon.sqlite.Sqlite; - - -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_INSTANCE; -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 { - - static final String HOME_TIMELINE = "home_timeline"; - static { - Helper.installProvider(); - } - - @NonNull - @Override - protected Result onRunJob(@NonNull Params params) { - callAsynchronousTask(); - return Result.SUCCESS; - } - public static int schedule(boolean updateCurrent){ - - Set jobRequests = JobManager.instance().getAllJobRequestsForTag(HOME_TIMELINE); - if (!jobRequests.isEmpty() && !updateCurrent) { - return jobRequests.iterator().next().getJobId(); - } - - return new JobRequest.Builder(HomeTimelineSyncJob.HOME_TIMELINE) - .setPeriodic(TimeUnit.MINUTES.toMillis(Helper.MINUTES_BETWEEN_HOME_TIMELINE), TimeUnit.MINUTES.toMillis(5)) - .setUpdateCurrent(updateCurrent) - .setRequiredNetworkType(JobRequest.NetworkType.METERED) - .setRequiresBatteryNotLow(true) - .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, false); - //User disagree with home timeline refresh - if( !notif_hometimeline) - return; //Nothing is done - //No account connected, the service is stopped - if(!Helper.isLoggedIn(getContext())) - return; - SQLiteDatabase db = Sqlite.getInstance(getContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - //If an Internet connection and user agrees with notification refresh - //If WIFI only and on WIFI OR user defined any connections to use the service. - if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getContext())) { - List accounts = new AccountDAO(getContext(),db).getAllAccount(); - //It means there is no user in DB. - if( accounts == null ) - return; - //Retrieve users in db that owner has. - for (Account account: accounts) { - String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null); - String lastHomeSeen = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + account.getId() + account.getInstance(), null); - if( lastHomeSeen != null && max_id != null){ - if( Long.parseLong(lastHomeSeen) > Long.parseLong(max_id)){ - max_id = lastHomeSeen; - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), max_id); - editor.apply(); - } - } - API api = new API(getContext(), account.getInstance(), account.getToken()); - APIResponse apiResponse = api.getHomeTimelineSinceId(max_id); - onRetrieveHomeTimelineService(apiResponse, account); - } - } - } - - private void onRetrieveHomeTimelineService(APIResponse apiResponse, final Account account) { - final List statuses = apiResponse.getStatuses(); - if( apiResponse.getError() != null || statuses == null || statuses.size() == 0 || account == null) - return; - - final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - - final String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null); - //No previous notifications in cache, so no notification will be sent - String message; - - 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( max_id != null && (status.getId().equals(max_id)) || (account.getAcct() != null && status.getAccount().getAcct().trim().equals(account.getAcct().trim()) )) - continue; - final 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, account.getId()); - intent.putExtra(PREF_INSTANCE, account.getInstance()); - long notif_id = Long.parseLong(account.getId()); - final int notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2); - if( notificationUrl != null){ - - 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; - - Handler mainHandler = new Handler(Looper.getMainLooper()); - - Runnable myRunnable = new Runnable() { - @Override - public void run() {Glide.with(getContext()) - .asBitmap() - .load(notificationUrl) - .listener(new RequestListener(){ - - @Override - public boolean onResourceReady(Bitmap resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { - return false; - } - - @Override - public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { - notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(), - R.drawable.mastodonlogo), Helper.NotifType.TOOT, finalTitle, finalMessage); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), statuses.get(0).getId()); - editor.apply(); - return false; - } - }) - .into(new SimpleTarget() { - @Override - public void onResourceReady(@NonNull Bitmap resource, Transition transition) { - notify_user(getContext(), intent, notificationId, resource, Helper.NotifType.TOOT, finalTitle, finalMessage); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), statuses.get(0).getId()); - editor.apply(); - } - }); - } - }; - mainHandler.post(myRunnable); - - } - } - - } - -} \ No newline at end of file