diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ed7dec05f..90a80a352 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -158,6 +158,11 @@ android:configChanges="orientation|screenSize" android:label="@string/app_name" /> + . */ +package fr.gouv.etalab.mastodon.activities; + + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.DividerItemDecoration; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; + +import java.util.ArrayList; +import java.util.List; +import fr.gouv.etalab.mastodon.R; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; +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.StatusListAdapter; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface; +import fr.gouv.etalab.mastodon.services.BackupStatusInDataBaseService; +import fr.gouv.etalab.mastodon.services.BackupStatusService; +import fr.gouv.etalab.mastodon.sqlite.AccountDAO; +import fr.gouv.etalab.mastodon.sqlite.Sqlite; + + +/** + * Created by Thomas on 17/02/2018. + * Show owner's toots + */ + +public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeedsInterface { + + + private TextView toolbarTitle; + private RecyclerView lv_status; + private boolean isRefreshed; + private ImageView pp_actionBar; + private StatusListAdapter statusListAdapter; + private SharedPreferences sharedpreferences; + private String max_id; + private List statuses; + private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; + private boolean firstLoad; + private SwipeRefreshLayout swipeRefreshLayout; + private boolean swiped; + private boolean flag_loading; + LinearLayoutManager mLayoutManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); + int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); + if( theme == Helper.THEME_LIGHT){ + setTheme(R.style.AppTheme_NoActionBar); + }else { + setTheme(R.style.AppThemeDark_NoActionBar); + } + setContentView(R.layout.activity_ower_status); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + ActionBar actionBar = getSupportActionBar(); + if( actionBar != null ){ + LayoutInflater inflater = (LayoutInflater) this.getSystemService(android.content.Context.LAYOUT_INFLATER_SERVICE); + assert inflater != null; + @SuppressLint("InflateParams") View view = inflater.inflate(R.layout.toot_action_bar, null); + actionBar.setCustomView(view, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); + + ImageView close_toot = actionBar.getCustomView().findViewById(R.id.close_toot); + close_toot.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + toolbarTitle = actionBar.getCustomView().findViewById(R.id.toolbar_title); + pp_actionBar = actionBar.getCustomView().findViewById(R.id.pp_actionBar); + toolbarTitle.setText(getString(R.string.owner_cached_toots)); + } + statuses = new ArrayList<>(); + lv_status = findViewById(R.id.lv_status); + mainLoader = findViewById(R.id.loader); + nextElementLoader = findViewById(R.id.loading_next_status); + textviewNoAction = findViewById(R.id.no_action); + mainLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.GONE); + max_id = null; + flag_loading = true; + firstLoad = true; + swiped = false; + boolean isOnWifi = Helper.isOnWIFI(OwnerStatusActivity.this); + int positionSpinnerTrans = sharedpreferences.getInt(Helper.SET_TRANSLATOR, Helper.TRANS_YANDEX); + int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); + lv_status.addItemDecoration(new DividerItemDecoration(OwnerStatusActivity.this, DividerItemDecoration.VERTICAL)); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + statusListAdapter = new StatusListAdapter(OwnerStatusActivity.this, RetrieveFeedsAsyncTask.Type.CACHE_STATUS, userId, isOnWifi, behaviorWithAttachments, positionSpinnerTrans, this.statuses); + lv_status.setAdapter(statusListAdapter); + mLayoutManager = new LinearLayoutManager(OwnerStatusActivity.this); + lv_status.setLayoutManager(mLayoutManager); + + SQLiteDatabase db = Sqlite.getInstance(OwnerStatusActivity.this, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + Account account = new AccountDAO(OwnerStatusActivity.this,db).getAccountByID(userId); + String url = account.getAvatar(); + if( url.startsWith("/") ){ + url = Helper.getLiveInstanceWithProtocol(OwnerStatusActivity.this) + account.getAvatar(); + } + Glide.with(OwnerStatusActivity.this) + .asBitmap() + .load(url) + .into(new SimpleTarget() { + @Override + public void onResourceReady(@NonNull Bitmap resource, Transition transition) { + BitmapDrawable ppDrawable = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(25, OwnerStatusActivity.this), (int) Helper.convertDpToPixel(25, OwnerStatusActivity.this), true)); + if( pp_actionBar != null){ + pp_actionBar.setImageDrawable(ppDrawable); + } else if( getSupportActionBar() != null){ + + getSupportActionBar().setIcon(ppDrawable); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + } + }); + + isRefreshed = false; + + swipeRefreshLayout = findViewById(R.id.swipeContainer); + new RetrieveFeedsAsyncTask(OwnerStatusActivity.this, RetrieveFeedsAsyncTask.Type.CACHE_STATUS, null, OwnerStatusActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4, + R.color.mastodonC2, + R.color.mastodonC3); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + isRefreshed = true; + new RetrieveFeedsAsyncTask(OwnerStatusActivity.this, RetrieveFeedsAsyncTask.Type.CACHE_STATUS, null, OwnerStatusActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + + lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if(dy > 0){ + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + if(firstVisibleItem + visibleItemCount == totalItemCount ) { + if(!flag_loading ) { + flag_loading = true; + new RetrieveFeedsAsyncTask(OwnerStatusActivity.this, RetrieveFeedsAsyncTask.Type.CACHE_STATUS, max_id, OwnerStatusActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } + }); + + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.option_owner_cache, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + case R.id.action_sync: + Intent backupIntent = new Intent(OwnerStatusActivity.this, BackupStatusInDataBaseService.class); + startService(backupIntent); + return true; + case R.id.action_filter: + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onRetrieveFeeds(APIResponse apiResponse) { + mainLoader.setVisibility(View.GONE); + nextElementLoader.setVisibility(View.GONE); + //Discards 404 - error which can often happen due to toots which have been deleted + if( apiResponse.getError() != null && apiResponse.getError().getStatusCode() != 404 ){ + boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true); + if( show_error_messages ) + Toast.makeText(OwnerStatusActivity.this, apiResponse.getError().getError(),Toast.LENGTH_LONG).show(); + swipeRefreshLayout.setRefreshing(false); + swiped = false; + flag_loading = false; + return; + } + int previousPosition = this.statuses.size(); + List statuses = apiResponse.getStatuses(); + max_id = apiResponse.getMax_id(); + flag_loading = (max_id == null ); + if( !swiped && firstLoad && (statuses == null || statuses.size() == 0)) + textviewNoAction.setVisibility(View.VISIBLE); + else + textviewNoAction.setVisibility(View.GONE); + + if( swiped ){ + if (previousPosition > 0) { + for (int i = 0; i < previousPosition; i++) { + this.statuses.remove(0); + } + statusListAdapter.notifyItemRangeRemoved(0, previousPosition); + } + swiped = false; + } + if( statuses != null && statuses.size() > 0) { + this.statuses.addAll(statuses); + statusListAdapter.notifyItemRangeInserted(previousPosition, statuses.size()); + } + swipeRefreshLayout.setRefreshing(false); + firstLoad = false; + + } + + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java index 0674d2bab..12e1cbe93 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveFeedsAsyncTask.java @@ -58,7 +58,8 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { ONESTATUS, CONTEXT, TAG, - CACHE_BOOKMARKS + CACHE_BOOKMARKS, + CACHE_STATUS } public RetrieveFeedsAsyncTask(Context context, Type action, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){ @@ -123,6 +124,20 @@ public class RetrieveFeedsAsyncTask extends AsyncTask { List statuses = new StatusCacheDAO(contextReference.get(), db).getAllStatus(StatusCacheDAO.BOOKMARK_CACHE); apiResponse.setStatuses(statuses); break; + case CACHE_STATUS: + apiResponse = new APIResponse(); + db = Sqlite.getInstance(contextReference.get(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + statuses = new StatusCacheDAO(contextReference.get(), db).getStatusFromID(StatusCacheDAO.ARCHIVE_CACHE, max_id); + if( statuses != null && statuses.size() > 0) { + apiResponse.setStatuses(statuses); + apiResponse.setMax_id(statuses.get(0).getId()); + apiResponse.setSince_id(statuses.get(statuses.size() - 1).getId()); + }else{ + apiResponse.setStatuses(null); + apiResponse.setMax_id(null); + apiResponse.setSince_id(null); + } + break; case HASHTAG: break; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/sqlite/StatusCacheDAO.java b/app/src/main/java/fr/gouv/etalab/mastodon/sqlite/StatusCacheDAO.java index 165931734..fb9956433 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/sqlite/StatusCacheDAO.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/sqlite/StatusCacheDAO.java @@ -160,6 +160,25 @@ public class StatusCacheDAO { } } + /** + * Returns all cached Statuses in db depending of their cache type + * @return stored status List + */ + public List getStatusFromID(int cacheType, String max_id){ + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + String instance = Helper.getLiveInstance(context); + try { + Cursor c; + if( max_id != null) + c = db.query(Sqlite.TABLE_STATUSES_CACHE, null, Sqlite.COL_CACHED_ACTION + " = '" + cacheType+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "' AND " + Sqlite.COL_USER_ID + " = '" + userId+ "' AND " + Sqlite.COL_STATUS_ID + " < '" + max_id+ "'", null, null, null, Sqlite.COL_CREATED_AT + " DESC", "80"); + else + c = db.query(Sqlite.TABLE_STATUSES_CACHE, null, Sqlite.COL_CACHED_ACTION + " = '" + cacheType+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "' AND " + Sqlite.COL_USER_ID + " = '" + userId+ "'", null, null, null, Sqlite.COL_CREATED_AT + " DESC", "80"); + return cursorToListStatuses(c); + } catch (Exception e) { + return null; + } + } /** * Returns the last date of backup for a user depending of the type of cache diff --git a/app/src/main/res/drawable-hdpi/ic_archive.png b/app/src/main/res/drawable-hdpi/ic_archive.png new file mode 100644 index 000000000..b82509f63 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_archive.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_date_range.png b/app/src/main/res/drawable-hdpi/ic_date_range.png new file mode 100644 index 000000000..d5a7dca1f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_date_range.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_filter_list.png b/app/src/main/res/drawable-hdpi/ic_filter_list.png new file mode 100644 index 000000000..c7c783d47 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_filter_list.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_sync.png b/app/src/main/res/drawable-hdpi/ic_sync.png new file mode 100644 index 000000000..cd24e1fcb Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_sync.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_archive.png b/app/src/main/res/drawable-ldpi/ic_archive.png new file mode 100644 index 000000000..3efa6168b Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_archive.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_date_range.png b/app/src/main/res/drawable-ldpi/ic_date_range.png new file mode 100644 index 000000000..47a10edd7 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_date_range.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_filter_list.png b/app/src/main/res/drawable-ldpi/ic_filter_list.png new file mode 100644 index 000000000..eb0bf288d Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_filter_list.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_sync.png b/app/src/main/res/drawable-ldpi/ic_sync.png new file mode 100644 index 000000000..3737e6656 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_sync.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_archive.png b/app/src/main/res/drawable-mdpi/ic_archive.png new file mode 100644 index 000000000..13e88f27d Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_archive.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_date_range.png b/app/src/main/res/drawable-mdpi/ic_date_range.png new file mode 100644 index 000000000..0937c5562 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_date_range.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_filter_list.png b/app/src/main/res/drawable-mdpi/ic_filter_list.png new file mode 100644 index 000000000..6086611d6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_filter_list.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_sync.png b/app/src/main/res/drawable-mdpi/ic_sync.png new file mode 100644 index 000000000..a7add46d8 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_sync.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_archive.png b/app/src/main/res/drawable-xhdpi/ic_archive.png new file mode 100644 index 000000000..4edab214e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_archive.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_date_range.png b/app/src/main/res/drawable-xhdpi/ic_date_range.png new file mode 100644 index 000000000..4e67bf00b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_date_range.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_filter_list.png b/app/src/main/res/drawable-xhdpi/ic_filter_list.png new file mode 100644 index 000000000..7ec8fd62f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_filter_list.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_sync.png b/app/src/main/res/drawable-xhdpi/ic_sync.png new file mode 100644 index 000000000..e47503e90 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_sync.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_archive.png b/app/src/main/res/drawable-xxhdpi/ic_archive.png new file mode 100644 index 000000000..64b56b9ae Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_archive.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_date_range.png b/app/src/main/res/drawable-xxhdpi/ic_date_range.png new file mode 100644 index 000000000..a864955b9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_date_range.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_filter_list.png b/app/src/main/res/drawable-xxhdpi/ic_filter_list.png new file mode 100644 index 000000000..02b0e8679 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_filter_list.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_sync.png b/app/src/main/res/drawable-xxhdpi/ic_sync.png new file mode 100644 index 000000000..cd065c9b2 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_sync.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_archive.png b/app/src/main/res/drawable-xxxhdpi/ic_archive.png new file mode 100644 index 000000000..441de85d9 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_archive.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_date_range.png b/app/src/main/res/drawable-xxxhdpi/ic_date_range.png new file mode 100644 index 000000000..5f23f16e7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_date_range.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_filter_list.png b/app/src/main/res/drawable-xxxhdpi/ic_filter_list.png new file mode 100644 index 000000000..ff17f5d68 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_filter_list.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_sync.png b/app/src/main/res/drawable-xxxhdpi/ic_sync.png new file mode 100644 index 000000000..82baf0755 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_sync.png differ diff --git a/app/src/main/res/layout/activity_ower_status.xml b/app/src/main/res/layout/activity_ower_status.xml new file mode 100644 index 000000000..c8cb5b187 --- /dev/null +++ b/app/src/main/res/layout/activity_ower_status.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/owner_status_action_bar.xml b/app/src/main/res/layout/owner_status_action_bar.xml new file mode 100644 index 000000000..30c6fd789 --- /dev/null +++ b/app/src/main/res/layout/owner_status_action_bar.xml @@ -0,0 +1,61 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index 42d4494a2..d2f8f6112 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -23,6 +23,10 @@ android:id="@+id/nav_drafts" android:icon="@drawable/ic_save_white" android:title="@string/drafts" /> + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ce0b64c9..e42a22177 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -396,6 +396,12 @@ Mb Cache was cleared! %1$s were released + + + Synchronize + Filter + Your toots + No toots were found in database. Please, use the synchronize button from the menu to retrieve them. Recorded data